From fa7266e92cb994c2fb9974797d66e125ebc2d5fb Mon Sep 17 00:00:00 2001 From: zhaoyuan Date: Fri, 10 Sep 2021 13:53:37 +0000 Subject: [PATCH] test static check Signed-off-by: zhaoyuan --- interfaces/innerkits/BUILD.gn | 1 + interfaces/innerkits/appexecfwk_base/BUILD.gn | 9 +- .../appexecfwk_base/include/ability_info.h | 10 +- .../include/appexecfwk_errors.h | 66 +- .../include/application_info.h | 2 +- .../include/bundle_constants.h | 5 + .../appexecfwk_base/include/form_constants.h | 168 ++ .../include/form_death_callback.h | 31 + .../appexecfwk_base/include/form_js_info.h | 49 + .../include/form_provider_data.h | 163 ++ .../include/form_provider_info.h | 114 + .../appexecfwk_base/include/install_param.h | 2 + .../include/launcher_ability_info.h | 40 + .../include/launcher_shortcut_info.h | 34 + .../include/module_usage_record.h | 58 + .../appexecfwk_base/src/ability_info.cpp | 49 +- .../appexecfwk_base/src/application_info.cpp | 10 +- .../src/compatible_ability_info.cpp | 79 + .../src/compatible_application_info.cpp | 8 +- .../appexecfwk_base/src/form_js_info.cpp | 82 + .../src/form_provider_data.cpp | 321 +++ .../src/form_provider_info.cpp | 63 + .../appexecfwk_base/src/install_param.cpp | 2 + .../src/module_usage_record.cpp | 101 + interfaces/innerkits/appexecfwk_core/BUILD.gn | 22 + .../appexecfwk_core/appexecfwk_headers.gni | 4 + .../include/appmgr/app_process_data.h | 1 + .../include/bundlemgr/bundle_mgr_host.h | 22 +- .../include/bundlemgr/bundle_mgr_interface.h | 29 +- .../include/bundlemgr/bundle_mgr_proxy.h | 24 + .../include/bundlemgr/bundle_monitor.h | 62 + .../bundle_status_callback_interface.h | 18 + .../bundlemgr/bundle_status_callback_proxy.h | 18 + .../include/bundlemgr/launcher_service.h | 115 + .../include/formmgr/form_host_interface.h | 70 + .../include/formmgr/form_host_proxy.h | 64 + .../include/formmgr/form_host_stub.h | 75 + .../include/formmgr/form_mgr_interface.h | 178 ++ .../include/formmgr/form_mgr_proxy.h | 156 ++ .../include/formmgr/form_mgr_stub.h | 147 ++ .../include/formmgr/form_provider_interface.h | 135 ++ .../include/formmgr/form_provider_proxy.h | 118 + .../include/formmgr/form_provider_stub.h | 105 + .../include/formmgr/form_supply_interface.h | 67 + .../include/formmgr/form_supply_proxy.h | 61 + .../include/formmgr/form_supply_stub.h | 67 + .../include/formmgr/provider_connect_proxy.h | 61 + .../include/formmgr/provider_connect_stub.h | 51 + .../src/appmgr/app_process_data.cpp | 4 +- .../src/bundlemgr/bundle_mgr_host.cpp | 78 +- .../src/bundlemgr/bundle_mgr_proxy.cpp | 77 +- .../src/bundlemgr/bundle_monitor.cpp | 69 + .../src/bundlemgr/launcher_service.cpp | 280 +++ .../src/formmgr/form_host_proxy.cpp | 126 + .../src/formmgr/form_host_stub.cpp | 120 + .../src/formmgr/form_mgr_proxy.cpp | 562 +++++ .../src/formmgr/form_mgr_stub.cpp | 385 +++ .../src/formmgr/form_provider_proxy.cpp | 346 +++ .../src/formmgr/form_provider_stub.cpp | 268 +++ .../src/formmgr/form_supply_proxy.cpp | 113 + .../src/formmgr/form_supply_stub.cpp | 124 + .../src/formmgr/provider_connect_proxy.cpp | 107 + .../src/formmgr/provider_connect_stub.cpp | 74 + interfaces/innerkits/fmskit/BUILD.gn | 63 + .../native/include/form_callback_interface.h | 46 + .../fmskit/native/include/form_host_client.h | 185 ++ .../fmskit/native/include/form_mgr.h | 254 ++ .../fmskit/native/src/form_host_client.cpp | 266 ++ .../innerkits/fmskit/native/src/form_mgr.cpp | 488 ++++ .../include/dispatcher/blocking_queue.h | 4 +- .../dispatcher/global_task_dispatcher.h | 2 - .../dispatcher/parallel_task_dispatcher.h | 4 - .../parallel_task_dispatcher_base.h | 6 +- .../dispatcher/serial_task_dispatcher.h | 4 +- .../include/dispatcher/spec_task_dispatcher.h | 13 +- .../dispatcher/task_dispatcher_context.h | 2 - .../include/task/barrier_handler.h | 2 +- .../task_dispatcher/include/task/sync_task.h | 16 - .../task_dispatcher/include/task/task.h | 38 +- .../task/task_handler_libevent_adapter.h | 12 +- .../task_dispatcher/include/task/task_stage.h | 11 +- .../include/threading/concurrent_queue.h | 7 +- .../include/threading/delay_queue.h | 3 +- .../include/threading/thread_factory.h | 2 - .../include/threading/work_thread.h | 2 - .../include/threading/worker_pool.h | 8 +- .../src/dispatcher/base_task_dispatcher.cpp | 56 +- .../src/dispatcher/group_impl.cpp | 35 +- .../dispatcher/parallel_task_dispatcher.cpp | 6 +- .../parallel_task_dispatcher_base.cpp | 18 +- .../src/dispatcher/serial_task_dispatcher.cpp | 32 +- .../src/dispatcher/spec_task_dispatcher.cpp | 37 +- .../dispatcher/task_dispatcher_context.cpp | 30 +- .../src/task/barrier_handler.cpp | 36 +- .../task_dispatcher/src/task/sync_task.cpp | 8 +- .../task_dispatcher/src/task/task.cpp | 38 +- .../src/threading/default_thread_factory.cpp | 4 +- .../src/threading/task_executor.cpp | 42 +- .../src/threading/work_thread.cpp | 6 +- .../src/threading/worker_pool.cpp | 66 +- .../base_task_dispatcher_test.cpp | 23 +- .../parallel_task_dispatcher_base_test.cpp | 8 +- .../parallel_task_dispatcher_test.cpp | 4 +- .../serial_task_dispatcher_test.cpp | 82 +- .../spec_dispatcher_config_test/BUILD.gn | 2 +- ...t .cpp => spec_dispatcher_config_test.cpp} | 8 +- .../spec_task_dispatcher_test.cpp | 56 +- .../task_dispatcher_context_test.cpp | 24 +- .../innerkits/test/mock/include/test.cpp | 0 .../global_task_dispatcher_module_test.cpp | 1 - .../parallel_task_dispatcher_module_test.cpp | 4 - .../serial_task_dispatcher_module_test.cpp | 8 +- kits/BUILD.gn | 2 - kits/appkit/napi/bundlemgr/BUILD.gn | 2 + kits/appkit/napi/bundlemgr/bundle_mgr.cpp | 1199 ++++++++- kits/appkit/napi/bundlemgr/bundle_mgr.h | 45 + kits/appkit/napi/bundlemgr/native_module.cpp | 4 + .../napi/bundlemgr/permission_callback.cpp | 75 + .../napi/bundlemgr/permission_callback.h | 45 + .../app/include/ability_start_setting.h | 109 - kits/appkit/native/app/include/context.h | 3 +- .../native/app/src/ability_start_setting.cpp | 181 -- .../native/app/src/application_context.cpp | 15 +- kits/appkit/native/app/src/context_deal.cpp | 115 +- kits/appkit/native/app/src/main_thread.cpp | 184 +- kits/appkit/native/test/BUILD.gn | 6 +- .../mock_ability_manager_client_interface1.h | 17 + .../mock_resourceManager_interface1.cpp | 15 +- .../unittest/ability_start_setting_test.cpp | 2 +- .../event_handler_fd_listener_module_test.cpp | 16 +- .../event_handler_press_module_test.cpp | 2 +- ohos.build | 210 +- sa_profile/403.xml | 27 + sa_profile/BUILD.gn | 1 + sa_profile/foundation.cfg | 36 +- sa_profile/foundation.rc | 3 +- services/BUILD.gn | 1 + services/appmgr/BUILD.gn | 6 +- .../appmgr/include/ability_running_record.h | 2 +- .../appmgr/include/app_mgr_service_inner.h | 16 +- services/appmgr/include/app_running_manager.h | 2 + services/appmgr/include/app_running_record.h | 5 +- services/appmgr/include/cgroup_manager.h | 12 +- services/appmgr/include/process_optimizer.h | 3 +- services/appmgr/lmks.cfg | 17 + services/appmgr/src/app_mgr_service_inner.cpp | 5 +- services/appmgr/src/app_running_manager.cpp | 19 +- services/appmgr/src/app_running_record.cpp | 41 +- services/appmgr/src/cgroup_manager.cpp | 27 +- services/appmgr/src/lmks/lmks_server.cpp | 73 +- services/appmgr/src/lmks/lmks_utils.cpp | 12 +- services/appmgr/src/process_optimizer.cpp | 2 +- .../test/mock/include/mock_bundle_manager.h | 30 +- .../test/mock/src/mock_bundle_manager.cpp | 2 + .../ams_ability_running_record_test.cpp | 20 +- .../ams_workflow_test.cpp | 1 + .../ams_process_optimizer_test.cpp | 14 + .../ams_recent_app_list_test.cpp | 10 +- services/bundlemgr/BUILD.gn | 5 + .../bundlemgr/include/base_bundle_installer.h | 16 +- services/bundlemgr/include/bundle_data_mgr.h | 87 +- .../bundlemgr/include/bundle_mgr_host_impl.h | 24 + .../bundlemgr/include/bundle_mgr_service.h | 2 + .../bundle_permissions_changed_monitor.h | 65 + services/bundlemgr/include/common_profile.h | 5 + .../bundlemgr/include/inner_bundle_info.h | 80 +- .../include/module_usage_data_storage.h | 83 + .../permission_changed_death_recipient.h | 34 + .../bundlemgr/src/base_bundle_installer.cpp | 54 +- services/bundlemgr/src/bundle_data_mgr.cpp | 397 ++- .../src/bundle_data_storage_database.cpp | 1 + .../bundlemgr/src/bundle_mgr_host_impl.cpp | 69 +- services/bundlemgr/src/bundle_mgr_service.cpp | 14 +- .../bundlemgr/src/bundle_permission_mgr.cpp | 4 +- services/bundlemgr/src/bundle_profile.cpp | 92 +- services/bundlemgr/src/inner_bundle_info.cpp | 93 +- .../src/module_usage_data_storage.cpp | 383 +++ .../permission_changed_death_recipient.cpp | 34 + .../test/mock/include/mock_ability_mgr_host.h | 42 + .../test/mock/include/mock_bundle_status.h | 3 + .../bms_bundle_data_storage_database_test.cpp | 71 +- .../bms_bundle_data_storage_test.cpp | 52 +- .../bms_bundle_installer_test/BUILD.gn | 6 +- .../bms_bundle_installer_test.cpp | 110 +- .../bms_bundle_kit_service_test/BUILD.gn | 7 +- .../bms_bundle_kit_service_test.cpp | 350 ++- .../bms_bundle_parser_test.cpp | 17 +- .../bms_bundle_permission_test/BUILD.gn | 6 +- .../bms_bundle_permission_test.cpp | 138 +- .../bms_bundle_uninstaller_test/BUILD.gn | 6 +- .../bms_bundle_uninstaller_test.cpp | 106 +- .../unittest/bms_bundle_updater_test/BUILD.gn | 6 +- .../bms_bundle_updater_test.cpp | 78 +- .../test/unittest/bms_data_mgr_test/BUILD.gn | 23 +- .../bms_data_mgr_test/bms_data_mgr_test.cpp | 68 +- .../unittest/bms_install_daemon_test/BUILD.gn | 3 +- .../bms_install_daemon_test.cpp | 78 +- .../bms_service_bundle_scan_test/BUILD.gn | 6 +- .../bms_service_bundle_scan_test.cpp | 24 +- .../bms_service_startup_test/BUILD.gn | 6 +- .../bms_service_startup_test.cpp | 10 +- services/formmgr/BUILD.gn | 111 + .../formmgr/include/form_ability_connection.h | 86 + .../formmgr/include/form_acquire_connection.h | 56 + services/formmgr/include/form_ams_helper.h | 71 + .../include/form_batch_delete_connection.h | 55 + services/formmgr/include/form_bms_helper.h | 81 + services/formmgr/include/form_cache_mgr.h | 78 + .../include/form_cast_temp_connection.h | 49 + services/formmgr/include/form_data_mgr.h | 412 ++++ services/formmgr/include/form_db_cache.h | 121 + services/formmgr/include/form_db_info.h | 328 +++ .../formmgr/include/form_delete_connection.h | 51 + services/formmgr/include/form_dump_mgr.h | 64 + .../include/form_event_notify_connection.h | 53 + services/formmgr/include/form_host_callback.h | 65 + services/formmgr/include/form_host_record.h | 202 ++ services/formmgr/include/form_id_key.h | 68 + services/formmgr/include/form_item_info.h | 255 ++ services/formmgr/include/form_mgr_adapter.h | 383 +++ services/formmgr/include/form_mgr_service.h | 213 ++ .../include/form_msg_event_connection.h | 53 + services/formmgr/include/form_provider_mgr.h | 115 + services/formmgr/include/form_record.h | 57 + .../formmgr/include/form_refresh_connection.h | 53 + .../formmgr/include/form_refresh_limiter.h | 91 + services/formmgr/include/form_storage_mgr.h | 75 + .../formmgr/include/form_supply_callback.h | 69 + .../formmgr/include/form_sys_event_receiver.h | 70 + services/formmgr/include/form_task_mgr.h | 264 ++ services/formmgr/include/form_timer.h | 186 ++ services/formmgr/include/form_timer_mgr.h | 317 +++ services/formmgr/include/form_util.h | 101 + .../formmgr/src/form_ability_connection.cpp | 102 + .../formmgr/src/form_acquire_connection.cpp | 65 + services/formmgr/src/form_ams_helper.cpp | 96 + .../src/form_batch_delete_connection.cpp | 55 + services/formmgr/src/form_bms_helper.cpp | 111 + services/formmgr/src/form_cache_mgr.cpp | 130 + .../formmgr/src/form_cast_temp_connection.cpp | 54 + services/formmgr/src/form_data_mgr.cpp | 1126 +++++++++ services/formmgr/src/form_db_cache.cpp | 297 +++ services/formmgr/src/form_db_info.cpp | 135 ++ .../formmgr/src/form_delete_connection.cpp | 56 + services/formmgr/src/form_dump_mgr.cpp | 165 ++ .../src/form_event_notify_connection.cpp | 60 + services/formmgr/src/form_host_callback.cpp | 88 + services/formmgr/src/form_host_record.cpp | 270 +++ services/formmgr/src/form_item_info.cpp | 370 +++ services/formmgr/src/form_mgr_adapter.cpp | 1399 +++++++++++ services/formmgr/src/form_mgr_service.cpp | 388 +++ .../formmgr/src/form_msg_event_connection.cpp | 64 + services/formmgr/src/form_provider_mgr.cpp | 369 +++ .../formmgr/src/form_refresh_connection.cpp | 70 + services/formmgr/src/form_refresh_limiter.cpp | 194 ++ services/formmgr/src/form_storage_mgr.cpp | 313 +++ services/formmgr/src/form_supply_callback.cpp | 118 + .../formmgr/src/form_sys_event_receiver.cpp | 490 ++++ services/formmgr/src/form_task_mgr.cpp | 566 +++++ services/formmgr/src/form_timer_mgr.cpp | 1017 ++++++++ services/formmgr/src/form_util.cpp | 202 ++ services/formmgr/test/BUILD.gn | 65 + .../test/mock/include/mock_ability_manager.h | 552 +++++ .../test/mock/include/mock_bundle_manager.h | 538 +++++ .../mock/include/mock_form_death_callback.h | 59 + .../test/mock/include/mock_form_host_client.h | 92 + .../mock/include/mock_form_provider_client.h | 114 + .../test/mock/include/mock_form_token.h | 60 + .../mock/include/mock_form_user_manager.h | 91 + .../test/mock/src/mock_bundle_manager.cpp | 156 ++ .../test/mock/src/mock_form_host_client.cpp | 76 + .../mock/src/mock_form_provider_client.cpp | 142 ++ .../unittest/fms_form_cache_mgr_test/BUILD.gn | 75 + .../fms_form_cache_mgr_test.cpp | 227 ++ .../unittest/fms_form_data_mgr_test/BUILD.gn | 81 + .../fms_form_data_mgr_test.cpp | 2136 +++++++++++++++++ .../unittest/fms_form_db_record_test/BUILD.gn | 76 + .../fms_form_db_record_test.cpp | 195 ++ .../fms_form_host_record_test/BUILD.gn | 82 + .../fms_form_host_record_test.cpp | 157 ++ .../fms_form_mgr_add_form_test/BUILD.gn | 86 + .../fms_form_mgr_add_form_test.cpp | 547 +++++ .../fms_form_mgr_cast_temp_form_test/BUILD.gn | 82 + .../fms_form_mgr_cast_temp_form_test.cpp | 241 ++ .../fms_form_mgr_death_callback_test/BUILD.gn | 17 + .../fms_form_mgr_death_callback_test.cpp | 209 ++ .../fms_form_mgr_delete_form_test/BUILD.gn | 86 + .../fms_form_mgr_delete_form_test.cpp | 465 ++++ .../BUILD.gn | 88 + .../fms_form_mgr_lifecycle_update_test.cpp | 294 +++ .../fms_form_mgr_message_event_test/BUILD.gn | 86 + .../fms_form_mgr_message_event_test.cpp | 356 +++ .../BUILD.gn | 88 + ...s_form_mgr_notify_invisible_forms_test.cpp | 311 +++ .../BUILD.gn | 88 + ...fms_form_mgr_notify_visible_forms_test.cpp | 401 ++++ .../fms_form_mgr_release_form_test/BUILD.gn | 82 + .../fms_form_mgr_release_form_test.cpp | 274 +++ .../fms_form_mgr_request_form_test/BUILD.gn | 81 + .../fms_form_mgr_request_form_test.cpp | 245 ++ .../fms_form_mgr_update_form_test/BUILD.gn | 86 + .../fms_form_mgr_update_form_test.cpp | 400 +++ .../fms_form_provider_data_test/BUILD.gn | 65 + .../fms_form_provider_data_test.cpp | 169 ++ .../fms_form_provider_mgr_test/BUILD.gn | 82 + .../fms_form_provider_mgr_test.cpp | 246 ++ .../fms_form_set_next_refresh_test/BUILD.gn | 87 + .../fms_form_set_next_refresh_test.cpp | 230 ++ .../fms_form_sys_event_receiver_test/BUILD.gn | 88 + .../fms_form_sys_event_receiver_test.cpp | 473 ++++ .../unittest/fms_form_timer_mgr_test/BUILD.gn | 64 + .../fms_form_timer_mgr_test.cpp | 600 +++++ .../test/mock/include/mock_ability_mgr_host.h | 42 + .../ams_app_life_cycle_module_test.cpp | 20 +- .../ams_app_mgr_service_module_test.cpp | 46 +- .../ams_app_running_record_module_test.cpp | 34 +- .../ams_service_start_process_module_test.cpp | 4 +- .../common/bms/bundle_installer_test/BUILD.gn | 5 + .../bms_bundle_installer_module_test.cpp | 237 +- .../common/bms/bundle_uninstall_test/BUILD.gn | 5 + .../bms_bundle_uninstaller_module_test.cpp | 38 +- .../bms/service_start_process_test/BUILD.gn | 9 +- .../amsAbilityVisibleTestPageA.hap | Bin 0 -> 125783 bytes .../amsAbilityVisibleTestServiceB.hap | Bin 0 -> 131123 bytes .../amsSystemTestDFX.hap | Bin 104270 -> 111934 bytes .../amsSystemTestQ.hap | Bin 109634 -> 119893 bytes .../amsSystemTestR.hap | Bin 109708 -> 119919 bytes test/resource/ams/ohos_test.xml | 6 + .../amssystemtestability/abilitySrc/BUILD.gn | 9 +- .../abilitySrc/amsAbilityAppendTestA/BUILD.gn | 2 + .../abilitySrc/amsAbilityAppendTestB/BUILD.gn | 2 + .../amsAbilityVisibleTestPageA/BUILD.gn | 65 + .../amsAbilityVisibleTestPageA/config.json | 66 + .../include/amsabilityvisibletestpagea1.h | 85 + .../include/amsabilityvisibletestpagea2.h | 103 + .../include/amsabilityvisibletestpagea3.h | 82 + .../include/amsabilityvisibletestpagea4.h | 82 + .../src/amsabilityvisibletestpagea1.cpp | 150 ++ .../src/amsabilityvisibletestpagea2.cpp | 177 ++ .../src/amsabilityvisibletestpagea3.cpp | 140 ++ .../src/amsabilityvisibletestpagea4.cpp | 141 ++ .../amsAbilityVisibleTestServiceB/BUILD.gn | 66 + .../amsAbilityVisibleTestServiceB/config.json | 77 + .../include/amsabilityvisibletestdata.h | 50 + .../include/amsabilityvisibletestpageb1.h | 85 + .../include/amsabilityvisibletestpageb2.h | 103 + .../include/amsabilityvisibletestservice.h | 88 + .../include/amsabilityvisibletestservicea1.h | 88 + .../src/amsabilityvisibletestdata.cpp | 97 + .../src/amsabilityvisibletestpageb1.cpp | 150 ++ .../src/amsabilityvisibletestpageb2.cpp | 181 ++ .../src/amsabilityvisibletestservice.cpp | 171 ++ .../src/amsabilityvisibletestservicea1.cpp | 171 ++ .../amsConfigurationUpdatedTest/BUILD.gn | 72 + .../amsConfigurationUpdatedTest/config.json | 92 + .../include/fifth_ability.h | 90 + .../include/fourth_ability.h | 90 + .../include/main_ability.h | 89 + .../include/second_ability.h | 90 + .../include/sixth_ability.h | 90 + .../include/test_utils.h | 41 + .../include/third_ability.h | 90 + .../src/fifth_ability.cpp | 173 ++ .../src/fourth_ability.cpp | 173 ++ .../src/main_ability.cpp | 175 ++ .../src/second_ability.cpp | 173 ++ .../src/sixth_ability.cpp | 172 ++ .../src/test_utils.cpp | 55 + .../src/third_ability.cpp | 173 ++ .../abilitySrc/amsDataSystemTestA/BUILD.gn | 2 + .../abilitySrc/amsDataSystemTestB/BUILD.gn | 2 + .../abilitySrc/amsDataSystemTestC/BUILD.gn | 2 + .../src/ams_st_data_ability_data_c1.cpp | 21 +- .../abilitySrc/amsKitSystemTest/BUILD.gn | 2 + .../amsKitSystemTest/src/fifth_ability.cpp | 10 + .../amsKitSystemTest/src/fourth_ability.cpp | 10 + .../amsKitSystemTest/src/second_ability.cpp | 11 + .../abilitySrc/amsKitSystemTestA/BUILD.gn | 2 + .../abilitySrc/amsKitSystemTestB/BUILD.gn | 2 + .../abilitySrc/amsKitSystemTestDataA/BUILD.gn | 2 + .../abilitySrc/amsKitSystemTestDataB/BUILD.gn | 2 + .../abilitySrc/amsKitSystemTestPageA/BUILD.gn | 2 + .../amsKitSystemTestService/BUILD.gn | 2 + .../abilitySrc/amsMissionStackTest/BUILD.gn | 68 + .../amsMissionStackTest/config.json | 60 + .../include/main_ability.h | 140 ++ .../include/second_ability.h | 139 ++ .../amsMissionStackTest/include/test_utils.h | 41 + .../include/third_ability.h | 119 + .../amsMissionStackTest/src/main_ability.cpp | 331 +++ .../src/second_ability.cpp | 289 +++ .../amsMissionStackTest/src/test_utils.cpp | 55 + .../amsMissionStackTest/src/third_ability.cpp | 236 ++ .../amsMissionStackTestSubsidiary/BUILD.gn | 69 + .../amsMissionStackTestSubsidiary/config.json | 60 + .../include/main_ability.h | 90 + .../include/second_ability.h | 91 + .../include/test_utils.h | 41 + .../include/third_ability.h | 89 + .../src/main_ability.cpp | 186 ++ .../src/second_ability.cpp | 187 ++ .../src/test_utils.cpp | 55 + .../src/third_ability.cpp | 173 ++ .../abilitySrc/amsSystemTestA/BUILD.gn | 2 + .../amsSystemTestA/src/amsstabilitya1.cpp | 4 - .../amsSystemTestA/src/amsstabilitya2.cpp | 4 - .../abilitySrc/amsSystemTestB/BUILD.gn | 2 + .../amsSystemTestB/src/amsstabilityb1.cpp | 4 - .../abilitySrc/amsSystemTestC/BUILD.gn | 2 + .../amsSystemTestC/src/amsstabilityc1.cpp | 4 - .../amsSystemTestC/src/amsstabilityc2.cpp | 4 - .../amsSystemTestC/src/amsstabilityc3.cpp | 4 - .../abilitySrc/amsSystemTestD/BUILD.gn | 2 + .../amsSystemTestD/src/amsstabilityd1.cpp | 4 - .../amsSystemTestD/src/amsstabilityd2.cpp | 4 - .../abilitySrc/amsSystemTestDFX/BUILD.gn | 2 + .../abilitySrc/amsSystemTestDFX/config.json | 8 +- .../include/ams_dfx_st_service_ability_a1.h | 4 +- .../include/ams_dfx_st_service_ability_a2.h | 4 +- .../src/ams_dfx_st_service_ability_a1.cpp | 40 +- .../src/ams_dfx_st_service_ability_a2.cpp | 40 +- .../abilitySrc/amsSystemTestE/BUILD.gn | 2 + .../amsSystemTestE/src/amsstabilitye1.cpp | 4 - .../abilitySrc/amsSystemTestErrorK/BUILD.gn | 2 + .../abilitySrc/amsSystemTestErrorL/BUILD.gn | 2 + .../abilitySrc/amsSystemTestF/BUILD.gn | 2 + .../amsSystemTestF/src/amsstabilityf1.cpp | 4 - .../amsSystemTestF/src/amsstabilityf2.cpp | 4 - .../amsSystemTestF/src/amsstabilityf3.cpp | 4 - .../abilitySrc/amsSystemTestG/BUILD.gn | 2 + .../amsSystemTestG/src/amsstabilityg1.cpp | 4 - .../amsSystemTestG/src/amsstabilityg2.cpp | 4 - .../abilitySrc/amsSystemTestH/BUILD.gn | 2 + .../amsSystemTestH/src/amsstabilityh1.cpp | 4 - .../abilitySrc/amsSystemTestI/BUILD.gn | 2 + .../amsSystemTestI/src/amsstabilityi1.cpp | 4 - .../amsSystemTestI/src/amsstabilityi2.cpp | 4 - .../amsSystemTestI/src/amsstabilityi3.cpp | 4 - .../amsSystemTestI/src/amsstabilityi4.cpp | 4 - .../abilitySrc/amsSystemTestM/BUILD.gn | 2 + .../amsSystemTestM/src/amsstabilitym1.cpp | 4 +- .../abilitySrc/amsSystemTestN/BUILD.gn | 2 + .../amsSystemTestN/src/amsstabilityn1.cpp | 4 +- .../amsSystemTestN/src/amsstabilityn2.cpp | 4 +- .../amsSystemTestN/src/amsstabilityn4.cpp | 4 - .../abilitySrc/amsSystemTestO/BUILD.gn | 2 + .../abilitySrc/amsSystemTestP/BUILD.gn | 2 + .../abilitySrc/amsSystemTestQ/BUILD.gn | 2 + .../amsSystemTestQ/src/amsstabilityq4.cpp | 4 - .../abilitySrc/amsSystemTestR/BUILD.gn | 2 + .../amsSystemTestR/src/amsstabilityr4.cpp | 4 - .../abilitySrc/amsSystemTestServiceA/BUILD.gn | 1 + .../abilitySrc/amsSystemTestServiceB/BUILD.gn | 2 + .../abilitySrc/amsSystemTestServiceC/BUILD.gn | 2 + .../abilitySrc/amsSystemTestServiceD/BUILD.gn | 2 + .../abilitySrc/amsSystemTestServiceE/BUILD.gn | 2 + .../abilitySrc/amsSystemTestServiceF/BUILD.gn | 2 + .../abilitySrc/amsSystemTestServiceG/BUILD.gn | 2 + .../abilitySrc/amsSystemTestServiceH/BUILD.gn | 2 + .../common/ability_append_test_info.h | 51 + .../abilitySrc/serviceAbilityA/BUILD.gn | 55 + .../abilitySrc/serviceAbilityA/config.json | 50 + .../include/service_ability_a.h | 68 + .../test_ability_connect_callback_proxy.h | 48 + .../test_ability_connect_callback_stub.h | 61 + .../include/test_ability_connection.h | 41 + .../include/verify_act_first_ability.h | 86 + .../serviceAbilityA/src/service_ability_a.cpp | 57 + .../test_ability_connect_callback_stub.cpp | 185 ++ .../src/test_ability_connection.cpp | 35 + .../src/verify_act_first_ability.cpp | 178 ++ .../abilitySrc/taskDispatcherTestA/BUILD.gn | 3 +- .../abilitySrc/taskDispatcherTestB/BUILD.gn | 3 +- .../tools/include/stpageabilityevent.h | 36 +- .../tools/src/stpageabilityevent.cpp | 54 +- .../bmssystemtestability/abilitySrc/BUILD.gn | 21 + .../abilitySrc/thirdPageDemo1/BUILD.gn | 60 + .../abilitySrc/thirdPageDemo1/config.json | 52 + .../thirdPageDemo1/include/pageAbilityDemo.h | 42 + .../thirdPageDemo1/src/pageAbilityDemo.cpp | 93 + .../abilitySrc/thirdPageDemo2/BUILD.gn | 60 + .../abilitySrc/thirdPageDemo2/config.json | 61 + .../thirdPageDemo2/include/pageAbilityDemo.h | 41 + .../thirdPageDemo2/src/pageAbilityDemo.cpp | 78 + .../abilitySrc/thirdPageDemo3/BUILD.gn | 60 + .../abilitySrc/thirdPageDemo3/config.json | 52 + .../thirdPageDemo3/include/pageAbilityDemo.h | 42 + .../thirdPageDemo3/src/pageAbilityDemo.cpp | 109 + .../abilitySrc/thirdPageDemo4/BUILD.gn | 60 + .../abilitySrc/thirdPageDemo4/config.json | 52 + .../thirdPageDemo4/include/pageAbilityDemo.h | 42 + .../thirdPageDemo4/src/pageAbilityDemo.cpp | 107 + .../jsSystemBundle/bmsSystemBundle1.hap | Bin 0 -> 44782 bytes .../jsThirdBundle/bmsThirdBundle1.hap | Bin 0 -> 44717 bytes .../jsThirdBundle/bmsThirdBundle2.hap | Bin 0 -> 44349 bytes .../jsThirdBundle/bmsThirdBundle3.hap | Bin 0 -> 44747 bytes .../jsThirdBundle/bmsThirdBundle4.hap | Bin 0 -> 44413 bytes .../jsThirdBundle/bmsThirdBundle5.hap | Bin 0 -> 44719 bytes .../jsThirdBundle/bmsThirdBundle6.hap | Bin 0 -> 44433 bytes .../stThirdBundle/bmsThirdBundle24.hap | Bin 93253 -> 100554 bytes .../stThirdBundle/bmsThirdBundle25.hap | Bin 93284 -> 100094 bytes .../stThirdBundle/bmsThirdBundle44.hap | Bin 0 -> 100942 bytes .../stThirdBundle/bmsThirdBundle45.hap | Bin 0 -> 100862 bytes test/resource/formsystemtestability/BUILD.gn | 16 + .../formSystemTestServiceA/BUILD.gn | 58 + .../formSystemTestServiceA/config.json | 87 + .../include/form_st_service_ability_a1.h | 130 + .../src/form_st_service_ability_a1.cpp | 306 +++ ...pageAbilityBundleForInstallNoSignature.hap | Bin 0 -> 17670 bytes test/systemtest/common/ams/BUILD.gn | 4 + .../common/ams/ams_aa_command_test/BUILD.gn | 2 + .../ams/ams_ability_append_test/BUILD.gn | 2 + .../ams/ams_ability_visible_test/BUILD.gn | 67 + .../ams_ability_visible_test.cpp | 1266 ++++++++++ .../ams/ams_app_process_manage_test/BUILD.gn | 2 + .../ams_configuration_updated_test/BUILD.gn | 67 + .../ams_configuration_updated_test.cpp | 613 +++++ .../common/ams/ams_data_ability_test/BUILD.gn | 2 + .../common/ams/ams_dfx_test/BUILD.gn | 2 + .../common/ams/ams_dfx_test/ams_dfx_test.cpp | 69 +- .../common/ams/ams_kit_test/BUILD.gn | 16 + .../common/ams/ams_missionstack_test/BUILD.gn | 69 + .../ams_missionstack_test.cpp | 850 +++++++ .../common/ams/ams_page_ability_test/BUILD.gn | 2 + .../ams_page_ability_test.cpp | 109 +- .../common/ams/ams_power_test/BUILD.gn | 2 + .../ams/ams_power_test/ams_power_test.cpp | 9 +- .../ams/ams_service_ability_test/BUILD.gn | 2 + .../ams_service_ability_test.cpp | 2 +- test/systemtest/common/ams/tool/BUILD.gn | 2 + test/systemtest/common/bms/BUILD.gn | 3 +- .../acts_bms_kit_system_test.cpp | 780 +++--- .../bms/bms_install_system_test/BUILD.gn | 2 +- .../bms_install_system_test.cpp | 296 +-- .../bms_launcher_service_system_test/BUILD.gn | 65 + .../bms_launcher_service_system_test.cpp | 1301 ++++++++++ .../bms_search_system_test.cpp | 181 +- .../bms_uninstall_system_test.cpp | 124 +- .../common/task_dispatcher/BUILD.gn | 4 +- tools/bm/include/bundle_command.h | 4 +- tools/bm/src/bundle_command.cpp | 26 +- tools/test/mock/mock_bundle_mgr_host.h | 4 + tools/test/moduletest/bm/BUILD.gn | 8 +- tools/test/systemtest/bm/BUILD.gn | 18 +- .../bm/bundle_command_install_system_test.cpp | 42 + tools/test/unittest/bm/BUILD.gn | 8 + .../bm/bundle_command_install_test.cpp | 52 + 547 files changed, 51085 insertions(+), 2833 deletions(-) create mode 100644 interfaces/innerkits/appexecfwk_base/include/form_constants.h create mode 100644 interfaces/innerkits/appexecfwk_base/include/form_death_callback.h create mode 100644 interfaces/innerkits/appexecfwk_base/include/form_js_info.h create mode 100644 interfaces/innerkits/appexecfwk_base/include/form_provider_data.h create mode 100644 interfaces/innerkits/appexecfwk_base/include/form_provider_info.h create mode 100644 interfaces/innerkits/appexecfwk_base/include/launcher_ability_info.h create mode 100644 interfaces/innerkits/appexecfwk_base/include/launcher_shortcut_info.h create mode 100644 interfaces/innerkits/appexecfwk_base/include/module_usage_record.h create mode 100644 interfaces/innerkits/appexecfwk_base/src/form_js_info.cpp create mode 100644 interfaces/innerkits/appexecfwk_base/src/form_provider_data.cpp create mode 100644 interfaces/innerkits/appexecfwk_base/src/form_provider_info.cpp create mode 100644 interfaces/innerkits/appexecfwk_base/src/module_usage_record.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_monitor.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/bundlemgr/launcher_service.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/formmgr/form_host_interface.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/formmgr/form_host_proxy.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/formmgr/form_host_stub.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/formmgr/form_mgr_interface.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/formmgr/form_mgr_proxy.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/formmgr/form_mgr_stub.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/formmgr/form_provider_interface.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/formmgr/form_provider_proxy.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/formmgr/form_provider_stub.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/formmgr/form_supply_interface.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/formmgr/form_supply_proxy.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/formmgr/form_supply_stub.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/formmgr/provider_connect_proxy.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/formmgr/provider_connect_stub.h create mode 100644 interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_monitor.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/bundlemgr/launcher_service.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/formmgr/form_host_proxy.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/formmgr/form_host_stub.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/formmgr/form_mgr_proxy.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/formmgr/form_mgr_stub.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/formmgr/form_provider_proxy.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/formmgr/form_provider_stub.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/formmgr/form_supply_proxy.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/formmgr/form_supply_stub.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/formmgr/provider_connect_proxy.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/formmgr/provider_connect_stub.cpp create mode 100644 interfaces/innerkits/fmskit/BUILD.gn create mode 100644 interfaces/innerkits/fmskit/native/include/form_callback_interface.h create mode 100755 interfaces/innerkits/fmskit/native/include/form_host_client.h create mode 100644 interfaces/innerkits/fmskit/native/include/form_mgr.h create mode 100755 interfaces/innerkits/fmskit/native/src/form_host_client.cpp create mode 100644 interfaces/innerkits/fmskit/native/src/form_mgr.cpp rename interfaces/innerkits/task_dispatcher/test/unittest/spec_dispatcher_config_test/{spec_dispatcher_config_test .cpp => spec_dispatcher_config_test.cpp} (93%) delete mode 100644 interfaces/innerkits/test/mock/include/test.cpp create mode 100644 kits/appkit/napi/bundlemgr/permission_callback.cpp create mode 100644 kits/appkit/napi/bundlemgr/permission_callback.h delete mode 100644 kits/appkit/native/app/include/ability_start_setting.h delete mode 100644 kits/appkit/native/app/src/ability_start_setting.cpp create mode 100644 sa_profile/403.xml create mode 100755 services/appmgr/lmks.cfg mode change 100644 => 100755 services/bundlemgr/BUILD.gn create mode 100644 services/bundlemgr/include/bundle_permissions_changed_monitor.h create mode 100644 services/bundlemgr/include/module_usage_data_storage.h create mode 100644 services/bundlemgr/include/permission_changed_death_recipient.h create mode 100644 services/bundlemgr/src/module_usage_data_storage.cpp create mode 100644 services/bundlemgr/src/permission_changed_death_recipient.cpp mode change 100644 => 100755 services/bundlemgr/test/unittest/bms_bundle_installer_test/BUILD.gn mode change 100644 => 100755 services/bundlemgr/test/unittest/bms_bundle_kit_service_test/BUILD.gn mode change 100644 => 100755 services/bundlemgr/test/unittest/bms_bundle_permission_test/BUILD.gn mode change 100644 => 100755 services/bundlemgr/test/unittest/bms_bundle_uninstaller_test/BUILD.gn mode change 100644 => 100755 services/bundlemgr/test/unittest/bms_bundle_updater_test/BUILD.gn mode change 100644 => 100755 services/bundlemgr/test/unittest/bms_data_mgr_test/BUILD.gn mode change 100644 => 100755 services/bundlemgr/test/unittest/bms_install_daemon_test/BUILD.gn mode change 100644 => 100755 services/bundlemgr/test/unittest/bms_service_bundle_scan_test/BUILD.gn mode change 100644 => 100755 services/bundlemgr/test/unittest/bms_service_startup_test/BUILD.gn create mode 100644 services/formmgr/BUILD.gn create mode 100644 services/formmgr/include/form_ability_connection.h create mode 100644 services/formmgr/include/form_acquire_connection.h create mode 100644 services/formmgr/include/form_ams_helper.h create mode 100644 services/formmgr/include/form_batch_delete_connection.h create mode 100644 services/formmgr/include/form_bms_helper.h create mode 100644 services/formmgr/include/form_cache_mgr.h create mode 100644 services/formmgr/include/form_cast_temp_connection.h create mode 100644 services/formmgr/include/form_data_mgr.h create mode 100644 services/formmgr/include/form_db_cache.h create mode 100644 services/formmgr/include/form_db_info.h create mode 100644 services/formmgr/include/form_delete_connection.h create mode 100644 services/formmgr/include/form_dump_mgr.h create mode 100644 services/formmgr/include/form_event_notify_connection.h create mode 100644 services/formmgr/include/form_host_callback.h create mode 100644 services/formmgr/include/form_host_record.h create mode 100644 services/formmgr/include/form_id_key.h create mode 100644 services/formmgr/include/form_item_info.h create mode 100644 services/formmgr/include/form_mgr_adapter.h create mode 100644 services/formmgr/include/form_mgr_service.h create mode 100644 services/formmgr/include/form_msg_event_connection.h create mode 100644 services/formmgr/include/form_provider_mgr.h create mode 100644 services/formmgr/include/form_record.h create mode 100644 services/formmgr/include/form_refresh_connection.h create mode 100644 services/formmgr/include/form_refresh_limiter.h create mode 100644 services/formmgr/include/form_storage_mgr.h create mode 100644 services/formmgr/include/form_supply_callback.h create mode 100644 services/formmgr/include/form_sys_event_receiver.h create mode 100644 services/formmgr/include/form_task_mgr.h create mode 100644 services/formmgr/include/form_timer.h create mode 100644 services/formmgr/include/form_timer_mgr.h create mode 100644 services/formmgr/include/form_util.h create mode 100644 services/formmgr/src/form_ability_connection.cpp create mode 100644 services/formmgr/src/form_acquire_connection.cpp create mode 100644 services/formmgr/src/form_ams_helper.cpp create mode 100644 services/formmgr/src/form_batch_delete_connection.cpp create mode 100644 services/formmgr/src/form_bms_helper.cpp create mode 100644 services/formmgr/src/form_cache_mgr.cpp create mode 100644 services/formmgr/src/form_cast_temp_connection.cpp create mode 100644 services/formmgr/src/form_data_mgr.cpp create mode 100644 services/formmgr/src/form_db_cache.cpp create mode 100644 services/formmgr/src/form_db_info.cpp create mode 100755 services/formmgr/src/form_delete_connection.cpp create mode 100644 services/formmgr/src/form_dump_mgr.cpp create mode 100644 services/formmgr/src/form_event_notify_connection.cpp create mode 100644 services/formmgr/src/form_host_callback.cpp create mode 100644 services/formmgr/src/form_host_record.cpp create mode 100644 services/formmgr/src/form_item_info.cpp create mode 100644 services/formmgr/src/form_mgr_adapter.cpp create mode 100644 services/formmgr/src/form_mgr_service.cpp create mode 100644 services/formmgr/src/form_msg_event_connection.cpp create mode 100644 services/formmgr/src/form_provider_mgr.cpp create mode 100644 services/formmgr/src/form_refresh_connection.cpp create mode 100644 services/formmgr/src/form_refresh_limiter.cpp create mode 100644 services/formmgr/src/form_storage_mgr.cpp create mode 100644 services/formmgr/src/form_supply_callback.cpp create mode 100644 services/formmgr/src/form_sys_event_receiver.cpp create mode 100644 services/formmgr/src/form_task_mgr.cpp create mode 100644 services/formmgr/src/form_timer_mgr.cpp create mode 100644 services/formmgr/src/form_util.cpp create mode 100644 services/formmgr/test/BUILD.gn create mode 100644 services/formmgr/test/mock/include/mock_ability_manager.h create mode 100644 services/formmgr/test/mock/include/mock_bundle_manager.h create mode 100644 services/formmgr/test/mock/include/mock_form_death_callback.h create mode 100644 services/formmgr/test/mock/include/mock_form_host_client.h create mode 100644 services/formmgr/test/mock/include/mock_form_provider_client.h create mode 100644 services/formmgr/test/mock/include/mock_form_token.h create mode 100644 services/formmgr/test/mock/include/mock_form_user_manager.h create mode 100644 services/formmgr/test/mock/src/mock_bundle_manager.cpp create mode 100644 services/formmgr/test/mock/src/mock_form_host_client.cpp create mode 100644 services/formmgr/test/mock/src/mock_form_provider_client.cpp create mode 100644 services/formmgr/test/unittest/fms_form_cache_mgr_test/BUILD.gn create mode 100644 services/formmgr/test/unittest/fms_form_cache_mgr_test/fms_form_cache_mgr_test.cpp create mode 100644 services/formmgr/test/unittest/fms_form_data_mgr_test/BUILD.gn create mode 100644 services/formmgr/test/unittest/fms_form_data_mgr_test/fms_form_data_mgr_test.cpp create mode 100644 services/formmgr/test/unittest/fms_form_db_record_test/BUILD.gn create mode 100644 services/formmgr/test/unittest/fms_form_db_record_test/fms_form_db_record_test.cpp create mode 100644 services/formmgr/test/unittest/fms_form_host_record_test/BUILD.gn create mode 100644 services/formmgr/test/unittest/fms_form_host_record_test/fms_form_host_record_test.cpp create mode 100644 services/formmgr/test/unittest/fms_form_mgr_add_form_test/BUILD.gn create mode 100644 services/formmgr/test/unittest/fms_form_mgr_add_form_test/fms_form_mgr_add_form_test.cpp create mode 100644 services/formmgr/test/unittest/fms_form_mgr_cast_temp_form_test/BUILD.gn create mode 100644 services/formmgr/test/unittest/fms_form_mgr_cast_temp_form_test/fms_form_mgr_cast_temp_form_test.cpp create mode 100644 services/formmgr/test/unittest/fms_form_mgr_death_callback_test/BUILD.gn create mode 100644 services/formmgr/test/unittest/fms_form_mgr_death_callback_test/fms_form_mgr_death_callback_test.cpp create mode 100644 services/formmgr/test/unittest/fms_form_mgr_delete_form_test/BUILD.gn create mode 100644 services/formmgr/test/unittest/fms_form_mgr_delete_form_test/fms_form_mgr_delete_form_test.cpp create mode 100644 services/formmgr/test/unittest/fms_form_mgr_lifecycle_update_test/BUILD.gn create mode 100644 services/formmgr/test/unittest/fms_form_mgr_lifecycle_update_test/fms_form_mgr_lifecycle_update_test.cpp create mode 100644 services/formmgr/test/unittest/fms_form_mgr_message_event_test/BUILD.gn create mode 100644 services/formmgr/test/unittest/fms_form_mgr_message_event_test/fms_form_mgr_message_event_test.cpp create mode 100644 services/formmgr/test/unittest/fms_form_mgr_notify_invisible_forms_test/BUILD.gn create mode 100644 services/formmgr/test/unittest/fms_form_mgr_notify_invisible_forms_test/fms_form_mgr_notify_invisible_forms_test.cpp create mode 100644 services/formmgr/test/unittest/fms_form_mgr_notify_visible_forms_test/BUILD.gn create mode 100644 services/formmgr/test/unittest/fms_form_mgr_notify_visible_forms_test/fms_form_mgr_notify_visible_forms_test.cpp create mode 100644 services/formmgr/test/unittest/fms_form_mgr_release_form_test/BUILD.gn create mode 100644 services/formmgr/test/unittest/fms_form_mgr_release_form_test/fms_form_mgr_release_form_test.cpp create mode 100644 services/formmgr/test/unittest/fms_form_mgr_request_form_test/BUILD.gn create mode 100644 services/formmgr/test/unittest/fms_form_mgr_request_form_test/fms_form_mgr_request_form_test.cpp create mode 100644 services/formmgr/test/unittest/fms_form_mgr_update_form_test/BUILD.gn create mode 100644 services/formmgr/test/unittest/fms_form_mgr_update_form_test/fms_form_mgr_update_form_test.cpp create mode 100644 services/formmgr/test/unittest/fms_form_provider_data_test/BUILD.gn create mode 100644 services/formmgr/test/unittest/fms_form_provider_data_test/fms_form_provider_data_test.cpp create mode 100644 services/formmgr/test/unittest/fms_form_provider_mgr_test/BUILD.gn create mode 100644 services/formmgr/test/unittest/fms_form_provider_mgr_test/fms_form_provider_mgr_test.cpp create mode 100644 services/formmgr/test/unittest/fms_form_set_next_refresh_test/BUILD.gn create mode 100644 services/formmgr/test/unittest/fms_form_set_next_refresh_test/fms_form_set_next_refresh_test.cpp create mode 100644 services/formmgr/test/unittest/fms_form_sys_event_receiver_test/BUILD.gn create mode 100644 services/formmgr/test/unittest/fms_form_sys_event_receiver_test/fms_form_sys_event_receiver_test.cpp create mode 100644 services/formmgr/test/unittest/fms_form_timer_mgr_test/BUILD.gn create mode 100644 services/formmgr/test/unittest/fms_form_timer_mgr_test/fms_form_timer_mgr_test.cpp create mode 100644 test/resource/ams/ams_page_ability_bundle/amsAbilityVisibleTestPageA.hap create mode 100644 test/resource/ams/ams_page_ability_bundle/amsAbilityVisibleTestServiceB.hap mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/amsAbilityAppendTestA/BUILD.gn mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/amsAbilityAppendTestB/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsAbilityVisibleTestPageA/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsAbilityVisibleTestPageA/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsAbilityVisibleTestPageA/include/amsabilityvisibletestpagea1.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsAbilityVisibleTestPageA/include/amsabilityvisibletestpagea2.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsAbilityVisibleTestPageA/include/amsabilityvisibletestpagea3.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsAbilityVisibleTestPageA/include/amsabilityvisibletestpagea4.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsAbilityVisibleTestPageA/src/amsabilityvisibletestpagea1.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsAbilityVisibleTestPageA/src/amsabilityvisibletestpagea2.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsAbilityVisibleTestPageA/src/amsabilityvisibletestpagea3.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsAbilityVisibleTestPageA/src/amsabilityvisibletestpagea4.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsAbilityVisibleTestServiceB/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsAbilityVisibleTestServiceB/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsAbilityVisibleTestServiceB/include/amsabilityvisibletestdata.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsAbilityVisibleTestServiceB/include/amsabilityvisibletestpageb1.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsAbilityVisibleTestServiceB/include/amsabilityvisibletestpageb2.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsAbilityVisibleTestServiceB/include/amsabilityvisibletestservice.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsAbilityVisibleTestServiceB/include/amsabilityvisibletestservicea1.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsAbilityVisibleTestServiceB/src/amsabilityvisibletestdata.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsAbilityVisibleTestServiceB/src/amsabilityvisibletestpageb1.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsAbilityVisibleTestServiceB/src/amsabilityvisibletestpageb2.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsAbilityVisibleTestServiceB/src/amsabilityvisibletestservice.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsAbilityVisibleTestServiceB/src/amsabilityvisibletestservicea1.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsConfigurationUpdatedTest/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsConfigurationUpdatedTest/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsConfigurationUpdatedTest/include/fifth_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsConfigurationUpdatedTest/include/fourth_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsConfigurationUpdatedTest/include/main_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsConfigurationUpdatedTest/include/second_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsConfigurationUpdatedTest/include/sixth_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsConfigurationUpdatedTest/include/test_utils.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsConfigurationUpdatedTest/include/third_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsConfigurationUpdatedTest/src/fifth_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsConfigurationUpdatedTest/src/fourth_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsConfigurationUpdatedTest/src/main_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsConfigurationUpdatedTest/src/second_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsConfigurationUpdatedTest/src/sixth_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsConfigurationUpdatedTest/src/test_utils.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsConfigurationUpdatedTest/src/third_ability.cpp mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/amsDataSystemTestA/BUILD.gn mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/amsDataSystemTestB/BUILD.gn mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/amsDataSystemTestC/BUILD.gn mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/amsKitSystemTest/BUILD.gn mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/amsKitSystemTest/src/fourth_ability.cpp mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/amsKitSystemTest/src/second_ability.cpp mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestA/BUILD.gn mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestB/BUILD.gn mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestDataA/BUILD.gn mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestDataB/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsMissionStackTest/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsMissionStackTest/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsMissionStackTest/include/main_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsMissionStackTest/include/second_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsMissionStackTest/include/test_utils.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsMissionStackTest/include/third_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsMissionStackTest/src/main_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsMissionStackTest/src/second_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsMissionStackTest/src/test_utils.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsMissionStackTest/src/third_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsMissionStackTestSubsidiary/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsMissionStackTestSubsidiary/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsMissionStackTestSubsidiary/include/main_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsMissionStackTestSubsidiary/include/second_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsMissionStackTestSubsidiary/include/test_utils.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsMissionStackTestSubsidiary/include/third_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsMissionStackTestSubsidiary/src/main_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsMissionStackTestSubsidiary/src/second_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsMissionStackTestSubsidiary/src/test_utils.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsMissionStackTestSubsidiary/src/third_ability.cpp mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/amsSystemTestA/BUILD.gn mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/amsSystemTestB/BUILD.gn mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/amsSystemTestC/BUILD.gn mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/amsSystemTestD/BUILD.gn mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/amsSystemTestE/BUILD.gn mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/amsSystemTestErrorK/BUILD.gn mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/amsSystemTestErrorL/BUILD.gn mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/amsSystemTestF/BUILD.gn mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/amsSystemTestG/BUILD.gn mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/amsSystemTestH/BUILD.gn mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/amsSystemTestI/BUILD.gn mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/amsSystemTestM/BUILD.gn mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/amsSystemTestN/BUILD.gn mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/amsSystemTestO/BUILD.gn mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/amsSystemTestP/BUILD.gn mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/amsSystemTestQ/BUILD.gn mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/amsSystemTestR/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/serviceAbilityA/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/serviceAbilityA/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/serviceAbilityA/include/service_ability_a.h create mode 100644 test/resource/amssystemtestability/abilitySrc/serviceAbilityA/include/test_ability_connect_callback_proxy.h create mode 100644 test/resource/amssystemtestability/abilitySrc/serviceAbilityA/include/test_ability_connect_callback_stub.h create mode 100644 test/resource/amssystemtestability/abilitySrc/serviceAbilityA/include/test_ability_connection.h create mode 100644 test/resource/amssystemtestability/abilitySrc/serviceAbilityA/include/verify_act_first_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/serviceAbilityA/src/service_ability_a.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/serviceAbilityA/src/test_ability_connect_callback_stub.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/serviceAbilityA/src/test_ability_connection.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/serviceAbilityA/src/verify_act_first_ability.cpp mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/taskDispatcherTestA/BUILD.gn mode change 100644 => 100755 test/resource/amssystemtestability/abilitySrc/taskDispatcherTestB/BUILD.gn create mode 100644 test/resource/bmssystemtestability/abilitySrc/BUILD.gn create mode 100755 test/resource/bmssystemtestability/abilitySrc/thirdPageDemo1/BUILD.gn create mode 100644 test/resource/bmssystemtestability/abilitySrc/thirdPageDemo1/config.json create mode 100644 test/resource/bmssystemtestability/abilitySrc/thirdPageDemo1/include/pageAbilityDemo.h create mode 100644 test/resource/bmssystemtestability/abilitySrc/thirdPageDemo1/src/pageAbilityDemo.cpp create mode 100755 test/resource/bmssystemtestability/abilitySrc/thirdPageDemo2/BUILD.gn create mode 100644 test/resource/bmssystemtestability/abilitySrc/thirdPageDemo2/config.json create mode 100644 test/resource/bmssystemtestability/abilitySrc/thirdPageDemo2/include/pageAbilityDemo.h create mode 100644 test/resource/bmssystemtestability/abilitySrc/thirdPageDemo2/src/pageAbilityDemo.cpp create mode 100755 test/resource/bmssystemtestability/abilitySrc/thirdPageDemo3/BUILD.gn create mode 100644 test/resource/bmssystemtestability/abilitySrc/thirdPageDemo3/config.json create mode 100644 test/resource/bmssystemtestability/abilitySrc/thirdPageDemo3/include/pageAbilityDemo.h create mode 100644 test/resource/bmssystemtestability/abilitySrc/thirdPageDemo3/src/pageAbilityDemo.cpp create mode 100755 test/resource/bmssystemtestability/abilitySrc/thirdPageDemo4/BUILD.gn create mode 100644 test/resource/bmssystemtestability/abilitySrc/thirdPageDemo4/config.json create mode 100644 test/resource/bmssystemtestability/abilitySrc/thirdPageDemo4/include/pageAbilityDemo.h create mode 100644 test/resource/bmssystemtestability/abilitySrc/thirdPageDemo4/src/pageAbilityDemo.cpp create mode 100755 test/resource/bundlemgrsst/jsBundle/jsSystemBundle/bmsSystemBundle1.hap create mode 100755 test/resource/bundlemgrsst/jsBundle/jsThirdBundle/bmsThirdBundle1.hap create mode 100755 test/resource/bundlemgrsst/jsBundle/jsThirdBundle/bmsThirdBundle2.hap create mode 100755 test/resource/bundlemgrsst/jsBundle/jsThirdBundle/bmsThirdBundle3.hap create mode 100755 test/resource/bundlemgrsst/jsBundle/jsThirdBundle/bmsThirdBundle4.hap create mode 100755 test/resource/bundlemgrsst/jsBundle/jsThirdBundle/bmsThirdBundle5.hap create mode 100755 test/resource/bundlemgrsst/jsBundle/jsThirdBundle/bmsThirdBundle6.hap create mode 100644 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle44.hap create mode 100644 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle45.hap create mode 100644 test/resource/formsystemtestability/BUILD.gn create mode 100644 test/resource/formsystemtestability/formSystemTestServiceA/BUILD.gn create mode 100644 test/resource/formsystemtestability/formSystemTestServiceA/config.json create mode 100644 test/resource/formsystemtestability/formSystemTestServiceA/include/form_st_service_ability_a1.h create mode 100644 test/resource/formsystemtestability/formSystemTestServiceA/src/form_st_service_ability_a1.cpp create mode 100644 test/resource/tools/bm/pageAbilityBundleForInstallNoSignature.hap mode change 100644 => 100755 test/systemtest/common/ams/ams_aa_command_test/BUILD.gn mode change 100644 => 100755 test/systemtest/common/ams/ams_ability_append_test/BUILD.gn create mode 100755 test/systemtest/common/ams/ams_ability_visible_test/BUILD.gn create mode 100644 test/systemtest/common/ams/ams_ability_visible_test/ams_ability_visible_test.cpp mode change 100644 => 100755 test/systemtest/common/ams/ams_app_process_manage_test/BUILD.gn create mode 100755 test/systemtest/common/ams/ams_configuration_updated_test/BUILD.gn create mode 100644 test/systemtest/common/ams/ams_configuration_updated_test/ams_configuration_updated_test.cpp mode change 100644 => 100755 test/systemtest/common/ams/ams_data_ability_test/BUILD.gn mode change 100644 => 100755 test/systemtest/common/ams/ams_dfx_test/BUILD.gn mode change 100644 => 100755 test/systemtest/common/ams/ams_kit_test/BUILD.gn create mode 100644 test/systemtest/common/ams/ams_missionstack_test/BUILD.gn create mode 100644 test/systemtest/common/ams/ams_missionstack_test/ams_missionstack_test.cpp mode change 100644 => 100755 test/systemtest/common/ams/ams_page_ability_test/BUILD.gn mode change 100644 => 100755 test/systemtest/common/ams/ams_power_test/BUILD.gn mode change 100644 => 100755 test/systemtest/common/ams/tool/BUILD.gn mode change 100755 => 100644 test/systemtest/common/bms/acts_bms_kit_system_test/acts_bms_kit_system_test.cpp create mode 100644 test/systemtest/common/bms/bms_launcher_service_system_test/BUILD.gn create mode 100644 test/systemtest/common/bms/bms_launcher_service_system_test/bms_launcher_service_system_test.cpp mode change 100644 => 100755 tools/test/systemtest/bm/BUILD.gn diff --git a/interfaces/innerkits/BUILD.gn b/interfaces/innerkits/BUILD.gn index db8b6a930d..3a6fb94c27 100644 --- a/interfaces/innerkits/BUILD.gn +++ b/interfaces/innerkits/BUILD.gn @@ -19,6 +19,7 @@ group("innerkits_target") { "appexecfwk_base:appexecfwk_base", "appexecfwk_core:appexecfwk_core", "eventhandler_native:eventhandler_native", + "fmskit:fmskit_native", "libeventhandler:libeventhandler", "task_dispatcher:appkit_dispatcher_td", ] diff --git a/interfaces/innerkits/appexecfwk_base/BUILD.gn b/interfaces/innerkits/appexecfwk_base/BUILD.gn index 3f302de9ec..5f5cdaf89f 100644 --- a/interfaces/innerkits/appexecfwk_base/BUILD.gn +++ b/interfaces/innerkits/appexecfwk_base/BUILD.gn @@ -16,7 +16,10 @@ import("//build/test.gni") import("//foundation/appexecfwk/standard/appexecfwk.gni") config("appexecfwk_base_sdk_config") { - include_dirs = [ "include" ] + include_dirs = [ + "include", + "//third_party/json/include", + ] } ohos_shared_library("appexecfwk_base") { @@ -30,9 +33,13 @@ ohos_shared_library("appexecfwk_base") { "src/compatible_application_info.cpp", "src/element_name.cpp", "src/form_info.cpp", + "src/form_js_info.cpp", + "src/form_provider_data.cpp", + "src/form_provider_info.cpp", "src/hap_module_info.cpp", "src/install_param.cpp", "src/module_info.cpp", + "src/module_usage_record.cpp", "src/permission_def.cpp", "src/running_process_info.cpp", "src/shortcut_info.cpp", diff --git a/interfaces/innerkits/appexecfwk_base/include/ability_info.h b/interfaces/innerkits/appexecfwk_base/include/ability_info.h index e452b025f8..1b735140a8 100644 --- a/interfaces/innerkits/appexecfwk_base/include/ability_info.h +++ b/interfaces/innerkits/appexecfwk_base/include/ability_info.h @@ -148,12 +148,17 @@ struct AbilityInfo : public Parcelable { std::string label; std::string description; std::string iconPath; + int32_t labelId; + int32_t descriptionId; + int32_t iconId; std::string theme; bool visible = false; std::string kind; // ability category AbilityType type = AbilityType::UNKNOWN; DisplayOrientation orientation = DisplayOrientation::UNSPECIFIED; LaunchMode launchMode = LaunchMode::STANDARD; + std::string srcPath; + std::string srcLanguage="js"; std::vector permissions; std::string process; @@ -165,9 +170,12 @@ struct AbilityInfo : public Parcelable { bool isLauncherAbility = false; bool isNativeAbility = false; bool enabled = false; + bool supportPipMode = false; + bool formEnabled = false; std::string readPermission; std::string writePermission; - uint32_t formEntity = 1; + std::vector configChanges; + uint32_t formEntity; int32_t minFormHeight = 0; int32_t defaultFormHeight = 0; int32_t minFormWidth = 0; diff --git a/interfaces/innerkits/appexecfwk_base/include/appexecfwk_errors.h b/interfaces/innerkits/appexecfwk_base/include/appexecfwk_errors.h index 6a92a32d08..999fd70b24 100644 --- a/interfaces/innerkits/appexecfwk_base/include/appexecfwk_errors.h +++ b/interfaces/innerkits/appexecfwk_base/include/appexecfwk_errors.h @@ -24,6 +24,7 @@ enum { APPEXECFWK_MODULE_COMMON = 0x00, APPEXECFWK_MODULE_APPMGR = 0x01, APPEXECFWK_MODULE_BUNDLEMGR = 0x02, + APPEXECFWK_MODULE_FORMMGR = 0x03, APPEXECFWK_MODULE_APPEXECFWK = 0x08, // Reserved 0x03 ~ 0x0f for new modules, Event related modules start from 0x10 APPEXECFWK_MODULE_EVENTMGR = 0x10 @@ -103,6 +104,69 @@ enum { ERR_APPEXECFWK_UNINSTALL_MISSING_INSTALLED_BUNDLE, ERR_APPEXECFWK_UNINSTALL_MISSING_INSTALLED_MODULE }; + +// Error code for FormMgr +constexpr ErrCode APPEXECFWK_FORMMGR_ERR_OFFSET = ErrCodeOffset(SUBSYS_APPEXECFWK, APPEXECFWK_MODULE_FORMMGR); +enum { + ERR_APPEXECFWK_FORM_COMMON_CODE = APPEXECFWK_FORMMGR_ERR_OFFSET + 1, + ERR_APPEXECFWK_FORM_PERMISSION_DENY, + ERR_APPEXECFWK_FORM_INTENT_PARCEL, + ERR_APPEXECFWK_FORM_GET_INFO_FAILED, + ERR_APPEXECFWK_FORM_GET_SYSMGR_FAILED, + ERR_APPEXECFWK_FORM_GET_BUNDLE_FAILED, + ERR_APPEXECFWK_FORM_GET_FMS_FAILED, + ERR_APPEXECFWK_FORM_ADD_DEATH_RECIPIENT_FAILED, + ERR_APPEXECFWK_FORM_BIND_FORMSUPPLY_FAILED, + ERR_APPEXECFWK_FORM_INVALID_PARAM, + ERR_APPEXECFWK_FORM_CFG_NOT_MATCH_ID, + ERR_APPEXECFWK_FORM_ADD_NOT_EXIST_ID, + ERR_APPEXECFWK_FORM_BIND_PROVIDER_FAILED, + ERR_APPEXECFWK_FORM_EXCEED_MAX_NUMBER, + ERR_APPEXECFWK_FORM_EXCEED_INSTANCES_PER_FORM, + ERR_APPEXECFWK_FORM_OPERATION_NOT_SELF, + ERR_APPEXECFWK_FORM_SUPPLIER_DEL_FAIL, + ERR_APPEXECFWK_FORM_NO_SUCH_MODULE, + ERR_APPEXECFWK_FORM_NO_SUCH_ABILITY, + ERR_APPEXECFWK_FORM_NO_SUCH_DIMENSION, + ERR_APPEXECFWK_FORM_FA_NOT_INSTALLED, + ERR_APPEXECFWK_FORM_INFO_NOT_EXIST, + ERR_APPEXECFWK_FORM_HOST_INFO_NOT_EXIST, + ERR_CODE_COMMON, + ERR_NOT_EXIST_ID, + ERR_MAX_RECORDS_PER_APP, + ERR_PERMISSION_DENY, + ERR_MAX_SYSTEM_FORMS, + ERR_MAX_INSTANCES_PER_FORM, + ERR_OPERATION_FORM_NOT_SELF, + ERR_PROVIDER_DEL_FAIL, + ERR_MAX_FORMS_PER_CLIENT, + ERR_MAX_REFRESH, + ERR_MAX_SYSTEM_TEMP_FORMS, + ERR_FORM_NO_SUCH_MODULE, + ERR_FORM_NO_SUCH_ABILITY, + ERR_FORM_NO_SUCH_DIMENSION, + ERR_FORM_FA_NOT_INSTALLED, + ERR_FORM_INVALID_PARAM, + ERR_DELETE_FORM_TIMER, + ERR_CFG_NOT_MATCH_ID, + ERR_APPEXECFWK_FORM_DBCACHE_FIND_FAIL, + ERR_APPEXECFWK_FORM_JSON_CREATE_DIR_FAIL, + ERR_APPEXECFWK_FORM_JSON_NEW_FILE_FAIL, + ERR_APPEXECFWK_FORM_JSON_NO_DIR, + ERR_APPEXECFWK_FORM_JSON_OPEN_FAIL, + ERR_APPEXECFWK_FORM_JSON_FILE_EMPTY, + ERR_APPEXECFWK_FORM_JSON_FIND_FAIL, + ERR_APPEXECFWK_FORM_JSON_PARSE_FAIL, + ERR_APPEXECFWK_FORM_JSON_DELETE_FAIL, + + // error code in sdk + ERR_GET_FMS_RPC, + ERR_FORM_DUPLICATE_ADDED, + ERR_SEND_FMS_MSG, + ERR_GET_BMS_RPC, + ERR_SEND_BMS_MSG, + ERR_IN_RECOVER, +}; constexpr ErrCode APPEXECFWK_APPEXECFWK_ERR_OFFSET = ErrCodeOffset(SUBSYS_APPEXECFWK, APPEXECFWK_MODULE_APPEXECFWK); enum { ERR_APPEXECFWK_CHECK_FAILED = APPEXECFWK_APPEXECFWK_ERR_OFFSET + 1, @@ -111,4 +175,4 @@ enum { } // namespace OHOS -#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_APPEXECFWK_ERRORS_H \ No newline at end of file +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_APPEXECFWK_ERRORS_H diff --git a/interfaces/innerkits/appexecfwk_base/include/application_info.h b/interfaces/innerkits/appexecfwk_base/include/application_info.h index 11ec2d1ae4..73b53e5f41 100644 --- a/interfaces/innerkits/appexecfwk_base/include/application_info.h +++ b/interfaces/innerkits/appexecfwk_base/include/application_info.h @@ -35,7 +35,7 @@ enum class ApplicationFlag { struct ApplicationInfo; -struct CompatibleApplicationInfo : public Parcelable { +struct CompatibleApplicationInfo : public Parcelable { // items set when installing. std::string name; // application name. std::string icon; // application icon resource index. diff --git a/interfaces/innerkits/appexecfwk_base/include/bundle_constants.h b/interfaces/innerkits/appexecfwk_base/include/bundle_constants.h index b809ba0d01..48e25adcfe 100755 --- a/interfaces/innerkits/appexecfwk_base/include/bundle_constants.h +++ b/interfaces/innerkits/appexecfwk_base/include/bundle_constants.h @@ -112,12 +112,17 @@ constexpr uint8_t MAX_MODULE_LABEL = 63; // distributed database const std::string APP_ID = "bundle_manager_service"; const std::string STORE_ID = "installed_bundle_datas"; +const std::string ABILITY_USAGE_STORE_ID = "ability_usage_datas"; // single max hap size constexpr int32_t MAX_HAP_SIZE = 50 * 1024 * 1024; +const std::string UID = "uid"; const int32_t MAX_LIMIT_SIZE = 4; +const std::string DATA_ABILITY_URI_PREFIX = "dataability://"; +const char DATA_ABILITY_URI_SEPARATOR = '/'; + } // namespace Constants } // namespace AppExecFwk } // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_base/include/form_constants.h b/interfaces/innerkits/appexecfwk_base/include/form_constants.h new file mode 100644 index 0000000000..0819e3111d --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/include/form_constants.h @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_FORM_CONSTANTS_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_FORM_CONSTANTS_H + +#include +#include + +namespace OHOS { +namespace AppExecFwk { +namespace Constants { + const std::string PERMISSION_REQUIRE_FORM = "ohos.permission.REQUIRE_FORM"; + const std::string PARAM_FORM_IDENTITY_KEY = "ohos.extra.param.key.form_identity"; + const std::string PARAM_FORM_CALLING_IDENTITY_KEY = "ohos.extra.param.key.form_calling_identity"; + const std::string PARAM_MODULE_NAME_KEY = "ohos.extra.param.key.module_name"; + const std::string PARAM_FORM_NAME_KEY = "ohos.extra.param.key.form_name"; + const std::string PARAM_FORM_DIMENSION_KEY = "ohos.extra.param.key.form_dimension"; + const std::string PARAM_MESSAGE_KEY = "ohos.extra.param.key.message"; + const std::string PARAM_FORM_TEMPORARY_KEY = "ohos.extra.param.key.form_temporary"; + const int32_t ONE_HOST_MAX_FORM_SIZE = 256; + const std::string RECREATE_FORM_KEY = "ohos.extra.param.key.recreate"; + const std::string PARAM_FORM_CUSTOMIZE_KEY = "ohos.extra.param.key.form_customize"; + const std::string PARAM_FORM_ORIENTATION_KEY = "ohos.extra.param.key.form_orientation"; + const int32_t ORIENTATION_PORTRAIT = 1; + const int32_t ORIENTATION_LANDSCAPE = 2; + const std::string PARAM_FORM_ABILITY_NAME_KEY = "abilityName"; + + const std::string KEY_IS_TIMER = "isTimerRefresh"; + const std::string SYSTEM_PARAM_FORM_UPDATE_TIME = "persist.sys.fms.form.update.time"; + const std::string SYSTEM_PARAM_FORM_REFRESH_MIN_TIME = "persist.sys.fms.form.refresh.min.time"; + const std::string ACTION_UPDATEATTIMER = "form_update_at_timer"; + const std::string KEY_WAKEUP_TIME = "wakeUpTime"; + const std::string KEY_ACTION_TYPE = "form_update_action_type"; + const int TYPE_RESET_LIMIT = 1; + const int TYPE_STATIC_UPDATE = 2; + const int TYPE_DYNAMIC_UPDATE = 3; + const long ABS_REFRESH_MS = 2500; + + // The form events type which means that the form becomes visible. + const int32_t FORM_VISIBLE = 1; + // The form events type which means that the form becomes invisible. + const int32_t FORM_INVISIBLE = 2; + + // The default user id + const int32_t DEFAULT_USER_ID = 0; + + // The max uid of system app. + const int32_t MAX_SYSTEM_APP_UID = 10000; + + const int MAX_HOUR = 23; + const int MAX_MININUTE = 59; + const int MIN_TIME = 0; + const int HOUR_PER_DAY = 24; + const int MIN_PER_HOUR = 60; + const long TIME_1000 = 1000; + const long TIME_1000000 = 1000000; + const long TIME_CONVERSION = 30 * 60 * TIME_1000; + const int MIN_CONFIG_DURATION = 1; // 1 means 30 min + const int MAX_CONFIG_DURATION = 2 * 24 * 7; // one week + const long MIN_PERIOD = MIN_CONFIG_DURATION * TIME_CONVERSION; // 30 min in ms unit + const long MAX_PERIOD = MAX_CONFIG_DURATION * TIME_CONVERSION; // 1 week in ms unit + const long ABS_TIME = 5 * TIME_1000; // 5s abs time + const int WORK_POOL_SIZE = 4; + const std::string TIME_DELIMETER = ":"; + const int UPDATE_AT_CONFIG_COUNT = 2; + + const int LIMIT_COUNT = 50; + const int MIN_NEXT_TIME = 300; // seconds + + // The max retry times of reconnection. + const int32_t MAX_RETRY_TIME = 30; + // The time interval between reconnections(milliseconds). + const int32_t SLEEP_TIME = 1000; + + const int64_t MS_PER_SECOND = 1000; + + // form host bundlename + const std::string PARAM_FORM_HOST_BUNDLENAME_KEY = "form_host_bundlename"; + + // form manager service bundlename + const std::string PARAM_FORM_MANAGER_SERVICE_BUNDLENAME_KEY = "form_manager_service_bundlename"; + + // PROVIDER_FLAG false:ProviderFormInfo is null;true: ProviderFormInfo not null + const std::string PROVIDER_FLAG = "provider_flag"; + const std::string FORM_CONNECT_ID = "form_connect_id"; + const std::string FORM_SUPPLY_INFO = "form_supply_info"; + + // the delimiter between bundleName and abilityName + const std::string NAME_DELIMITER = "::"; + + const size_t MAX_LAYOUT = 8; + const std::map DIMENSION_MAP = { + {1, "1*2"}, + {2, "2*2"}, + {3, "2*4"}, + {4, "4*4"}, + }; + const int MAX_FORMS = 512; + const int MAX_RECORD_PER_APP = 256; + const int MAX_TEMP_FORMS = 256; + const int MAX_FORM_DATA_SIZE = 1024; + + const int NOT_IN_RECOVERY = 0; + const int RECOVER_FAIL = 1; + const int IN_RECOVERING = 2; + + const int FLAG_HAS_OBJECT = 1; + const int FLAG_NO_OBJECT = 0; + + const int DEATH_RECIPIENT_FLAG = 0; + const int MAX_VISIBLE_NOTIFY_LIST = 32; + + const std::string ACQUIRE_TYPE = "form_acquire_form"; + const int ACQUIRE_TYPE_CREATE_FORM = 1; + const int ACQUIRE_TYPE_RECREATE_FORM = 2; + + const int DELETE_FORM = 3; + const int RELEASE_FORM = 8; + const int RELEASE_CACHED_FORM = 9; + + const int64_t INVALID_UDID_HASH = 0L; + + enum class FormMgrMessage { + // ipc id 1-1000 for kit + // ipc id 1001-2000 for DMS + // ipc id 2001-3000 for tools + // ipc id for add form (3001) + FORM_MGR_ADD_FORM = 3001, + + // ipc id for delete form (3002) + FORM_MGR_DELETE_FORM, + + // ipc id for form done release form (3003) + FORM_MGR_RELEASE_FORM, + + // ipc id for connecting update form (3004) + FORM_MGR_UPDATE_FORM, + + // ipc id for form visible notify (3005) + FORM_MGR_NOTIFY_FORM_VISIBLE, + + // ipc id for form invisible notify (3006) + FORM_MGR_NOTIFY_FORM_INVISIBLE, + + // ipc id for refreshing data cache (3007) + FORM_MGR_CAST_TEMP_FORM, + + // ipc id 2001-3000 for tools + // ipc id for dumping state (2001) + FORM_MGR_DUMP_STATE = 2001, + }; +} // namespace Constants +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_FORM_CONSTANTS_H diff --git a/interfaces/innerkits/appexecfwk_base/include/form_death_callback.h b/interfaces/innerkits/appexecfwk_base/include/form_death_callback.h new file mode 100644 index 0000000000..795d7f8f19 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/include/form_death_callback.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_OHOS_FORM_DEATH_CALLBACK_H +#define FOUNDATION_APPEXECFWK_OHOS_FORM_DEATH_CALLBACK_H + +namespace OHOS { +namespace AppExecFwk { +/** + * @brief The form death callback. + */ +class FormDeathCallback { +public: + virtual void OnDeathReceived() = 0; + virtual void OnReconnectFailed() = 0; +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_OHOS_FORM_DEATH_CALLBACK_H diff --git a/interfaces/innerkits/appexecfwk_base/include/form_js_info.h b/interfaces/innerkits/appexecfwk_base/include/form_js_info.h new file mode 100644 index 0000000000..cacddf263d --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/include/form_js_info.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_OHOS_FORM_JS_INFO_H +#define FOUNDATION_APPEXECFWK_OHOS_FORM_JS_INFO_H + + +#include +#include "parcel.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @struct FormJsInfo + * Defines form js info. + */ +struct FormJsInfo : public Parcelable { + int64_t formId; + std::string formName; + std::string bundleName; + std::string abilityName; + bool formTempFlg = false; + std::string jsFormCodePath; + std::string formData; + + std::string htmlPath; + std::string cssPath; + std::string jsPath; + std::string fileReousePath; + + bool ReadFromParcel(Parcel &parcel); + virtual bool Marshalling(Parcel &parcel) const override; + static FormJsInfo *Unmarshalling(Parcel &parcel); +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_OHOS_FORM_JS_INFO_H \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_base/include/form_provider_data.h b/interfaces/innerkits/appexecfwk_base/include/form_provider_data.h new file mode 100644 index 0000000000..51f2a3ef4f --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/include/form_provider_data.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_OHOS_FORM_PROVIDER_DATA_H +#define FOUNDATION_APPEXECFWK_OHOS_FORM_PROVIDER_DATA_H + +#include +#include + +#include "ashmem.h" +#include "message_parcel.h" +#include "nlohmann/json.hpp" +#include "parcel.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @class FormProviderData + * Defines form provider data. + */ +class FormProviderData : public Parcelable { +public: + /** + * @brief Constructor. + */ + FormProviderData(); + + /** + * @brief A constructor used to create a {@code FormProviderData} instance with data of + * the {@code nlohmann::json} type specified. + * @param jsonData Indicates the data to be carried in the new {@code FormProviderData} instance, + * in {@code nlohmann::json} format. + */ + FormProviderData(nlohmann::json &jsonData); + + /** + * @brief A constructor used to create a {@code FormProviderData} instance with data of the {@code String} type + * specified. + * @param jsonDataString Indicates the data to be carried in the new {@code FormProviderData} instance, in JSON + * string format. + */ + FormProviderData(std::string jsonDataString); + + /** + * @brief Destructor. + */ + virtual ~FormProviderData(){}; + + /** + * @brief Updates form data in this {@code FormProviderData} object. + * @param jsonData Indicates the new data to use, in {@code nlohmann::json} format. + */ + void UpdateData(nlohmann::json &jsonData); + + /** + * @brief Obtains the form data stored in this {@code FormProviderData} object. + * @return Returns json string format + */ + std::string GetDataString() const; + + /** + * @brief Adds an image to this {@code FormProviderData} instance. + * @param picName Indicates the name of the image to add. + * @param data Indicates the binary data of the image content. + */ + void AddImageData(std::string picName, char *data); + + /** + * @brief Removes data of an image with the specified {@code picName} from this {@code FormProviderData} instance. + * @param picName Indicates the name of the image to remove. + */ + void RemoveImageData(std::string picName); + + /** + * @brief Obtains the add/remove state stored in this {@code FormProviderData} object. + * @return Returns the add/remove state of shared image data. + */ + int32_t GetImageDataState(); + + /** + * @brief Updates imageDataState in this {@code FormProviderData} object. + * @param imageDataState Indicates the imageDataState to update. + */ + void SetImageDataState(int32_t imageDataState); + + /** + * @brief Obtains the imageDataMap stored in this {@code FormProviderData} object. + * @return Returns the map that contains shared image data. + */ + std::map, int32_t>> GetImageDataMap(); + + /** + * @brief Updates imageDataMap in this {@code FormProviderData} object. + * @param imageDataMap Indicates the imageDataMap to update. + */ + void SetImageDataMap(std::map, int32_t>> imageDataMap); + + /** + * @brief Obtains the form data stored in this {@code FormProviderData} object. + * @return Returns json data + */ + nlohmann::json GetData() const; + /** + * @brief Set the form data stored from string string. + * @param Returns string string. + */ + void SetDataString(std::string &jsonDataString); + /** + * @brief Merge new data to FormProviderData. + * @param addJsonData data to merge to FormProviderData + */ + void MergeData(nlohmann::json &addJsonData); + + /** + * Read this {@code FormProviderData} object from a Parcel. + * @param parcel the parcel + * eturn Returns {@code true} if the marshalling is successful; returns {@code false} otherwise. + */ + bool ReadFromParcel(Parcel &parcel); + /** + * @brief Marshals this {@code FormProviderData} object into a {@link ohos.utils.Parcel} object. + * @param parcel Indicates the {@code Parcel} object for marshalling. + * @return Returns {@code true} if the marshalling is successful; returns {@code false} otherwise. + */ + virtual bool Marshalling(Parcel &parcel) const override; + + /** + * @brief Unmarshals this {@code FormProviderData} object from a {@link ohos.utils.Parcel} object. + * @param parcel Indicates the {@code Parcel} object for unmarshalling. + * @return Returns FormProviderData. + */ + static FormProviderData* Unmarshalling(Parcel &parcel); + + /** + * @brief Clear imageDataMap, rawImageBytesMap, imageDataState and jsonFormProviderData. + */ + void ClearData(); + +private: + bool WriteImageDataToParcel(Parcel &parcel, std::string picName, char *data) const; + +private: + nlohmann::json jsonFormProviderData_; + std::map, int32_t>> imageDataMap_; + std::map rawImageBytesMap_; + int32_t imageDataState_; +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_OHOS_FORM_PROVIDER_DATA_H diff --git a/interfaces/innerkits/appexecfwk_base/include/form_provider_info.h b/interfaces/innerkits/appexecfwk_base/include/form_provider_info.h new file mode 100644 index 0000000000..73bfd4a478 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/include/form_provider_info.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_OHOS_FORM_PROVIDER_INFO_H +#define FOUNDATION_APPEXECFWK_OHOS_FORM_PROVIDER_INFO_H + +#include +#include "form_provider_data.h" +#include "parcel.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @struct FormProviderInfo + * Defines form provider info. + */ +class FormProviderInfo : public Parcelable { +public: + FormProviderInfo() = default; + ~FormProviderInfo() = default; + /** + * @brief Set the id of the form. + * @param formId the id of the form. + */ + inline void SetFormId(const int64_t formId) + { + formId_ = formId; + } + /** + * @brief Get the id of the form. + * @return the id of the form. + */ + inline int64_t GetFormId() const + { + return formId_; + } + /** + * @brief Set the form data. + * @param formProviderData The form data. + */ + inline void SetFormData(const FormProviderData &formProviderData) + { + jsBindingData_ = formProviderData; + } + + /** + * @brief Get the form data. + * @return the form data. + */ + inline FormProviderData GetFormData() const + { + return jsBindingData_; + } + /** + * @brief Get the form data. + * @return the form data. + */ + inline std::string GetFormDataString() const + { + return jsBindingData_.GetDataString(); + } + + /** + * @brief Set the upgrade flg. + * @param upgradeFlg The upgrade flg. + */ + inline void SetUpgradeFlg(const bool upgradeFlg) + { + upgradeFlg_ = upgradeFlg; + } + /** + * @brief Get the upgrade flg. + * @return the upgrade flg. + */ + inline bool GetUpgradeFlg() const + { + return upgradeFlg_; + } + + /** + * @brief Set form date by string. + * @param dataString string json data. + */ + void SetFormDataString(std::string &dataString); + + /** + * @brief Merge new data to FormProviderData. + * @param addJsonData data to merge to FormProviderData + */ + void MergeData(nlohmann::json &addJsonData); + + bool ReadFromParcel(Parcel &parcel); + virtual bool Marshalling(Parcel &parcel) const override; + static FormProviderInfo *Unmarshalling(Parcel &parcel); +private: + int64_t formId_; + FormProviderData jsBindingData_; + bool upgradeFlg_; +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_OHOS_FORM_PROVIDER_INFO_H diff --git a/interfaces/innerkits/appexecfwk_base/include/install_param.h b/interfaces/innerkits/appexecfwk_base/include/install_param.h index fdec9375b9..c389749754 100644 --- a/interfaces/innerkits/appexecfwk_base/include/install_param.h +++ b/interfaces/innerkits/appexecfwk_base/include/install_param.h @@ -28,6 +28,7 @@ enum class InstallFlag { // Allow to replace the existing bundle when the new version isn't lower than the old one. // If the bundle does not exist, just like normal flag. REPLACE_EXISTING = 1, + FREE_INSTALL = 0x10, }; enum class InstallLocation { @@ -42,6 +43,7 @@ struct InstallParam : public Parcelable { int userId = 0; // is keep user data while uninstall. bool isKeepData = false; + bool noCheckSignature = false; // the parcel object function is not const. bool ReadFromParcel(Parcel &parcel); diff --git a/interfaces/innerkits/appexecfwk_base/include/launcher_ability_info.h b/interfaces/innerkits/appexecfwk_base/include/launcher_ability_info.h new file mode 100644 index 0000000000..33fa0eee27 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/include/launcher_ability_info.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_LAUNCHER_ABILITYINFO_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_LAUNCHER_ABILITYINFO_H + +#include + +#include "application_info.h" +#include "element_name.h" + +namespace OHOS { +namespace AppExecFwk { + +struct LauncherAbilityInfo { +public: + std::string name; // ability name, only the main class name + ApplicationInfo applicationInfo; + std::string label; + ElementName elementname; + std::string icon; + int32_t userid; + int64_t installTime; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_LAUNCHER_ABILITYINFO_H \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_base/include/launcher_shortcut_info.h b/interfaces/innerkits/appexecfwk_base/include/launcher_shortcut_info.h new file mode 100644 index 0000000000..825b4a123f --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/include/launcher_shortcut_info.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_LAUNCHER_SHORTCUT_INFO_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_LAUNCHER_SHORTCUT_INFO_H + +#include "shortcut_info.h" + +namespace OHOS { +namespace AppExecFwk { + +struct LauncherShortcutInfo { + std::string icon; + std::vector intents; + std::string shortcutid; + std::string bundleName; + std::string label; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_LAUNCHER_SHORTCUT_INFO_H \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_base/include/module_usage_record.h b/interfaces/innerkits/appexecfwk_base/include/module_usage_record.h new file mode 100644 index 0000000000..faf211f237 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/include/module_usage_record.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_MODULE_USAGE_RECORD_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_MODULE_USAGE_RECORD_H + +#include + +#include "ability_info.h" +#include "parcel.h" +#include "refbase.h" + +namespace OHOS { +namespace AppExecFwk { +namespace UsageRecordKey { + const std::string LAUNCHED_COUNT = "launchedCount"; + const std::string LAST_LAUNCH_TIME = "lastLaunchTime"; + const std::string IS_REMOVED = "isRemoved"; + const std::string ABILITY_NAME = "abilityName"; + const std::string SCHEMA_LAST_LAUNCH_TIME = "$.lastLaunchTime"; +} // UsageRecordKey + +struct ModuleUsageRecord : public Parcelable { + std::string bundleName; + uint32_t appLabelId = 0; + std::string name; + uint32_t labelId = 0; + uint32_t descriptionId = 0; + std::string abilityName; + uint32_t abilityLabelId = 0; + uint32_t abilityDescriptionId = 0; + uint32_t abilityIconId = 0; + uint32_t launchedCount = 0; + int64_t lastLaunchTime = 0; + bool removed = false; + bool installationFreeSupported = true; + + bool ReadFromParcel(Parcel &parcel); + virtual bool Marshalling(Parcel &parcel) const override; + static ModuleUsageRecord *Unmarshalling(Parcel &parcel); + std::string ToString() const; + bool FromJsonString(const std::string &jsonString); +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_MODULE_USAGE_RECORD_H diff --git a/interfaces/innerkits/appexecfwk_base/src/ability_info.cpp b/interfaces/innerkits/appexecfwk_base/src/ability_info.cpp index 33497a8851..f3b64dcefd 100644 --- a/interfaces/innerkits/appexecfwk_base/src/ability_info.cpp +++ b/interfaces/innerkits/appexecfwk_base/src/ability_info.cpp @@ -58,9 +58,11 @@ const std::string JSON_KEY_DEVICE_ID = "deviceId"; const std::string JSON_KEY_IS_LAUNCHER_ABILITY = "isLauncherAbility"; const std::string JSON_KEY_IS_NATIVE_ABILITY = "isNativeAbility"; const std::string JSON_KEY_ENABLED = "enabled"; +const std::string JSON_KEY_SUPPORT_PIP_MODE = "supportPipMode"; const std::string JSON_KEY_TARGET_ABILITY = "targetAbility"; const std::string JSON_KEY_READ_PERMISSION = "readPermission"; const std::string JSON_KEY_WRITE_PERMISSION = "writePermission"; +const std::string JSON_KEY_CONFIG_CHANGES = "configChanges"; const std::string JSON_KEY_FORM = "form"; const std::string JSON_KEY_FORM_ENTITY = "formEntity"; const std::string JSON_KEY_MIN_FORM_HEIGHT = "minFormHeight"; @@ -73,6 +75,10 @@ const std::string JSON_KEY_CUSTOMIZE_DATA = "customizeData"; const std::string JSON_KEY_META_DATA = "metaData"; const std::string JSON_KEY_META_VALUE = "value"; const std::string JSON_KEY_META_EXTRA = "extra"; +const std::string JSON_KEY_LABEL_ID = "labelId"; +const std::string JSON_KEY_DESCRIPTION_ID = "descriptionId"; +const std::string JSON_KEY_ICON_ID = "iconId"; +const std::string JSON_KEY_FORM_ENABLED = "formEnabled"; } // namespace @@ -101,12 +107,21 @@ bool AbilityInfo::ReadFromParcel(Parcel &parcel) isLauncherAbility = parcel.ReadBool(); isNativeAbility = parcel.ReadBool(); enabled = parcel.ReadBool(); - + supportPipMode = parcel.ReadBool(); + formEnabled = parcel.ReadBool(); + int32_t configChangesSize; + READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, configChangesSize); + for (int32_t i = 0; i < configChangesSize; i++) { + configChanges.emplace_back(Str16ToStr8(parcel.ReadString16())); + } formEntity = parcel.ReadInt32(); minFormHeight = parcel.ReadInt32(); defaultFormHeight = parcel.ReadInt32(); minFormWidth = parcel.ReadInt32(); defaultFormWidth = parcel.ReadInt32(); + labelId = parcel.ReadInt32(); + descriptionId = parcel.ReadInt32(); + iconId = parcel.ReadInt32(); int32_t typeData; READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, typeData); @@ -222,11 +237,20 @@ bool AbilityInfo::Marshalling(Parcel &parcel) const WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Bool, parcel, isLauncherAbility); WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Bool, parcel, isNativeAbility); WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Bool, parcel, enabled); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Bool, parcel, supportPipMode); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Bool, parcel, formEnabled); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, configChanges.size()); + for (auto &configChange : configChanges) { + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(configChange)); + } WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, formEntity); WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, minFormHeight); WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, defaultFormHeight); WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, minFormWidth); WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, defaultFormWidth); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, labelId); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, descriptionId); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, iconId); WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, static_cast(type)); WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, static_cast(orientation)); WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, static_cast(launchMode)); @@ -286,8 +310,9 @@ void AbilityInfo::Dump(std::string prefix, int fd) APP_LOGE("dump Abilityinfo fcntl error %{public}s", strerror(errno)); return; } - flags &= O_ACCMODE; - if ((flags == O_WRONLY) || (flags == O_RDWR)) { + uint uflags = static_cast(flags); + uflags &= O_ACCMODE; + if ((uflags == O_WRONLY) || (uflags == O_RDWR)) { nlohmann::json jsonObject = *this; std::string result; result.append(prefix); @@ -347,13 +372,18 @@ void to_json(nlohmann::json &jsonObject, const AbilityInfo &abilityInfo) {JSON_KEY_IS_LAUNCHER_ABILITY, abilityInfo.isLauncherAbility}, {JSON_KEY_IS_NATIVE_ABILITY, abilityInfo.isNativeAbility}, {JSON_KEY_ENABLED, abilityInfo.enabled}, + {JSON_KEY_SUPPORT_PIP_MODE, abilityInfo.supportPipMode}, {JSON_KEY_READ_PERMISSION, abilityInfo.readPermission}, {JSON_KEY_WRITE_PERMISSION, abilityInfo.writePermission}, + {JSON_KEY_CONFIG_CHANGES, abilityInfo.configChanges}, {JSON_KEY_FORM_ENTITY, abilityInfo.formEntity}, {JSON_KEY_MIN_FORM_HEIGHT, abilityInfo.minFormHeight}, {JSON_KEY_DEFAULT_FORM_HEIGHT, abilityInfo.defaultFormHeight}, {JSON_KEY_MIN_FORM_WIDTH, abilityInfo.minFormWidth}, {JSON_KEY_DEFAULT_FORM_WIDTH, abilityInfo.defaultFormWidth}, + {JSON_KEY_LABEL_ID, abilityInfo.labelId}, + {JSON_KEY_DESCRIPTION_ID, abilityInfo.descriptionId}, + {JSON_KEY_ICON_ID, abilityInfo.iconId}, {JSON_KEY_KIND, abilityInfo.kind}, {JSON_KEY_TYPE, abilityInfo.type}, {JSON_KEY_ORIENTATION, abilityInfo.orientation}, @@ -372,7 +402,8 @@ void to_json(nlohmann::json &jsonObject, const AbilityInfo &abilityInfo) {JSON_KEY_CODE_PATH, abilityInfo.codePath}, {JSON_KEY_RESOURCE_PATH, abilityInfo.resourcePath}, {JSON_KEY_LIB_PATH, abilityInfo.libPath}, - {JSON_KEY_META_DATA, abilityInfo.metaData} + {JSON_KEY_META_DATA, abilityInfo.metaData}, + {JSON_KEY_FORM_ENABLED, abilityInfo.formEnabled} }; } @@ -415,13 +446,18 @@ void from_json(const nlohmann::json &jsonObject, AbilityInfo &abilityInfo) abilityInfo.isLauncherAbility = jsonObject.at(JSON_KEY_IS_LAUNCHER_ABILITY).get(); abilityInfo.isNativeAbility = jsonObject.at(JSON_KEY_IS_NATIVE_ABILITY).get(); abilityInfo.enabled = jsonObject.at(JSON_KEY_ENABLED).get(); + abilityInfo.supportPipMode = jsonObject.at(JSON_KEY_SUPPORT_PIP_MODE).get(); abilityInfo.readPermission = jsonObject.at(JSON_KEY_READ_PERMISSION).get(); abilityInfo.writePermission = jsonObject.at(JSON_KEY_WRITE_PERMISSION).get(); + abilityInfo.configChanges = jsonObject.at(JSON_KEY_CONFIG_CHANGES).get>(); abilityInfo.formEntity = jsonObject.at(JSON_KEY_FORM_ENTITY).get(); abilityInfo.minFormHeight = jsonObject.at(JSON_KEY_MIN_FORM_HEIGHT).get(); abilityInfo.defaultFormHeight = jsonObject.at(JSON_KEY_DEFAULT_FORM_HEIGHT).get(); abilityInfo.minFormWidth = jsonObject.at(JSON_KEY_MIN_FORM_WIDTH).get(); abilityInfo.defaultFormWidth = jsonObject.at(JSON_KEY_DEFAULT_FORM_WIDTH).get(); + abilityInfo.labelId = jsonObject.at(JSON_KEY_LABEL_ID).get(); + abilityInfo.descriptionId = jsonObject.at(JSON_KEY_DESCRIPTION_ID).get(); + abilityInfo.iconId = jsonObject.at(JSON_KEY_ICON_ID).get(); abilityInfo.kind = jsonObject.at(JSON_KEY_KIND).get(); abilityInfo.type = jsonObject.at(JSON_KEY_TYPE).get(); abilityInfo.orientation = jsonObject.at(JSON_KEY_ORIENTATION).get(); @@ -441,6 +477,7 @@ void from_json(const nlohmann::json &jsonObject, AbilityInfo &abilityInfo) abilityInfo.resourcePath = jsonObject.at(JSON_KEY_RESOURCE_PATH).get(); abilityInfo.libPath = jsonObject.at(JSON_KEY_LIB_PATH).get(); abilityInfo.metaData = jsonObject.at(JSON_KEY_META_DATA).get(); + abilityInfo.formEnabled = jsonObject.at(JSON_KEY_FORM_ENABLED).get(); } void AbilityInfo::ConvertToCompatiableAbilityInfo(CompatibleAbilityInfo& compatibleAbilityInfo) const @@ -462,6 +499,7 @@ void AbilityInfo::ConvertToCompatiableAbilityInfo(CompatibleAbilityInfo& compati compatibleAbilityInfo.permissions = permissions; compatibleAbilityInfo.deviceTypes = deviceTypes; compatibleAbilityInfo.deviceCapabilities = deviceCapabilities; + compatibleAbilityInfo.supportPipMode = supportPipMode; compatibleAbilityInfo.readPermission = readPermission; compatibleAbilityInfo.writePermission = writePermission; compatibleAbilityInfo.bundleName = bundleName; @@ -474,6 +512,9 @@ void AbilityInfo::ConvertToCompatiableAbilityInfo(CompatibleAbilityInfo& compati compatibleAbilityInfo.defaultFormHeight = defaultFormHeight; compatibleAbilityInfo.minFormWidth = minFormWidth; compatibleAbilityInfo.defaultFormWidth = defaultFormWidth; + compatibleAbilityInfo.iconId = iconId; + compatibleAbilityInfo.labelId = labelId; + compatibleAbilityInfo.descriptionId = descriptionId; compatibleAbilityInfo.enabled = enabled; } diff --git a/interfaces/innerkits/appexecfwk_base/src/application_info.cpp b/interfaces/innerkits/appexecfwk_base/src/application_info.cpp index 7fc357a4e7..8ae6e966e8 100644 --- a/interfaces/innerkits/appexecfwk_base/src/application_info.cpp +++ b/interfaces/innerkits/appexecfwk_base/src/application_info.cpp @@ -142,8 +142,9 @@ void ApplicationInfo::Dump(std::string prefix, int fd) APP_LOGE("dump ApplicationInfo fcntl error %{public}s", strerror(errno)); return; } - flags &= O_ACCMODE; - if ((flags == O_WRONLY) || (flags == O_RDWR)) { + uint uflags = static_cast(flags); + uflags &= O_ACCMODE; + if ((uflags == O_WRONLY) || (uflags == O_RDWR)) { nlohmann::json jsonObject = *this; std::string result; result.append(prefix); @@ -216,17 +217,22 @@ void from_json(const nlohmann::json &jsonObject, ApplicationInfo &applicationInf void ApplicationInfo::ConvertToCompatibleApplicationInfo(CompatibleApplicationInfo& compatibleApplicationInfo) const { + APP_LOGD("ApplicationInfo::ConvertToCompatibleApplicationInfo called"); compatibleApplicationInfo.name = name; + //compatibleApplicationInfo.icon = icon; compatibleApplicationInfo.label = label; compatibleApplicationInfo.description = description; + //compatibleApplicationInfo.cpuAbi = cpuAbi; compatibleApplicationInfo.process = process; compatibleApplicationInfo.systemApp = isSystemApp; + //compatibleApplicationInfo.isCompressNativeLibs = isCompressNativeLibs; compatibleApplicationInfo.iconId = iconId; compatibleApplicationInfo.labelId = labelId; compatibleApplicationInfo.descriptionId = descriptionId; compatibleApplicationInfo.permissions = permissions; compatibleApplicationInfo.moduleInfos = moduleInfos; compatibleApplicationInfo.supportedModes = supportedModes; + //compatibleApplicationInfo.enabled = debug; } } // namespace AppExecFwk diff --git a/interfaces/innerkits/appexecfwk_base/src/compatible_ability_info.cpp b/interfaces/innerkits/appexecfwk_base/src/compatible_ability_info.cpp index e6253fa5dd..80092620a7 100644 --- a/interfaces/innerkits/appexecfwk_base/src/compatible_ability_info.cpp +++ b/interfaces/innerkits/appexecfwk_base/src/compatible_ability_info.cpp @@ -63,6 +63,51 @@ bool CompatibleAbilityInfo::ReadFromParcel(Parcel& parcel) READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, launchModeData); launchMode = static_cast(launchModeData); + // int32_t permissionsSize; + // READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, permissionsSize); + // if (permissionsSize > Constants::MAX_LIMIT_SIZE) { + // APP_LOGE("permissions size is overflow"); + // return false; + // } + // for (int32_t i = 0; i < permissionsSize; i++) { + // std::string permission = Str16ToStr8(parcel.ReadString16()); + // if (permission.empty()) { + // APP_LOGE("ReadParcelable failed"); + // return false; + // } + // permissions.emplace_back(permission); + // } + + // int32_t deviceTypeSize; + // READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, deviceTypeSize); + // if (deviceTypeSize > Constants::MAX_DEVICETYPE_SIZE) { + // APP_LOGE("device type size is overflow"); + // return false; + // } + // for (auto i = 0; i < deviceTypeSize; i++) { + // std::string deviceType = Str16ToStr8(parcel.ReadString16()); + // if (deviceType.empty()) { + // APP_LOGE("ReadParcelable failed"); + // return false; + // } + // deviceTypes.emplace_back(deviceType); + // } + + // int32_t deviceCapabilitySize; + // READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, deviceCapabilitySize); + // if (deviceCapabilitySize > Constants::MAX_LIMIT_SIZE) { + // APP_LOGE("device capability size is overflow"); + // return false; + // } + // for (auto i = 0; i < deviceCapabilitySize; i++) { + // std::string deviceCapability = Str16ToStr8(parcel.ReadString16()); + // if (deviceCapability.empty()) { + // APP_LOGE("ReadParcelable failed"); + // return false; + // } + // deviceCapabilities.emplace_back(deviceCapability); + // } + supportPipMode = parcel.ReadBool(); grantPermission = parcel.ReadBool(); readPermission = Str16ToStr8(parcel.ReadString16()); @@ -73,6 +118,12 @@ bool CompatibleAbilityInfo::ReadFromParcel(Parcel& parcel) bundleName = Str16ToStr8(parcel.ReadString16()); className = Str16ToStr8(parcel.ReadString16()); deviceId = Str16ToStr8(parcel.ReadString16()); + // std::unique_ptr appInfo(parcel.ReadParcelable()); + // if (!appInfo) { + // APP_LOGE("ReadParcelable failed"); + // return false; + // } + // applicationInfo = *appInfo; formEntity = parcel.ReadInt32(); minFormHeight = parcel.ReadInt32(); defaultFormHeight = parcel.ReadInt32(); @@ -124,6 +175,27 @@ bool CompatibleAbilityInfo::Marshalling(Parcel& parcel) const WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, static_cast(orientation)); WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, static_cast(launchMode)); + // for compatible with JAVA. + // const auto permissionsSize = static_cast(permissions.size()); + // WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, permissionsSize); + // for (auto i = 0; i < permissionsSize; i++) { + // WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(permissions[i])); + // } + + // // for compatible with JAVA. + // const auto deviceTypeSize = static_cast(deviceTypes.size()); + // WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, deviceTypeSize); + // for (auto i = 0; i < deviceTypeSize; i++) { + // WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(deviceTypes[i])); + // } + + // // for compatible with JAVA. + // const auto deviceCapabilitySize = static_cast(deviceCapabilities.size()); + // WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, deviceCapabilitySize); + // for (auto i = 0; i < deviceCapabilitySize; i++) { + // WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(deviceCapabilities[i])); + // } + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Bool, parcel, supportPipMode); WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Bool, parcel, grantPermission); WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(readPermission)); @@ -135,6 +207,9 @@ bool CompatibleAbilityInfo::Marshalling(Parcel& parcel) const WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(className)); WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(deviceId)); APP_LOGE("CompatibleAbilityInfo::Marshalling start to write application info."); + // if (!parcel.WriteParcelable(&applicationInfo)) { + // return false; + // } WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, formEntity); WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, minFormHeight); WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, defaultFormHeight); @@ -166,6 +241,7 @@ void CompatibleAbilityInfo::ConvertToAbilityInfo(AbilityInfo& abilityInfo) const abilityInfo.permissions = permissions; abilityInfo.deviceTypes = deviceTypes; abilityInfo.deviceCapabilities = deviceCapabilities; + abilityInfo.supportPipMode = supportPipMode; abilityInfo.readPermission = readPermission; abilityInfo.writePermission = writePermission; abilityInfo.bundleName = bundleName; @@ -178,6 +254,9 @@ void CompatibleAbilityInfo::ConvertToAbilityInfo(AbilityInfo& abilityInfo) const abilityInfo.defaultFormHeight = defaultFormHeight; abilityInfo.minFormWidth = minFormWidth; abilityInfo.defaultFormWidth = defaultFormWidth; + abilityInfo.iconId = iconId; + abilityInfo.labelId = labelId; + abilityInfo.descriptionId = descriptionId; abilityInfo.enabled = enabled; } } // namespace AppExecFwk diff --git a/interfaces/innerkits/appexecfwk_base/src/compatible_application_info.cpp b/interfaces/innerkits/appexecfwk_base/src/compatible_application_info.cpp index ec8bab4822..8c1ddf82ae 100644 --- a/interfaces/innerkits/appexecfwk_base/src/compatible_application_info.cpp +++ b/interfaces/innerkits/appexecfwk_base/src/compatible_application_info.cpp @@ -17,8 +17,8 @@ #include #include -#include -#include +#include +#include #include "nlohmann/json.hpp" #include "string_ex.h" @@ -137,10 +137,13 @@ void CompatibleApplicationInfo::ConvertToApplicationInfo(ApplicationInfo& applic { APP_LOGD("CompatibleApplicationInfo::ConvertToApplicationInfo called"); applicationInfo.name = name; + //applicationInfo.icon = icon; applicationInfo.label = label; applicationInfo.description = description; + //applicationInfo.cpuAbi = cpuAbi; applicationInfo.process = process; applicationInfo.isSystemApp = systemApp; + //applicationInfo.isCompressNativeLibs = isCompressNativeLibs; applicationInfo.iconId = iconId; applicationInfo.labelId = labelId; applicationInfo.descriptionId = descriptionId; @@ -148,6 +151,7 @@ void CompatibleApplicationInfo::ConvertToApplicationInfo(ApplicationInfo& applic applicationInfo.moduleInfos = moduleInfos; applicationInfo.supportedModes = supportedModes; applicationInfo.enabled = debug; + //applicationInfo.entryModuleName = ""; } } // namespace AppExecFwk } // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_base/src/form_js_info.cpp b/interfaces/innerkits/appexecfwk_base/src/form_js_info.cpp new file mode 100644 index 0000000000..4b674f42bd --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/src/form_js_info.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2021 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 "form_js_info.h" +#include "string_ex.h" + +namespace OHOS { +namespace AppExecFwk { +bool FormJsInfo::ReadFromParcel(Parcel &parcel) +{ + formId = parcel.ReadInt64(); + formName = Str16ToStr8(parcel.ReadString16()); + bundleName = Str16ToStr8(parcel.ReadString16()); + abilityName = Str16ToStr8(parcel.ReadString16()); + + formTempFlg = parcel.ReadBool(); + jsFormCodePath = Str16ToStr8(parcel.ReadString16()); + formData = Str16ToStr8(parcel.ReadString16()); + + return true; +} + +FormJsInfo *FormJsInfo::Unmarshalling(Parcel &parcel) +{ + FormJsInfo *formJsInfo = new (std::nothrow) FormJsInfo(); + if (formJsInfo && !formJsInfo->ReadFromParcel(parcel)) { + delete formJsInfo; + formJsInfo = nullptr; + } + return formJsInfo; +} + +bool FormJsInfo::Marshalling(Parcel &parcel) const +{ + // write formId + if (!parcel.WriteInt64(formId)) { + return false; + } + // write formName + if (!parcel.WriteString16(Str8ToStr16(formName))) { + return false; + } + // write bundleName + if (!parcel.WriteString16(Str8ToStr16(bundleName))) { + return false; + } + // write abilityName + if (!parcel.WriteString16(Str8ToStr16(abilityName))) { + return false; + } + + // write tempFlag + if (!parcel.WriteBool(formTempFlg)) { + return false; + } + + // write jsFormCodePath + if (!parcel.WriteString16(Str8ToStr16(jsFormCodePath))) { + return false; + } + + // write formData + if (!parcel.WriteString16(Str8ToStr16(formData))) { + return false; + } + + return true; +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_base/src/form_provider_data.cpp b/interfaces/innerkits/appexecfwk_base/src/form_provider_data.cpp new file mode 100644 index 0000000000..e314d468e1 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/src/form_provider_data.cpp @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2021 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 + +#include "app_log_wrapper.h" +#include "form_provider_data.h" +#include "message_parcel.h" +#include "string_ex.h" + +namespace OHOS { +namespace AppExecFwk { +const int IMAGE_DATA_STATE_REMOVED = -1; +const int IMAGE_DATA_STATE_NO_OPERATION = 0; +const int IMAGE_DATA_STATE_ADDED = 1; + +/** + * @brief Constructor. + */ +FormProviderData::FormProviderData() +{ + jsonFormProviderData_.clear(); +} + +/** + * @brief A constructor used to create a {@code FormProviderData} instance with data of + * the {@code nlohmann::json} type specified. + * @param jsonData Indicates the data to be carried in the new {@code FormProviderData} instance, + * in {@code nlohmann::json} format. + */ +FormProviderData::FormProviderData(nlohmann::json &jsonData) +{ + jsonFormProviderData_ = jsonData; +} + +/** + * @brief A constructor used to create a {@code FormProviderData} instance with data of the {@code String} type + * specified. + * @param jsonDataString Indicates the data to be carried in the new {@code FormProviderData} instance, + * in JSON string format. + */ +FormProviderData::FormProviderData(std::string jsonDataString) +{ + jsonFormProviderData_ = nlohmann::json::parse(jsonDataString); +} + +/** + * @brief Updates form data in this {@code FormProviderData} object. + * @param jsonData Indicates the new data to use, in {@code ZSONObject} format. + */ +void FormProviderData::UpdateData(nlohmann::json &jsonData) +{ + jsonFormProviderData_ = jsonData; +} +/** + * @brief Obtains the form data stored in this {@code FormProviderData} object. + * @return Returns json data + */ +nlohmann::json FormProviderData::GetData() const +{ + return jsonFormProviderData_; +} +/** + * @brief Obtains the form data stored in this {@code FormProviderData} object. + * @return Returns json string format + */ +std::string FormProviderData::GetDataString() const +{ + APP_LOGI("%{public}s called", __func__); + return jsonFormProviderData_.empty() ? "" : jsonFormProviderData_.dump(); +} + +/** + * @brief Adds an image to this {@code FormProviderData} instance. + * @param picName Indicates the name of the image to add. + * @param data Indicates the binary data of the image content. + */ +void FormProviderData::AddImageData(std::string picName, char *data) +{ + if ((picName.length() == 0) || (sizeof(data) == 0)) { + APP_LOGE("input param is NULL!"); + return; + } + + rawImageBytesMap_[picName] = data; + + imageDataState_ = IMAGE_DATA_STATE_ADDED; +} + +/** + * @brief Removes data of an image with the specified {@code picName} from this {@code FormProviderData} instance. + * @param picName Indicates the name of the image to remove. + */ +void FormProviderData::RemoveImageData(std::string picName) +{ + rawImageBytesMap_.erase(picName); +} + +/** + * @brief Set the form data stored from string string. + * @param Returns string string. + */ +void FormProviderData::SetDataString(std::string &jsonDataString) +{ + APP_LOGI("%{public}s called", __func__); + jsonFormProviderData_ = nlohmann::json::parse(jsonDataString); +} +/** + * @brief Merge new data to FormProviderData. + * @param addJsonData data to merge to FormProviderData + */ +void FormProviderData::MergeData(nlohmann::json &addJsonData) +{ + APP_LOGI("%{public}s called", __func__); + if (addJsonData.empty()) { + return; + } + + if (jsonFormProviderData_.empty()) { + jsonFormProviderData_ = addJsonData; + return; + } + + for (auto &it : addJsonData.items()) { + jsonFormProviderData_[it.key()] = it.value(); + } +} + +/** + * @brief Obtains the imageDataMap stored in this {@code FormProviderData} object. + * @return Returns the map that contains shared image data. + */ +std::map, int32_t>> FormProviderData::GetImageDataMap() +{ + return imageDataMap_; +} + +/** + * @brief Obtains the add/remove state stored in this {@code FormProviderData} object. + * @return Returns the add/remove state of shared image data. + */ +int32_t FormProviderData::GetImageDataState() +{ + return imageDataState_; +} + +/** + * @brief Updates imageDataState in this {@code FormProviderData} object. + * @param imageDataState Indicates the imageDataState to update. + */ +void FormProviderData::SetImageDataState(int32_t imageDataState) +{ + imageDataState_ = imageDataState; +} + +/** + * @brief Updates imageDataMap in this {@code FormProviderData} object. + * @param imageDataMap Indicates the imageDataMap to update. + */ +void FormProviderData::SetImageDataMap(std::map, int32_t>> imageDataMap) +{ + imageDataMap_ = imageDataMap; +} + +/** + * Read this {@code FormProviderData} object from a Parcel. + * @param parcel the parcel + * eturn Returns {@code true} if the marshalling is successful; returns {@code false} otherwise. + */ +bool FormProviderData::ReadFromParcel(Parcel &parcel) +{ + jsonFormProviderData_ = nlohmann::json::parse(Str16ToStr8(parcel.ReadString16())); + // MessageParcel* messageParcel = dynamic_cast&parcel; // dynamic_cast need rtti + // if(messageParcel == nullptr) { + // return true; + // } + + imageDataState_ = parcel.ReadInt32(); + switch (imageDataState_) { + case IMAGE_DATA_STATE_ADDED: { + int32_t imageDataNum = parcel.ReadInt32(); + for (int32_t i = 0; i < imageDataNum; i++) { + MessageParcel* messageParcel = (MessageParcel*)&parcel; + sptr ashmem = messageParcel->ReadAshmem(); + if (ashmem == nullptr) { + APP_LOGE("%{public}s failed, ashmem is nullptr", __func__); + return false; + } + + int32_t len = parcel.ReadInt32(); + std::pair, int32_t> imageDataRecord = std::make_pair(ashmem, len); + imageDataMap_.emplace(Str16ToStr8(parcel.ReadString16()), imageDataRecord); + } + break; + } + case IMAGE_DATA_STATE_NO_OPERATION: + case IMAGE_DATA_STATE_REMOVED: + break; + default: + APP_LOGW("%{public}s failed, unexpected imageDataState_ %{public}d", __func__, imageDataState_); + break; + } + return true; +} + +/** + * @brief Marshals this {@code FormProviderData} object into a {@link ohos.utils.Parcel} object. + * @param parcel Indicates the {@code Parcel} object for marshalling. + * @return Returns {@code true} if the marshalling is successful; returns {@code false} otherwise. + */ +bool FormProviderData::Marshalling(Parcel &parcel) const +{ + APP_LOGI("%{public}s called", __func__); + if (!parcel.WriteString16(Str8ToStr16(jsonFormProviderData_.empty() ? "" : jsonFormProviderData_.dump()))) { + return false; + } + // MessageParcel* messageParcel = dynamic_cast&parcel; // dynamic_cast need rtti + // if(messageParcel == nullptr) { + // return true; + // } + + parcel.WriteInt32(imageDataState_); + switch (imageDataState_) { + case IMAGE_DATA_STATE_ADDED: { + if (rawImageBytesMap_.size() == 0) { + APP_LOGE("%{public}s failed, rawImageBytesMap_ is empty", __func__); + return false; + } + parcel.WriteInt32(rawImageBytesMap_.size()); // firstly write the number of shared image to add + for (auto &entry : rawImageBytesMap_) { + if (!WriteImageDataToParcel(parcel, entry.first, entry.second)) { + APP_LOGE("%{public}s failed, the picture name is %{public}s", __func__, entry.first.c_str()); + return false; + } + parcel.WriteInt32(sizeof(entry.second)); + parcel.WriteString16(Str8ToStr16(entry.first)); + } + break; + } + case IMAGE_DATA_STATE_NO_OPERATION: + case IMAGE_DATA_STATE_REMOVED: + break; + default: + APP_LOGW("%{public}s failed, unexpected imageDataState_ %{public}d", __func__, imageDataState_); + break; + } + return true; +} + +/** + * @brief Unmarshals this {@code FormProviderData} object from a {@link ohos.utils.Parcel} object. + * @param parcel Indicates the {@code Parcel} object for unmarshalling. + * @return FormProviderData. + */ +FormProviderData* FormProviderData::Unmarshalling(Parcel &parcel) +{ + FormProviderData *formProviderData = new (std::nothrow) FormProviderData(); + if (formProviderData && !formProviderData->ReadFromParcel(parcel)) { + delete formProviderData; + formProviderData = nullptr; + } + + return formProviderData; +} + +/** + * @brief Clear imageDataMap, rawImageBytesMap_, imageDataState_ and jsonFormProviderData_. + */ +void FormProviderData::ClearData() +{ + jsonFormProviderData_.clear(); +} + +bool FormProviderData::WriteImageDataToParcel(Parcel &parcel, std::string picName, char *data) const +{ + sptr ashmem = Ashmem::CreateAshmem(picName.c_str(), sizeof(data)); + if (ashmem == nullptr) { + APP_LOGE("create shared memory fail"); + return false; + } + + bool ret = ashmem->MapReadAndWriteAshmem(); + if (!ret) { + APP_LOGE("map shared memory fail"); + return false; + } + + ret = ashmem->WriteToAshmem(data, sizeof(data), 0); + if (!ret) { + APP_LOGE("write image data to shared memory fail"); + return false; + } + + ashmem->UnmapAshmem(); + + MessageParcel* messageParcel = (MessageParcel*)&parcel; + ret = messageParcel->WriteAshmem(ashmem); + + ashmem->CloseAshmem(); // close ashmem after writeAshmem because writeAshmem will dup fd + if (!ret) { + APP_LOGE("writeAshmem fail, the picture name is %{public}s", picName.c_str()); + return false; + } + + return true; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_base/src/form_provider_info.cpp b/interfaces/innerkits/appexecfwk_base/src/form_provider_info.cpp new file mode 100644 index 0000000000..64773c9d5a --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/src/form_provider_info.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2021 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 "form_provider_info.h" +#include "string_ex.h" + +namespace OHOS { +namespace AppExecFwk { +bool FormProviderInfo::ReadFromParcel(Parcel &parcel) +{ + formId_ = parcel.ReadInt64(); + auto bindingData = parcel.ReadParcelable(); + jsBindingData_ = *bindingData; + return true; +} + +FormProviderInfo *FormProviderInfo::Unmarshalling(Parcel &parcel) +{ + FormProviderInfo *formProviderInfo = new (std::nothrow) FormProviderInfo(); + if (formProviderInfo && !formProviderInfo->ReadFromParcel(parcel)) { + delete formProviderInfo; + formProviderInfo = nullptr; + } + return formProviderInfo; +} + +bool FormProviderInfo::Marshalling(Parcel &parcel) const +{ + if (!parcel.WriteInt64(formId_)) { + return false; + } + if (!parcel.WriteParcelable(&jsBindingData_)) { + return false; + } + + return true; +} +void FormProviderInfo::SetFormDataString(std::string &dataString) +{ + jsBindingData_.SetDataString(dataString); +} +/** + * @brief Merge new data to FormProviderData. + * @param addJsonData data to merge to FormProviderData + */ +void FormProviderInfo::MergeData(nlohmann::json &addJsonData) +{ + jsBindingData_.MergeData(addJsonData); +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_base/src/install_param.cpp b/interfaces/innerkits/appexecfwk_base/src/install_param.cpp index 378233ae39..639c79683c 100644 --- a/interfaces/innerkits/appexecfwk_base/src/install_param.cpp +++ b/interfaces/innerkits/appexecfwk_base/src/install_param.cpp @@ -36,6 +36,7 @@ bool InstallParam::ReadFromParcel(Parcel &parcel) userId = parcel.ReadInt32(); isKeepData = parcel.ReadBool(); + noCheckSignature = parcel.ReadBool(); return true; } @@ -56,6 +57,7 @@ bool InstallParam::Marshalling(Parcel &parcel) const WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, static_cast(installLocation)); WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, userId); WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Bool, parcel, isKeepData); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Bool, parcel, noCheckSignature); return true; } diff --git a/interfaces/innerkits/appexecfwk_base/src/module_usage_record.cpp b/interfaces/innerkits/appexecfwk_base/src/module_usage_record.cpp new file mode 100644 index 0000000000..369f47976a --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/src/module_usage_record.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2021 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 "module_usage_record.h" + +#include "string_ex.h" + +#include "app_log_wrapper.h" +#include "nlohmann/json.hpp" +#include "parcel_macro.h" + +namespace OHOS { +namespace AppExecFwk { + +bool ModuleUsageRecord::ReadFromParcel(Parcel &parcel) +{ + name = Str16ToStr8(parcel.ReadString16()); + bundleName = Str16ToStr8(parcel.ReadString16()); + abilityName = Str16ToStr8(parcel.ReadString16()); + appLabelId = parcel.ReadInt32(); + labelId = parcel.ReadInt32(); + descriptionId = parcel.ReadInt32(); + abilityLabelId = parcel.ReadInt32(); + abilityDescriptionId = parcel.ReadInt32(); + abilityIconId = parcel.ReadInt32(); + launchedCount = parcel.ReadInt32(); + lastLaunchTime = parcel.ReadInt64(); + removed = parcel.ReadBool(); + installationFreeSupported = parcel.ReadBool(); + return true; +} + +ModuleUsageRecord *ModuleUsageRecord::Unmarshalling(Parcel &parcel) +{ + ModuleUsageRecord *record = new ModuleUsageRecord(); + if (!record->ReadFromParcel(parcel)) { + APP_LOGW("read ModuleUsageRecord from parcel failed"); + delete record; + record = nullptr; + } + return record; +} + +bool ModuleUsageRecord::Marshalling(Parcel &parcel) const +{ + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(name)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(bundleName)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(abilityName)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, appLabelId); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, labelId); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, descriptionId); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, abilityLabelId); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, abilityDescriptionId); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, abilityIconId); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, launchedCount); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int64, parcel, lastLaunchTime); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Bool, parcel, removed); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Bool, parcel, installationFreeSupported); + return true; +} + +std::string ModuleUsageRecord::ToString() const +{ + nlohmann::json json; + json[UsageRecordKey::LAUNCHED_COUNT] = launchedCount; + json[UsageRecordKey::LAST_LAUNCH_TIME] = lastLaunchTime; + json[UsageRecordKey::IS_REMOVED] = removed; + json[UsageRecordKey::ABILITY_NAME] = abilityName; + return json.dump(); +} + +bool ModuleUsageRecord::FromJsonString(const std::string &jsonString) +{ + nlohmann::json jsonObject; + + jsonObject = nlohmann::json::parse(jsonString); + if (jsonObject.is_discarded()) { + APP_LOGE("failed to parse module usage record: %{public}s.", jsonString.c_str()); + return false; + } + this->launchedCount = jsonObject.at(UsageRecordKey::LAUNCHED_COUNT).get(); + this->lastLaunchTime = jsonObject.at(UsageRecordKey::LAST_LAUNCH_TIME).get(); + this->removed = jsonObject.at(UsageRecordKey::IS_REMOVED).get(); + this->abilityName = jsonObject.at(UsageRecordKey::ABILITY_NAME).get(); + + return true; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_core/BUILD.gn b/interfaces/innerkits/appexecfwk_core/BUILD.gn index e42c15b90f..476fbe7153 100644 --- a/interfaces/innerkits/appexecfwk_core/BUILD.gn +++ b/interfaces/innerkits/appexecfwk_core/BUILD.gn @@ -18,6 +18,7 @@ config("appmgr_sdk_config") { include_dirs = [ "include/appmgr", "//foundation/aafwk/standard/frameworks/kits/ability/native/include", + "//foundation/aafwk/standard/interfaces/innerkits/ability_manager/include", ] } @@ -25,6 +26,10 @@ config("bundlemgr_sdk_config") { include_dirs = [ "include/bundlemgr" ] } +config("formmgr_sdk_config") { + include_dirs = [ "include/formmgr" ] +} + config("appexecfwk_core_config") { include_dirs = [ "include" ] } @@ -34,6 +39,7 @@ ohos_shared_library("appexecfwk_core") { "//third_party/json/include", "${services_path}/appmgr/include", "${services_path}/bundlemgr/include", + "${services_path}/formmgr/include", "//utils/system/safwk/native/include", ] @@ -59,20 +65,33 @@ ohos_shared_library("appexecfwk_core") { "src/bundlemgr/bundle_installer_proxy.cpp", "src/bundlemgr/bundle_mgr_host.cpp", "src/bundlemgr/bundle_mgr_proxy.cpp", + "src/bundlemgr/bundle_monitor.cpp", "src/bundlemgr/bundle_status_callback_host.cpp", "src/bundlemgr/bundle_status_callback_proxy.cpp", "src/bundlemgr/clean_cache_callback_host.cpp", "src/bundlemgr/clean_cache_callback_proxy.cpp", + "src/bundlemgr/launcher_service.cpp", "src/bundlemgr/on_permission_changed_callback_host.cpp", "src/bundlemgr/on_permission_changed_callback_proxy.cpp", "src/bundlemgr/status_receiver_host.cpp", "src/bundlemgr/status_receiver_proxy.cpp", + "src/formmgr/form_host_proxy.cpp", + "src/formmgr/form_host_stub.cpp", + "src/formmgr/form_mgr_proxy.cpp", + "src/formmgr/form_mgr_stub.cpp", + "src/formmgr/form_provider_proxy.cpp", + "src/formmgr/form_provider_stub.cpp", + "src/formmgr/form_supply_proxy.cpp", + "src/formmgr/form_supply_stub.cpp", + "src/formmgr/provider_connect_proxy.cpp", + "src/formmgr/provider_connect_stub.cpp", ] public_configs = [ ":appexecfwk_core_config", ":appmgr_sdk_config", ":bundlemgr_sdk_config", + ":formmgr_sdk_config", ] defines = [ @@ -93,6 +112,9 @@ ohos_shared_library("appexecfwk_core") { ] external_deps = [ + "ces_standard:cesfwk_core", + "ces_standard:cesfwk_innerkits", + "hiviewdfx_hilog_native:libhilog", "hiviewdfx_hilog_native:libhilog", "ipc:ipc_core", ] diff --git a/interfaces/innerkits/appexecfwk_core/appexecfwk_headers.gni b/interfaces/innerkits/appexecfwk_core/appexecfwk_headers.gni index a0bae2802b..0be383b054 100644 --- a/interfaces/innerkits/appexecfwk_core/appexecfwk_headers.gni +++ b/interfaces/innerkits/appexecfwk_core/appexecfwk_headers.gni @@ -24,6 +24,10 @@ appexecfwk_headers = { "bundlemgr/status_receiver_interface.h", "bundlemgr/on_permission_changed_callback_interface.h", "appmgr/app_process_data.h", + "formmgr/form_mgr_interface.h", + "formmgr/form_host_interface.h", + "formmgr/form_provider_interface.h", + "formmgr/form_supply_interface.h", ] header_base = "interfaces/innerkits/appexecfwk_core/include" diff --git a/interfaces/innerkits/appexecfwk_core/include/appmgr/app_process_data.h b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_process_data.h index 8ba81a3d45..aae4d47494 100644 --- a/interfaces/innerkits/appexecfwk_core/include/appmgr/app_process_data.h +++ b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_process_data.h @@ -52,6 +52,7 @@ struct AppProcessData : public Parcelable { std::string processName; ApplicationState appState = ApplicationState::APP_STATE_CREATE; pid_t pid = 0; + int32_t uid = 0; }; } // namespace AppExecFwk diff --git a/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_mgr_host.h b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_mgr_host.h index cae86ca55d..ecf6aff158 100644 --- a/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_mgr_host.h +++ b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_mgr_host.h @@ -118,6 +118,13 @@ private: * @return Returns ERR_OK if called successfully; returns error code otherwise. */ ErrCode HandleQueryAbilityInfo(Parcel &data, Parcel &reply); + /** + * @brief Handles the QueryAbilityInfos function called from a IBundleMgr proxy object. + * @param data Indicates the data to be read. + * @param reply Indicates the reply to be sent; + * @return Returns ERR_OK if called successfully; returns error code otherwise. + */ + ErrCode HandleQueryAbilityInfos(Parcel &data, Parcel &reply); /** * @brief Handles the QueryAbilityInfoByUri function called from a IBundleMgr proxy object. * @param data Indicates the data to be read. @@ -370,7 +377,20 @@ private: * @return Returns ERR_OK if called successfully; returns error code otherwise. */ ErrCode HandleGetShortcutInfos(Parcel &data, Parcel &reply); - + /** + * @brief Handles the HandleGetModuleUsageRecords function called from a IBundleMgr proxy object. + * @param data Indicates the data to be read. + * @param reply Indicates the reply to be sent; + * @return Returns ERR_OK if called successfully; returns error code otherwise. + */ + ErrCode HandleGetModuleUsageRecords(Parcel &data, Parcel &reply); + /** + * @brief Handles the HandleNotifyActivityLifeStatus function called from a IBundleMgr proxy object. + * @param data Indicates the data to be read. + * @param reply Indicates the reply to be sent; + * @return Returns ERR_OK if called successfully; returns error code otherwise. + */ + ErrCode HandleNotifyActivityLifeStatus(Parcel &data, Parcel &reply); private: /** * @brief Write a parcelabe vector objects to the proxy node. diff --git a/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_mgr_interface.h b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_mgr_interface.h index ce84212199..ea34e91cfa 100644 --- a/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_mgr_interface.h +++ b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_mgr_interface.h @@ -19,6 +19,7 @@ #include "ability_info.h" #include "form_info.h" #include "shortcut_info.h" +#include "module_usage_record.h" #include "application_info.h" #include "bundle_info.h" #include "hap_module_info.h" @@ -147,6 +148,13 @@ public: * @return Returns true if the AbilityInfo is successfully obtained; returns false otherwise. */ virtual bool QueryAbilityInfo(const Want &want, AbilityInfo &abilityInfo) = 0; + /** + * @brief Query the AbilityInfo of list by the given Want. + * @param want Indicates the information of the ability. + * @param abilityInfos Indicates the obtained AbilityInfos object. + * @return Returns true if the AbilityInfos is successfully obtained; returns false otherwise. + */ + virtual bool QueryAbilityInfos(const Want &want, std::vector &abilityInfos) = 0; /** * @brief Query the AbilityInfo by ability.uri in config.json. * @param abilityUri Indicates the uri of the ability. @@ -391,11 +399,27 @@ public: * @return Returns true if this function is successfully called; returns false otherwise. */ virtual bool GetShortcutInfos(const std::string &bundleName, std::vector &shortcutInfos) = 0; + /** + * @brief Get module usage record list in descending order of lastLaunchTime. + * @param maxNum the return size of the records, must be in range of 1 to 1000. + * @param moduleUsageRecords List of ModuleUsageRecord objects if obtained. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool GetModuleUsageRecords(const int32_t number, std::vector &moduleUsageRecords) = 0; /** * @brief Obtains the interface used to install and uninstall bundles. * @return Returns a pointer to IBundleInstaller class if exist; returns nullptr otherwise. */ virtual sptr GetBundleInstaller() = 0; + /** + * @brief Notify a specified ability for activity. + * @param bundleName Indicates the bundle name of the ability to activity. + * @param abilityName Indicates the name of the ability to activity. + * @param launchTime Indicates the ability launchTime. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool NotifyActivityLifeStatus( + const std::string &bundleName, const std::string &abilityName, const int64_t launchTime) = 0; enum class Message { GET_APPLICATION_INFO, @@ -412,6 +436,7 @@ public: CHECK_IS_SYSTEM_APP_BY_UID, GET_BUNDLE_INFOS_BY_METADATA, QUERY_ABILITY_INFO, + QUERY_ABILITY_INFOS, QUERY_ABILITY_INFO_BY_URI, QUERY_KEEPALIVE_BUNDLE_INFOS, GET_ABILITY_LABEL, @@ -445,8 +470,10 @@ public: GET_ALL_FORMS_INFO, GET_FORMS_INFO_BY_APP, GET_FORMS_INFO_BY_MODULE, - GET_SHORTCUT_INFO, + GET_MODULE_USAGE_RECORD, + GET_SHORTCUT_INFO, GET_BUNDLE_INSTALLER, + NOTIFY_ACTIVITY_LIFE_STATUS, }; }; diff --git a/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_mgr_proxy.h b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_mgr_proxy.h index 82d74f9831..bd268e69f4 100644 --- a/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_mgr_proxy.h +++ b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_mgr_proxy.h @@ -136,6 +136,13 @@ public: * @return Returns true if the AbilityInfo is successfully obtained; returns false otherwise. */ virtual bool QueryAbilityInfo(const Want &want, AbilityInfo &abilityInfo) override; + /** + * @brief Query the AbilityInfo of list by the given Want. + * @param want Indicates the information of the ability. + * @param abilityInfos Indicates the obtained AbilityInfos object. + * @return Returns true if the AbilityInfos is successfully obtained; returns false otherwise. + */ + virtual bool QueryAbilityInfos(const Want &want, std::vector &abilityInfos) override; /** * @brief Query the AbilityInfo by ability.uri in config.json through the proxy object. * @param abilityUri Indicates the uri of the ability. @@ -387,6 +394,23 @@ public: * @return Returns true if this function is successfully called; returns false otherwise. */ virtual bool GetShortcutInfos(const std::string &bundleName, std::vector &shortcutInfos) override; + /** + * @brief Get module usage record list in descending order of lastLaunchTime. + * @param maxNum the return size of the records, must be in range of 1 to 1000. + * @param moduleUsageRecords List of ModuleUsageRecord objects if obtained. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool GetModuleUsageRecords(const int32_t number, std::vector &moduleUsageRecords) override; + /** + * @brief Notify a specified ability for activity. + * @param bundleName Indicates the bundle name of the ability to activity. + * @param abilityName Indicates the name of the ability to activity. + * @param launchTime Indicates the ability launchTime. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool NotifyActivityLifeStatus( + const std::string &bundleName, const std::string &abilityName, const int64_t launchTime) override; + private: /** * @brief Send a command message from the proxy object. diff --git a/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_monitor.h b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_monitor.h new file mode 100644 index 0000000000..337502c15b --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_monitor.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_MONITOR_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_MONITOR_H + +#include "common_event_manager.h" +#include "common_event_support.h" +#include "common_event_subscriber.h" +#include "common_event_subscribe_info.h" +#include "bundle_status_callback_interface.h" +#include "bundle_constants.h" +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { + +class BundleMonitor : public EventFwk::CommonEventSubscriber, public std::enable_shared_from_this { +public: + using Want = OHOS::AAFwk::Want; + + BundleMonitor(const EventFwk::CommonEventSubscribeInfo &subscribeInfo); + ~BundleMonitor() = default; + + /** + * @brief Subscribe commonEvent. + * @param callback The callback of IBundleStatusCallback + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool Subscribe(const sptr &callback); + /** + * @brief Unsubscribe commonEvent. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool UnSubscribe(); + /** + * @brief CommonEvent callback. + * @param eventData publish common event data. + * @return + */ + void OnReceiveEvent(const EventFwk::CommonEventData &eventData); + +private: + const std::string BUNDLE_NAME = "bundleName"; + const std::string USER_ID = "userId"; + sptr callback_ = nullptr; +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_MONITOR_H \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_status_callback_interface.h b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_status_callback_interface.h index 7764cff7cb..e498c616a4 100644 --- a/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_status_callback_interface.h +++ b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_status_callback_interface.h @@ -41,6 +41,24 @@ public: */ virtual void OnBundleStateChanged(const uint8_t installType, const int32_t resultCode, const std::string &resultMsg, const std::string &bundleName) = 0; + /** + * @brief Called when a new application package has been installed on the device. + * @param bundleName Indicates the name of the bundle whose state has been installed. + * @param userId Indicates the id of the bundle whose state has been installed. + */ + virtual void OnBundleAdded(const std::string &bundleName, const int userId) = 0; + /** + * @brief Called when a new application package has been Updated on the device. + * @param bundleName Indicates the name of the bundle whose state has been Updated. + * @param userId Indicates the id of the bundle whose state has been Updated. + */ + virtual void OnBundleUpdated(const std::string &bundleName, const int userId) = 0; + /** + * @brief Called when a new application package has been Removed on the device. + * @param bundleName Indicates the name of the bundle whose state has been Removed. + * @param userId Indicates the id of the bundle whose state has been Removed. + */ + virtual void OnBundleRemoved(const std::string &bundleName, const int userId) = 0; enum class Message { ON_BUNDLE_STATE_CHANGED, diff --git a/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_status_callback_proxy.h b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_status_callback_proxy.h index ad8a0dedc9..1ff2832b4a 100644 --- a/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_status_callback_proxy.h +++ b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_status_callback_proxy.h @@ -39,6 +39,24 @@ public: */ virtual void OnBundleStateChanged(const uint8_t installType, const int32_t resultCode, const std::string &resultMsg, const std::string &bundleName) override; + /** + * @brief Called when a new application package has been installed on the device. + * @param bundleName Indicates the name of the bundle whose state has been installed. + * @param userId Indicates the id of the bundle whose state has been installed. + */ + virtual void OnBundleAdded(const std::string &bundleName, const int userId) override {}; + /** + * @brief Called when a new application package has been Updated on the device. + * @param bundleName Indicates the name of the bundle whose state has been Updated. + * @param userId Indicates the id of the bundle whose state has been Updated. + */ + virtual void OnBundleUpdated(const std::string &bundleName, const int userId) override {}; + /** + * @brief Called when a new application package has been Removed on the device. + * @param bundleName Indicates the name of the bundle whose state has been Removed. + * @param userId Indicates the id of the bundle whose state has been Removed. + */ + virtual void OnBundleRemoved(const std::string &bundleName, const int userId) override {}; private: static inline BrokerDelegator delegator_; diff --git a/interfaces/innerkits/appexecfwk_core/include/bundlemgr/launcher_service.h b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/launcher_service.h new file mode 100644 index 0000000000..83ba113d6f --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/launcher_service.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_LAUNCHER_SERVICE_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_LAUNCHER_SERVICE_H + +#include +#include + +#include "bundle_mgr_interface.h" +#include "securec.h" +#include "system_ability_definition.h" +#include "if_system_ability_manager.h" +#include "iservice_registry.h" +#include "bundle_monitor.h" +#include "bundle_status_callback_interface.h" +#include "launcher_ability_info.h" +#include "launcher_shortcut_info.h" +#include "ability_info.h" +#include "application_info.h" +#include "want.h" +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { + +class LauncherService { +public: + using Want = OHOS::AAFwk::Want; + + LauncherService(); + virtual ~LauncherService() = default; + + /** + * @brief Registers a callback method for monitoring bundle installation, uninstallation, and update events. + * @param callback Indicates the callback method to be called. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool RegisterCallback(const sptr &callback); + /** + * @brief Unregisters the callback method for monitoring bundle installation, uninstallation, and update events. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool UnRegisterCallback(); + /** + * @brief Obtains launcher abilities based on the bundle name and user id. + * @param bundleName Indicates the bundle name. + * @param userId Indicates the user ID. + * @param launcherAbilityInfos List of LauncherAbilityInfo objects if obtained; + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool GetAbilityList( + const std::string &bundleName, const int userId, std::vector &launcherAbilityInfos); + /** + * @brief Obtains launcher ability based on the want and user id. + * @param want Indicates the application bundle name to be queried. + * @param userId Indicates the user ID. + * @param launcherAbilityInfo Indicates the obtained LauncherAbilityInfo object. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool GetAbilityInfo(const Want &want, const int userId, LauncherAbilityInfo &launcherAbilityInfo); + /** + * @brief Obtains the ApplicationInfo based on a given bundle name. + * @param bundleName Indicates the application bundle name to be queried. + * @param flag Indicates the flag used to specify information contained + * in the ApplicationInfo object that will be returned. + * @param userId Indicates the user ID. + * @param applicationInfo Indicates the obtained ApplicationInfo object. + * @return Returns true if the function is successfully called; returns false otherwise. + */ + virtual bool GetApplicationInfo(const std::string &bundleName, const ApplicationFlag &flags, const int userId, + ApplicationInfo &applicationInfo); + /** + * @brief Checks whether a bundle exists and is enabled. + * @param bundleName Indicates the bundle name. + * @return Returns true if the bundle is enabled; returns false otherwise. + */ + virtual bool IsBundleEnabled(const std::string &bundleName); + /** + * @brief Checks whether an ability exists and is enabled. + * @param abilityInfo Indicates information about the ability to check. + * @return Returns true if the ability exists and is enabled; returns false otherwise. + */ + virtual bool IsAbilityEnabled(const AbilityInfo &abilityInfo); + /** + * @brief Obtains information about the shortcuts of the application. + * @param bundleName Indicates the bundle name of the application. + * @param launcherShortcutInfo List of LauncherShortcutInfo objects if obtained. + * @return Returns true if the function is successfully called; returns false otherwise. + */ + virtual bool GetShortcutInfos(const std::string &bundleName, std::vector &launcherShortcutInfo); + +private: + void init(); + OHOS::sptr GetBundleMgr(); + + std::shared_ptr bundleMonitor_ = nullptr; + + DISALLOW_COPY_AND_MOVE(LauncherService); +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_LAUNCHER_SERVICE_H \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_core/include/formmgr/form_host_interface.h b/interfaces/innerkits/appexecfwk_core/include/formmgr/form_host_interface.h new file mode 100644 index 0000000000..07812871c5 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/formmgr/form_host_interface.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_HOST_INTERFACE_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_HOST_INTERFACE_H + +#include + +#include "form_js_info.h" +#include "ipc_types.h" +#include "iremote_broker.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @class IFormHost + * IFormHost interface is used to access form host service. + */ +class IFormHost : public OHOS::IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.appexecfwk.FormHost"); + + /** + * @brief Request to give back a Form. + * @param formInfo Form info. + */ + virtual void OnAcquired(const FormJsInfo &formInfo) = 0; + + /** + * @brief Form is updated. + * @param formInfo Form info. + */ + virtual void OnUpdate(const FormJsInfo &formInfo) = 0; + + /** + * @brief Form provider is uninstalled. + * @param formIds The Id list of the forms. + */ + virtual void OnUninstall(const std::vector &formIds) = 0; + + enum class Message { + // ipc id 1-1000 for kit + // ipc id 1001-2000 for DMS + // ipc id 2001-3000 for tools + // ipc id for create (3001) + FORM_HOST_ON_ACQUIRED = 3681, + + // ipc id for update (3682) + FORM_HOST_ON_UPDATE, + + // ipc id for uninstall (3683) + FORM_HOST_ON_UNINSTALL, + }; +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_HOST_INTERFACE_H diff --git a/interfaces/innerkits/appexecfwk_core/include/formmgr/form_host_proxy.h b/interfaces/innerkits/appexecfwk_core/include/formmgr/form_host_proxy.h new file mode 100644 index 0000000000..255fa5d39e --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/formmgr/form_host_proxy.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_HOST_PROXY_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_HOST_PROXY_H + +#include "app_log_wrapper.h" +#include "form_host_interface.h" +#include "iremote_proxy.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @class FormHostProxy + * Form host proxy is used to access form host service. + */ +class FormHostProxy : public IRemoteProxy { +public: + explicit FormHostProxy(const sptr &impl) : IRemoteProxy(impl) + {} + + virtual ~FormHostProxy() = default; + + /** + * @brief Request to give back a Form. + * @param formInfo Form info. + */ + virtual void OnAcquired(const FormJsInfo &formInfo) override; + + /** + * @brief Form is updated. + * @param formInfo Form info. + */ + virtual void OnUpdate(const FormJsInfo &formInfo) override; + + /** + * @brief Form provider is uninstalled. + * @param formIds The Id list of the forms. + */ + virtual void OnUninstall(const std::vector &formIds) override; + +private: + template + int GetParcelableInfos(MessageParcel &reply, std::vector &parcelableInfos); + bool WriteInterfaceToken(MessageParcel &data); + +private: + static inline BrokerDelegator delegator_; +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_HOST_PROXY_H diff --git a/interfaces/innerkits/appexecfwk_core/include/formmgr/form_host_stub.h b/interfaces/innerkits/appexecfwk_core/include/formmgr/form_host_stub.h new file mode 100644 index 0000000000..1c32be18be --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/formmgr/form_host_stub.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_HOST_STUB_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_HOST_STUB_H + +#include + +#include "form_host_interface.h" +#include "iremote_object.h" +#include "iremote_stub.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @class FormHostStub + * Form host service stub. + */ +class FormHostStub : public IRemoteStub { +public: + FormHostStub(); + virtual ~FormHostStub(); + /** + * @brief handle remote request. + * @param data input param. + * @param reply output param. + * @param option message option. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option); + +private: + /** + * @brief handle OnAcquired message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ + int HandleAcquired(MessageParcel &data, MessageParcel &reply); + /** + * @brief handle OnUpdate message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ + int HandleOnUpdate(MessageParcel &data, MessageParcel &reply); + /** + * @brief handle OnUnInstall message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ + int HandleOnUninstall(MessageParcel &data, MessageParcel &reply); +private: + using FormHostFunc = int32_t (FormHostStub::*)(MessageParcel &data, MessageParcel &reply); + std::map memberFuncMap_; + + DISALLOW_COPY_AND_MOVE(FormHostStub); +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_HOST_STUB_H diff --git a/interfaces/innerkits/appexecfwk_core/include/formmgr/form_mgr_interface.h b/interfaces/innerkits/appexecfwk_core/include/formmgr/form_mgr_interface.h new file mode 100644 index 0000000000..19b3d58e7d --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/formmgr/form_mgr_interface.h @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_MGR_INTERFACE_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_MGR_INTERFACE_H + +#include +#include "form_js_info.h" +#include "form_provider_data.h" +#include "ipc_types.h" +#include "iremote_broker.h" + +#include "want.h" + +namespace OHOS { +namespace AppExecFwk { +using OHOS::AAFwk::Want; + +/** + * @class IFormMgr + * IFormMgr interface is used to access form manager service. + */ +class IFormMgr : public OHOS::IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.appexecfwk.FormMgr") + + /** + * @brief Add form with want, send want to form manager service. + * @param formId The Id of the forms to add. + * @param want The want of the form to add. + * @param callerToken Caller ability token. + * @param formInfo Form info. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int AddForm(const int64_t formId, const Want &want, const sptr &callerToken, + FormJsInfo &formInfo) = 0; + + /** + * @brief Delete forms with formIds, send formIds to form manager service. + * @param formId The Id of the forms to delete. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int DeleteForm(const int64_t formId, const sptr &callerToken) = 0; + + /** + * @brief Release forms with formIds, send formIds to form manager service. + * @param formId The Id of the forms to release. + * @param callerToken Caller ability token. + * @param delCache Delete Cache or not. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int ReleaseForm(const int64_t formId, const sptr &callerToken, const bool delCache) = 0; + + /** + * @brief Update form with formId, send formId to form manager service. + * @param formId The Id of the form to update. + * @param bundleName Provider ability bundleName. + * @param formProviderData Form binding data. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int UpdateForm(const int64_t formId, const std::string &bundleName, + const FormProviderData &formProviderData) = 0; + + /** + * @brief Set next refresh time. + * @param formId The Id of the form to update. + * @param nextTime Next refresh time. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int SetNextRefreshTime(const int64_t formId, const int64_t nextTime) = 0; + + /** + * @brief Lifecycle update. + * @param formIds The Id of the forms. + * @param callerToken Caller ability token. + * @param updateType update type. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int LifecycleUpdate(const std::vector &formIds, const sptr &callerToken, + const int32_t updateType) = 0; + + /** + * @brief Request form with formId and want, send formId and want to form manager service. + * @param formId The Id of the form to request. + * @param callerToken Caller ability token. + * @param want The want of the form to add. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int RequestForm(const int64_t formId, const sptr &callerToken, const Want &want) = 0; + + /** + * @brief Form visible/invisible notify, send formIds to form manager service. + * @param formIds The Id list of the forms to notify. + * @param callerToken Caller ability token. + * @param formVisibleType The form visible type, including FORM_VISIBLE and FORM_INVISIBLE. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int NotifyWhetherVisibleForms(const std::vector &formIds, const sptr &callerToken, + const int32_t formVisibleType) = 0; + + /** + * @brief temp form to normal form. + * @param formId The Id of the form. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int CastTempForm(const int64_t formId, const sptr &callerToken) = 0; + + /** + * @brief Dump all of form storage infos. + * @param formInfos All of form storage infos. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int DumpStorageFormInfos(std::string &formInfos) = 0; + /** + * @brief Dump form info by a bundle name. + * @param bundleName The bundle name of form provider. + * @param formInfos Form infos. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int DumpFormInfoByBundleName(const std::string &bundleName, std::string &formInfos) = 0; + /** + * @brief Dump form info by a bundle name. + * @param formId The id of the form. + * @param formInfo Form info. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int DumpFormInfoByFormId(const std::int64_t formId, std::string &formInfo) = 0; + /** + * @brief Process js message event. + * @param formId Indicates the unique id of form. + * @param want information passed to supplier. + * @param callerToken Caller ability token. + * @return Returns true if execute success, false otherwise. + */ + virtual int MessageEvent(const int64_t formId, const Want &want, const sptr &callerToken) = 0; + + enum class Message { + // ipc id 1-1000 for kit + // ipc id 1001-2000 for DMS + // ipc id 2001-3000 for tools + // ipc id for create (3001) + FORM_MGR_ADD_FORM = 3001, + FORM_MGR_ADD_FORM_OHOS, + FORM_MGR_DELETE_FORM, + FORM_MGR_UPDATE_FORM, + FORM_MGR_LIFECYCLE_UPDATE, + FORM_MGR_REQUEST_FORM, + FORM_MGR_RELEASE_FORM, + FORM_MGR_RELEASE_CACHED_FORM, + FORM_MGR_CAST_TEMP_FORM, + FORM_MGR_EVENT_NOTIFY, + FORM_MGR_CHECK_AND_DELETE_INVALID_FORMS, + FORM_MGR_SET_NEXT_REFRESH_TIME, + FORM_MGR_ACQUIRE_FORM_STATE, + FORM_MGR_NOTIFY_FORM_WHETHER_VISIBLE, + FORM_MGR_STORAGE_FORM_INFOS, + FORM_MGR_FORM_INFOS_BY_NAME, + FORM_MGR_FORM_INFOS_BY_ID, + FORM_MGR_MESSAGE_EVENT, + }; +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_MGR_INTERFACE_H diff --git a/interfaces/innerkits/appexecfwk_core/include/formmgr/form_mgr_proxy.h b/interfaces/innerkits/appexecfwk_core/include/formmgr/form_mgr_proxy.h new file mode 100644 index 0000000000..576f077c00 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/formmgr/form_mgr_proxy.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_MGR_PROXY_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_MGR_PROXY_H + +#include "form_mgr_interface.h" +#include "iremote_proxy.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @class FormMgrProxy + * FormMgrProxy is used to access form manager service. + */ +class FormMgrProxy : public IRemoteProxy { +public: + explicit FormMgrProxy(const sptr &impl); + virtual ~FormMgrProxy() = default; + /** + * @brief Add form with want, send want to form manager service. + * @param formId The Id of the forms to add. + * @param want The want of the form to add. + * @param callerToken Caller ability token. + * @param formInfo Form info. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int AddForm(const int64_t formId, const Want &want, const sptr &callerToken, + FormJsInfo &formInfo) override; + + /** + * @brief Delete forms with formIds, send formIds to form manager service. + * @param formId The Id of the forms to delete. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int DeleteForm(const int64_t formId, const sptr &callerToken) override; + + /** + * @brief Release forms with formIds, send formIds to form manager service. + * @param formId The Id of the forms to release. + * @param callerToken Caller ability token. + * @param delCache Delete Cache or not. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int ReleaseForm(const int64_t formId, const sptr &callerToken, const bool delCache) override; + + /** + * @brief Update form with formId, send formId to form manager service. + * @param formId The Id of the form to update. + * @param bundleName Provider ability bundleName. + * @param FormProviderData Form binding data. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int UpdateForm(const int64_t formId, const std::string &bundleName, + const FormProviderData &FormProviderData) override; + + /** + * @brief Set next refresh time. + * @param formId The Id of the form to update. + * @param nextTime Next refresh time. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int SetNextRefreshTime(const int64_t formId, const int64_t nextTime) override; + + /** + * @brief Lifecycle update. + * @param formIds The Id of the forms. + * @param callerToken Caller ability token. + * @param updateType update type. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int LifecycleUpdate(const std::vector &formIds, const sptr &callerToken, + const int32_t updateType) override; + + /** + * @brief Request form with formId and want, send formId and want to form manager service. + * @param formId The Id of the form to update. + * @param callerToken Caller ability token. + * @param want The want of the form to add. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int RequestForm(const int64_t formId, const sptr &callerToken, const Want &want) override; + + /** + * @brief Form visible/invisible notify, send formIds to form manager service. + * @param formIds The Id list of the forms to notify. + * @param callerToken Caller ability token. + * @param formVisibleType The form visible type, including FORM_VISIBLE and FORM_INVISIBLE. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int NotifyWhetherVisibleForms(const std::vector &formIds, const sptr &callerToken, + const int32_t formVisibleType) override; + + /** + * @brief temp form to normal form. + * @param formId The Id of the form. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int CastTempForm(const int64_t formId, const sptr &callerToken) override; + + /** + * @brief Dump all of form storage infos. + * @param formInfos All of form storage infos. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int DumpStorageFormInfos(std::string &formInfos) override; + /** + * @brief Dump form info by a bundle name. + * @param bundleName The bundle name of form provider. + * @param formInfos Form infos. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int DumpFormInfoByBundleName(const std::string &bundleName, std::string &formInfos) override; + /** + * @brief Dump form info by a bundle name. + * @param formId The id of the form. + * @param formInfo Form info. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int DumpFormInfoByFormId(const std::int64_t formId, std::string &formInfo) override; + /** + * @brief Process js message event. + * @param formId Indicates the unique id of form. + * @param want information passed to supplier. + * @param callerToken Caller ability token. + * @return Returns true if execute success, false otherwise. + */ + virtual int MessageEvent(const int64_t formId, const Want &want, const sptr &callerToken) override; +private: + template + int GetParcelableInfos(MessageParcel &reply, std::vector &parcelableInfos); + bool WriteInterfaceToken(MessageParcel &data); + template + int GetParcelableInfo(IFormMgr::Message code, MessageParcel &data, T &parcelableInfo); + int SendTransactCmd(IFormMgr::Message code, MessageParcel &data, MessageParcel &reply); + int GetStringInfo(IFormMgr::Message code, MessageParcel &data, std::string &stringInfo); +private: + static inline BrokerDelegator delegator_; +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_MGR_PROXY_H diff --git a/interfaces/innerkits/appexecfwk_core/include/formmgr/form_mgr_stub.h b/interfaces/innerkits/appexecfwk_core/include/formmgr/form_mgr_stub.h new file mode 100644 index 0000000000..95467215c8 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/formmgr/form_mgr_stub.h @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_MGR_STUB_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_MGR_STUB_H + +#include + +#include "form_mgr_interface.h" +#include "iremote_object.h" +#include "iremote_stub.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @class FormMgrStub + * Form manager service stub. + */ +class FormMgrStub : public IRemoteStub { +public: + FormMgrStub(); + virtual ~FormMgrStub(); + /** + * @brief Handle remote request. + * @param data input param. + * @param reply output param. + * @param option message option. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option); + +private: + /** + * @brief Handle AddForm message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ + int32_t HandleAddForm(MessageParcel &data, MessageParcel &reply); + /** + * @brief Handle DeleteForm message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ + int32_t HandleDeleteForm(MessageParcel &data, MessageParcel &reply); + /** + * @brief Handle ReleaseForm message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ + int32_t HandleReleaseForm(MessageParcel &data, MessageParcel &reply); + /** + * @brief Handle UpdateForm message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ + int32_t HandleUpdateForm(MessageParcel &data, MessageParcel &reply); + + /** + * @brief handle LifecycleUpdate message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ + int32_t HandleLifecycleUpdate(MessageParcel &data, MessageParcel &reply); + /** + * @brief handle SetNextRefreshTime message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ + int32_t HandleSetNextRefreshTime(MessageParcel &data, MessageParcel &reply); + /** + * @brief Handle RequestForm message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ + int32_t HandleRequestForm(MessageParcel &data, MessageParcel &reply); + /** + * @brief Handle NotifyWhetherVisibleForms message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ + int32_t HandleNotifyWhetherVisibleForms(MessageParcel &data, MessageParcel &reply); + /** + * @brief Handle CastTempForm message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ + int32_t HandleCastTempForm(MessageParcel &data, MessageParcel &reply); + /** + * @brief Handle DumpStorageFormInfos message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ + int32_t HandleDumpStorageFormInfos(MessageParcel &data, MessageParcel &reply); + /** + * @brief Handle DumpFormInfoByBundleName message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ + int32_t HandleDumpFormInfoByBundleName(MessageParcel &data, MessageParcel &reply); + /** + * @brief Handle DumpFormInfoByFormId message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ + int32_t HandleDumpFormInfoByFormId(MessageParcel &data, MessageParcel &reply); + /** + * @brief Handle DumpFormInfoByFormId message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ + int32_t HandleMessageEvent(MessageParcel &data, MessageParcel &reply); + +private: + using FormMgrFunc = int32_t (FormMgrStub::*)(MessageParcel &data, MessageParcel &reply); + std::map memberFuncMap_; + + DISALLOW_COPY_AND_MOVE(FormMgrStub); +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_MGR_STUB_H diff --git a/interfaces/innerkits/appexecfwk_core/include/formmgr/form_provider_interface.h b/interfaces/innerkits/appexecfwk_core/include/formmgr/form_provider_interface.h new file mode 100644 index 0000000000..425ad1673f --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/formmgr/form_provider_interface.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_PROVIDER_INTERFACE_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_PROVIDER_INTERFACE_H + +#include + +#include "ipc_types.h" +#include "iremote_broker.h" +#include "want.h" + +namespace OHOS { +namespace AppExecFwk { +using OHOS::AAFwk::Want; +/** + * @class IFormProvider + * IFormProvider interface is used to access form provider service. + */ +class IFormProvider : public OHOS::IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.appexecfwk.FormProvider"); + + /** + * @brief Acquire to give back an ProviderFormInfo. This is sync API. + * @param formId The Id of the from. + * @param want Indicates the {@link Want} structure containing form info. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int AcquireProviderFormInfo(const int64_t formId, const Want &want, + const sptr &callerToken) = 0; + + /** + * @brief Notify provider when the form was deleted. + * @param formId The Id of the form. + * @param want Indicates the structure containing form info. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int NotifyFormDelete(const int64_t formId, const Want &want, const sptr &callerToken) = 0; + + /** + * @brief Notify provider when the forms was deleted. + * @param formIds The id list of forms. + * @param want Indicates the structure containing form info. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int NotifyFormsDelete(const std::vector &formIds, const Want &want, + const sptr &callerToken) = 0; + /** + * @brief Notify provider when the form need update. + * @param formId The Id of the form. + * @param want Indicates the structure containing form info. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int NotifyFormUpdate(const int64_t formId, const Want &want, const sptr &callerToken) = 0; + + /** + * @brief Event notify when change the form visible. + * + * @param formIds The vector of form ids. + * @param formVisibleType The form visible type, including FORM_VISIBLE and FORM_INVISIBLE. + * @param want Indicates the structure containing form info. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int EventNotify(const std::vector &formIds, const int32_t formVisibleType, + const Want &want, const sptr &callerToken) = 0; + + /** + * @brief Notify provider when the temp form was cast to normal form. + * @param formId The Id of the form to update. + * @param want Indicates the structure containing form info. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int NotifyFormCastTempForm(const int64_t formId, const Want &want, + const sptr &callerToken) = 0; + + /** + * @brief Fire message event to form provider. + * @param formId The Id of the from. + * @param message Event message. + * @param want The want of the request. + * @param callerToken Form provider proxy object. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int FireFormEvent(const int64_t formId, const std::string &message, const Want &want, + const sptr &callerToken) = 0; + + enum class Message { + // ipc id 1-1000 for kit + // ipc id 1001-2000 for DMS + // ipc id 2001-3000 for tools + // ipc id for add form (3001) + FORM_ACQUIRE_PROVIDER_FORM_INFO = 3051, + + // ipc id for delete form (3052) + FORM_PROVIDER_NOTIFY_FORM_DELETE, + + // ipc id for form done release form (3053) + FORM_PROVIDER_NOTIFY_FORMS_DELETE, + + // ipc id for connecting update form (3054) + FORM_PROVIDER_NOTIFY_FORM_UPDATE, + + // ipc id for form visible notify (3055) + FORM_PROVIDER_NOTIFY_TEMP_FORM_CAST, + + // ipc id for event notify (3056) + FORM_PROVIDER_EVENT_NOTIFY, + + // ipc id for event notify (3057) + FORM_PROVIDER_EVENT_MESSAGE, + }; +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_PROVIDER_INTERFACE_H diff --git a/interfaces/innerkits/appexecfwk_core/include/formmgr/form_provider_proxy.h b/interfaces/innerkits/appexecfwk_core/include/formmgr/form_provider_proxy.h new file mode 100644 index 0000000000..4344d59b58 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/formmgr/form_provider_proxy.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_PROVIDER_PROXY_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_PROVIDER_PROXY_H + +#include "app_log_wrapper.h" +#include "form_provider_interface.h" +#include "iremote_proxy.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @class FormProviderProxy + * FormProviderProxy is used to access form provider service. + */ +class FormProviderProxy : public IRemoteProxy { +public: + explicit FormProviderProxy(const sptr &impl) : IRemoteProxy(impl) + {} + + virtual ~FormProviderProxy() = default; + + /** + * @brief Acquire to give back an ProviderFormInfo. This is sync API. + * @param formId The Id of the from. + * @param want Indicates the {@link Want} structure containing form info. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int AcquireProviderFormInfo(const int64_t formId, const Want &want, + const sptr &callerToken) override; + + /** + * @brief Notify provider when the form was deleted. + * @param formId The Id of the form. + * @param want Indicates the structure containing form info. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int NotifyFormDelete(const int64_t formId, const Want &want, + const sptr &callerToken) override; + + /** + * @brief Notify provider when the forms was deleted. + * @param formIds The id list of forms. + * @param want Indicates the structure containing form info. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int NotifyFormsDelete(const std::vector &formIds, const Want &want, + const sptr &callerToken) override; + + /** + * @brief Notify provider when the form need update. + * @param formId The Id of the form. + * @param want Indicates the structure containing form info. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int NotifyFormUpdate(const int64_t formId, const Want &want, + const sptr &callerToken) override; + + /** + * @brief Event notify when change the form visible. + * + * @param formIds The vector of form ids. + * @param formVisibleType The form visible type, including FORM_VISIBLE and FORM_INVISIBLE. + * @param want Indicates the structure containing form info. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int EventNotify(const std::vector &formIds, const int32_t formVisibleType, + const Want &want, const sptr &callerToken) override; + + /** + * @brief Notify provider when the temp form was cast to normal form. + * @param formId The Id of the form to update. + * @param want Indicates the structure containing form info. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int NotifyFormCastTempForm(const int64_t formId, const Want &want, + const sptr &callerToken) override; + /** + * @brief Fire message event to form provider. + * @param formId The Id of the from. + * @param message Event message. + * @param want The want of the request. + * @param callerToken Form provider proxy object. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int FireFormEvent(const int64_t formId, const std::string &message, const Want &want, + const sptr &callerToken) override; + +private: + template + int GetParcelableInfos(MessageParcel &reply, std::vector &parcelableInfos); + bool WriteInterfaceToken(MessageParcel &data); + +private: + static inline BrokerDelegator delegator_; +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_PROVIDER_PROXY_H diff --git a/interfaces/innerkits/appexecfwk_core/include/formmgr/form_provider_stub.h b/interfaces/innerkits/appexecfwk_core/include/formmgr/form_provider_stub.h new file mode 100644 index 0000000000..5c0751e96d --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/formmgr/form_provider_stub.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_PROVIDER_STUB_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_PROVIDER_STUB_H + +#include + +#include "form_provider_interface.h" +#include "iremote_object.h" +#include "iremote_stub.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @class FormProviderStub + * form provider service stub. + */ +class FormProviderStub : public IRemoteStub { +public: + FormProviderStub(); + virtual ~FormProviderStub(); + /** + * @brief handle remote request. + * @param data input param. + * @param reply output param. + * @param option message option. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option); + +private: + /** + * @brief handle AcquireProviderFormInfo message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ + int HandleAcquireProviderFormInfo(MessageParcel &data, MessageParcel &reply); + /** + * @brief handle NotifyFormDelete message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ + int HandleNotifyFormDelete(MessageParcel &data, MessageParcel &reply); + /** + * @brief handle NotifyFormsDelete message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ + int HandleNotifyFormsDelete(MessageParcel &data, MessageParcel &reply); + /** + * @brief handle NotifyFormUpdate message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ + int HandleNotifyFormUpdate(MessageParcel &data, MessageParcel &reply); + + /** + * @brief handle EventNotify message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ + int HandleEventNotify(MessageParcel &data, MessageParcel &reply); + + /** + * @brief handle NotifyFormCastTempForm message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ + int HandleNotifyFormCastTempForm(MessageParcel &data, MessageParcel &reply); + /** + * @brief handle NotifyFormCastTempForm message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ + int HandleFireFormEvent(MessageParcel &data, MessageParcel &reply); +private: + using FormProviderFunc = int32_t (FormProviderStub::*)(MessageParcel &data, MessageParcel &reply); + std::map memberFuncMap_; + + DISALLOW_COPY_AND_MOVE(FormProviderStub); +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_PROVIDER_STUB_H diff --git a/interfaces/innerkits/appexecfwk_core/include/formmgr/form_supply_interface.h b/interfaces/innerkits/appexecfwk_core/include/formmgr/form_supply_interface.h new file mode 100644 index 0000000000..93b634717d --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/formmgr/form_supply_interface.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_SUPPLY_INTERFACE_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_SUPPLY_INTERFACE_H + +#include + +#include "form_provider_info.h" +#include "ipc_types.h" +#include "iremote_broker.h" + +#include "want.h" + +namespace OHOS { +namespace AppExecFwk { +using OHOS::AAFwk::Want; + +/** + * @class IFormSupply + * IFormSupply interface is used to access form supply service. + */ +class IFormSupply : public OHOS::IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.appexecfwk.FormSupply"); + + /** + * @brief Accept form binding data from form provider. + * @param providerFormInfo Form binding data. + * @param want input data. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int OnAcquire(const FormProviderInfo &formInfo, const Want &want) = 0; + + /** + * @brief Accept other event. + * @param want input data. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int OnEventHandle(const Want &want) = 0; + + enum class Message { + // ipc id 1-1000 for kit + // ipc id 1001-2000 for DMS + // ipc id 2001-3000 for tools + // ipc id for create (3201) + TRANSACTION_FORM_ACQUIRED = 3201, + TRANSACTION_EVENT_HANDLE, + }; +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_SUPPLY_INTERFACE_H diff --git a/interfaces/innerkits/appexecfwk_core/include/formmgr/form_supply_proxy.h b/interfaces/innerkits/appexecfwk_core/include/formmgr/form_supply_proxy.h new file mode 100644 index 0000000000..095130a673 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/formmgr/form_supply_proxy.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_SUPPLY_PROXY_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_SUPPLY_PROXY_H + +#include "app_log_wrapper.h" +#include "form_supply_interface.h" +#include "iremote_proxy.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @class FormSupplyProxy + * FormSupplyProxy is used to access form supply service. + */ +class FormSupplyProxy : public IRemoteProxy { +public: + explicit FormSupplyProxy(const sptr &impl) : IRemoteProxy(impl) + {} + + virtual ~FormSupplyProxy() = default; + + /** + * @brief Send form binding data from form provider to fms. + * @param providerFormInfo Form binding data. + * @param want input data. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int OnAcquire(const FormProviderInfo &formInfo, const Want &want) override; + + /** + * @brief Send other event to fms. + * @param want input data. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int OnEventHandle(const Want &want) override; + +private: + template + int GetParcelableInfos(MessageParcel &reply, std::vector &parcelableInfos); + bool WriteInterfaceToken(MessageParcel &data); + +private: + static inline BrokerDelegator delegator_; +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_SUPPLY_PROXY_H diff --git a/interfaces/innerkits/appexecfwk_core/include/formmgr/form_supply_stub.h b/interfaces/innerkits/appexecfwk_core/include/formmgr/form_supply_stub.h new file mode 100644 index 0000000000..796012eb14 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/formmgr/form_supply_stub.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_SUPPLY_STUP_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_SUPPLY_STUP_H + +#include +#include "form_supply_interface.h" +#include "iremote_object.h" +#include "iremote_stub.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @class FormSupplyStub + * form supply service stub. + */ +class FormSupplyStub : public IRemoteStub { +public: + FormSupplyStub(); + virtual ~FormSupplyStub(); + /** + * @brief handle remote request. + * @param data input param. + * @param reply output param. + * @param option message option. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option); + +private: + /** + * @brief handle OnAcquire message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ + int HandleOnAcquire(MessageParcel &data, MessageParcel &reply); + /** + * @brief handle OnEventHandle message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ + int HandleOnEventHandle(MessageParcel &data, MessageParcel &reply); +private: + using FormSupplyFunc = int32_t (FormSupplyStub::*)(MessageParcel &data, MessageParcel &reply); + std::map memberFuncMap_; + + DISALLOW_COPY_AND_MOVE(FormSupplyStub); +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_FORM_SUPPLY_STUP_H diff --git a/interfaces/innerkits/appexecfwk_core/include/formmgr/provider_connect_proxy.h b/interfaces/innerkits/appexecfwk_core/include/formmgr/provider_connect_proxy.h new file mode 100644 index 0000000000..194c8804b3 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/formmgr/provider_connect_proxy.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_PROVIDER_CONNECT_PROXY_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_PROVIDER_CONNECT_PROXY_H + +#include "ability_connect_callback_interface.h" +#include "iremote_proxy.h" + +namespace OHOS { +namespace AppExecFwk { +using IAbilityConnection = OHOS::AAFwk::IAbilityConnection; + +/** + * @class ProviderConnectProxy + * Provider connect proxy is used to connect form ability service. + */ +class ProviderConnectProxy : public IRemoteProxy { +public: + explicit ProviderConnectProxy(const sptr &impl) : IRemoteProxy(impl) + {} + + virtual ~ProviderConnectProxy() = default; + + /** + * @brief OnAbilityConnectDone, AbilityMs notify caller ability the result of connect. + * @param element service ability's ElementName. + * @param remoteObject the session proxy of service ability. + * @param resultCode ERR_OK on success, others on failure. + */ + virtual void OnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) override; + + /** + * @brief OnAbilityDisconnectDone, AbilityMs notify caller ability the result of disconnect. + * @param element service ability's ElementName. + * @param resultCode ERR_OK on success, others on failure. + */ + virtual void OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode) override; + +private: + bool WriteInterfaceToken(MessageParcel &data); + +private: + static inline BrokerDelegator delegator_; +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_PROVIDER_CONNECT_PROXY_H \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_core/include/formmgr/provider_connect_stub.h b/interfaces/innerkits/appexecfwk_core/include/formmgr/provider_connect_stub.h new file mode 100644 index 0000000000..c8f52b8eea --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/formmgr/provider_connect_stub.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_PROVIDER_CONNECT_STUB_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_PROVIDER_CONNECT_STUB_H + +#include "ability_connect_callback_interface.h" +#include "iremote_object.h" +#include "iremote_stub.h" +#include "nocopyable.h" + +namespace OHOS { +namespace AppExecFwk { +using IAbilityConnection = OHOS::AAFwk::IAbilityConnection; + +/** + * @class ProviderConnectStub + * Form ability service stub. + */ +class ProviderConnectStub : public IRemoteStub { +public: + ProviderConnectStub() = default; + virtual ~ProviderConnectStub() = default; + /** + * @brief handle remote request. + * @param data input param. + * @param reply output param. + * @param option message option. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + +private: + DISALLOW_COPY_AND_MOVE(ProviderConnectStub); +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_FORMMGR_PROVIDER_CONNECT_STUB_H diff --git a/interfaces/innerkits/appexecfwk_core/src/appmgr/app_process_data.cpp b/interfaces/innerkits/appexecfwk_core/src/appmgr/app_process_data.cpp index dfb3cc85db..4f3c27071d 100644 --- a/interfaces/innerkits/appexecfwk_core/src/appmgr/app_process_data.cpp +++ b/interfaces/innerkits/appexecfwk_core/src/appmgr/app_process_data.cpp @@ -23,7 +23,7 @@ namespace AppExecFwk { bool AppProcessData::Marshalling(Parcel &parcel) const { return (parcel.WriteString(appName) && parcel.WriteString(processName) && - parcel.WriteInt32(static_cast(appState)) && parcel.WriteInt32(pid)); + parcel.WriteInt32(static_cast(appState)) && parcel.WriteInt32(pid) && parcel.WriteInt32(uid)); } bool AppProcessData::ReadFromParcel(Parcel &parcel) @@ -36,6 +36,8 @@ bool AppProcessData::ReadFromParcel(Parcel &parcel) pid = parcel.ReadInt32(); + uid = parcel.ReadInt32(); + return true; } diff --git a/interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_mgr_host.cpp b/interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_mgr_host.cpp index 4a4ae766db..f1fb6a7eb1 100755 --- a/interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_mgr_host.cpp +++ b/interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_mgr_host.cpp @@ -86,6 +86,9 @@ int BundleMgrHost::OnRemoteRequest(uint32_t code, MessageParcel &data, MessagePa case static_cast(IBundleMgr::Message::QUERY_ABILITY_INFO): errCode = HandleQueryAbilityInfo(data, reply); break; + case static_cast(IBundleMgr::Message::QUERY_ABILITY_INFOS): + errCode = HandleQueryAbilityInfos(data, reply); + break; case static_cast(IBundleMgr::Message::QUERY_ABILITY_INFO_BY_URI): errCode = HandleQueryAbilityInfoByUri(data, reply); break; @@ -194,6 +197,12 @@ int BundleMgrHost::OnRemoteRequest(uint32_t code, MessageParcel &data, MessagePa case static_cast(IBundleMgr::Message::GET_SHORTCUT_INFO): errCode = HandleGetShortcutInfos(data, reply); break; + case static_cast(IBundleMgr::Message::GET_MODULE_USAGE_RECORD): + errCode = HandleGetModuleUsageRecords(data, reply); + break; + case static_cast(IBundleMgr::Message::NOTIFY_ACTIVITY_LIFE_STATUS): + errCode = HandleNotifyActivityLifeStatus(data, reply); + break; default: return IPCObjectStub::OnRemoteRequest(code, data, reply, option); } @@ -432,6 +441,29 @@ ErrCode BundleMgrHost::HandleQueryAbilityInfo(Parcel &data, Parcel &reply) return ERR_OK; } +ErrCode BundleMgrHost::HandleQueryAbilityInfos(Parcel &data, Parcel &reply) +{ + std::unique_ptr want(data.ReadParcelable()); + if (!want) { + APP_LOGE("ReadParcelable failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + std::vector abilityInfos; + bool ret = QueryAbilityInfos(*want, abilityInfos); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (ret) { + if (!WriteParcelableVector(abilityInfos, reply)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + } + return ERR_OK; +} + ErrCode BundleMgrHost::HandleQueryAbilityInfoByUri(Parcel &data, Parcel &reply) { std::string abilityUri = data.ReadString(); @@ -1022,7 +1054,51 @@ ErrCode BundleMgrHost::HandleGetShortcutInfos(Parcel &data, Parcel &reply) return ERR_OK; } -template +ErrCode BundleMgrHost::HandleGetModuleUsageRecords(Parcel &data, Parcel &reply) +{ + int32_t number = data.ReadInt32(); + std::vector records; + bool ret = GetModuleUsageRecords(number, records); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + if (ret) { + if (!WriteParcelableVector(records, reply)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleNotifyActivityLifeStatus(Parcel &data, Parcel &reply) +{ + std::string bundleName = data.ReadString(); + std::string abilityName = data.ReadString(); + int64_t launchTime = data.ReadInt64(); +#if __WORDSIZE == 64 + APP_LOGI("bundleName %{public}s, abilityName %{public}s, launchTime %{public}ld", + bundleName.c_str(), + abilityName.c_str(), + launchTime); +#else + APP_LOGI("bundleName %{public}s, abilityName %{public}s, launchTime %{public}lld", + bundleName.c_str(), + abilityName.c_str(), + launchTime); +#endif + + bool ret = NotifyActivityLifeStatus(bundleName, abilityName, launchTime); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + return ERR_OK; +} + +template bool BundleMgrHost::WriteParcelableVector(std::vector &parcelableVector, Parcel &reply) { if (!reply.WriteInt32(parcelableVector.size())) { diff --git a/interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_mgr_proxy.cpp b/interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_mgr_proxy.cpp index a80f71e9da..52b27df27b 100644 --- a/interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_mgr_proxy.cpp +++ b/interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_mgr_proxy.cpp @@ -367,6 +367,25 @@ bool BundleMgrProxy::QueryAbilityInfo(const Want &want, AbilityInfo &abilityInfo return true; } +bool BundleMgrProxy::QueryAbilityInfos(const Want &want, std::vector &abilityInfos) +{ + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to QueryAbilityInfo due to write MessageParcel fail"); + return false; + } + if (!data.WriteParcelable(&want)) { + APP_LOGE("fail to QueryAbilityInfo due to write want fail"); + return false; + } + + if (!GetParcelableInfos(IBundleMgr::Message::QUERY_ABILITY_INFOS, data, abilityInfos)) { + APP_LOGE("fail to QueryAbilityInfos from server"); + return false; + } + return true; +} + bool BundleMgrProxy::QueryAbilityInfoByUri(const std::string &abilityUri, AbilityInfo &abilityInfo) { MessageParcel data; @@ -1104,7 +1123,7 @@ bool BundleMgrProxy::RequestPermissionFromUser( } MessageParcel reply; - if (!SendTransactCmd(IBundleMgr::Message::CAN_REQUEST_PERMISSION, data, reply)) { + if (!SendTransactCmd(IBundleMgr::Message::REQUEST_PERMISSION_FROM_USER, data, reply)) { APP_LOGE("fail to RequestPermissionsFromUser from server"); return false; } @@ -1288,6 +1307,62 @@ bool BundleMgrProxy::GetShortcutInfos(const std::string &bundleName, std::vector return true; } +bool BundleMgrProxy::GetModuleUsageRecords(const int32_t number, std::vector &moduleUsageRecords) +{ + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to GetModuleUsageRecords due to write MessageParcel fail"); + return false; + } + + if (!data.WriteInt32(number)) { + APP_LOGE("fail to GetModuleUsageRecords due to write number fail"); + return false; + } + + if (!GetParcelableInfos(IBundleMgr::Message::GET_MODULE_USAGE_RECORD, data, moduleUsageRecords)) { + APP_LOGE("fail to GetModuleUsageRecords from server"); + return false; + } + return true; +} + +bool BundleMgrProxy::NotifyActivityLifeStatus( + const std::string &bundleName, const std::string &abilityName, const int64_t launchTime) +{ + APP_LOGI("begin to NotifyActivityLifeStatus of %{public}s", abilityName.c_str()); + if (bundleName.empty() || abilityName.empty()) { + APP_LOGE("fail to NotifyActivityLifeStatus due to params empty"); + return false; + } + + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to NotifyActivityLifeStatus due to write InterfaceToken fail"); + return false; + } + if (!data.WriteString(bundleName)) { + APP_LOGE("fail to NotifyActivityLifeStatus due to write bundleName fail"); + return false; + } + if (!data.WriteString(abilityName)) { + APP_LOGE("fail to NotifyActivityLifeStatus due to write abilityName fail"); + return false; + } + if (!data.WriteInt64(launchTime)) { + APP_LOGE("fail to NotifyActivityLifeStatus due to write launchTime fail"); + return false; + } + + MessageParcel reply; + if (!SendTransactCmd(IBundleMgr::Message::NOTIFY_ACTIVITY_LIFE_STATUS, data, reply)) { + APP_LOGE("fail to NotifyActivityLifeStatus from server"); + return false; + } + return reply.ReadBool(); + +} + template bool BundleMgrProxy::GetParcelableInfo(IBundleMgr::Message code, MessageParcel &data, T &parcelableInfo) { diff --git a/interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_monitor.cpp b/interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_monitor.cpp new file mode 100644 index 0000000000..543ac97fb4 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_monitor.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2021 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 "bundle_monitor.h" + +namespace OHOS { +namespace AppExecFwk { + +BundleMonitor::BundleMonitor(const EventFwk::CommonEventSubscribeInfo &subscribeInfo) + : EventFwk::CommonEventSubscriber(subscribeInfo) +{ + APP_LOGI("BundleMonitor constructor with subscribeInfo"); +} + +bool BundleMonitor::Subscribe(const sptr &callback) +{ + APP_LOGI("Subscribe called"); + callback_ = callback; + + if (EventFwk::CommonEventManager::SubscribeCommonEvent(shared_from_this()) != true) { + APP_LOGE("SubscribeCommonEvent occur exception."); + return false; + } + return true; +} + +bool BundleMonitor::UnSubscribe() +{ + APP_LOGI("unsubscribe called"); + if (EventFwk::CommonEventManager::UnSubscribeCommonEvent(shared_from_this()) != true) { + APP_LOGE("UnsubscribeCommonEvent occur exception."); + return false; + } + return true; +} + +void BundleMonitor::OnReceiveEvent(const EventFwk::CommonEventData &eventData) +{ + APP_LOGI("OnReceiveEvent common event onReceiveEvent called"); + Want want = eventData.GetWant(); + std::string action = want.GetAction(); + std::string bundleName = want.GetElement().GetBundleName(); + int userId = want.GetIntParam(USER_ID, Constants::INVALID_USERID); + APP_LOGI("OnReceiveEvent action = %{public}s, bundle = %{public}s", action.c_str(), bundleName.c_str()); + if ((action == EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_ADDED) && (callback_ != nullptr)) { + callback_->OnBundleAdded(bundleName, userId); + } else if ((action == EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_CHANGED) && (callback_ != nullptr)) { + callback_->OnBundleUpdated(bundleName, userId); + } else if ((action == EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_REMOVED) && (callback_ != nullptr)) { + callback_->OnBundleRemoved(bundleName, userId); + } else { + APP_LOGI("OnReceiveEvent action = %{public}s not support", action.c_str()); + } +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_core/src/bundlemgr/launcher_service.cpp b/interfaces/innerkits/appexecfwk_core/src/bundlemgr/launcher_service.cpp new file mode 100644 index 0000000000..16753cb5a2 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/bundlemgr/launcher_service.cpp @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2021 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 "launcher_service.h" + +#include "matching_skills.h" +#include "common_event_support.h" +#include "common_event_subscribe_info.h" +#include "operation_builder.h" + +namespace OHOS { +namespace AppExecFwk { + +LauncherService::LauncherService() +{ + init(); +} + +void LauncherService::init() +{ + EventFwk::MatchingSkills matchingSkills; + matchingSkills.AddEvent(EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_ADDED); + matchingSkills.AddEvent(EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_CHANGED); + matchingSkills.AddEvent(EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_REMOVED); + EventFwk::CommonEventSubscribeInfo subscribeInfo(matchingSkills); + bundleMonitor_ = std::make_shared(subscribeInfo); +} + +OHOS::sptr LauncherService::GetBundleMgr() +{ + OHOS::sptr systemAbilityManager = + OHOS::SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + OHOS::sptr remoteObject = + systemAbilityManager->GetSystemAbility(OHOS::BUNDLE_MGR_SERVICE_SYS_ABILITY_ID); + return OHOS::iface_cast(remoteObject); +} + +bool LauncherService::RegisterCallback(const sptr &callback) +{ + APP_LOGI("RegisterCallback called"); + if (bundleMonitor_ == nullptr) { + APP_LOGE("failed to register callback, bundleMonitor is null"); + return false; + } + + return bundleMonitor_->Subscribe(callback); +} + +bool LauncherService::UnRegisterCallback() +{ + APP_LOGI("UnRegisterCallback called"); + if (bundleMonitor_ == nullptr) { + APP_LOGE("failed to unregister callback, bundleMonitor is null"); + return false; + } + + return bundleMonitor_->UnSubscribe(); +} + +bool LauncherService::GetAbilityList( + const std::string &bundleName, const int userId, std::vector &launcherAbilityInfos) +{ + APP_LOGI("GetAbilityList called"); + auto iBundleMgr = GetBundleMgr(); + if (!iBundleMgr) { + APP_LOGE("can not get iBundleMgr"); + return false; + } + + std::vector entities; + entities.push_back(Want::ENTITY_HOME); + Want want; + OHOS::AAFwk::OperationBuilder opBuilder; + auto operation = opBuilder.WithAction(Want::ACTION_HOME).WithEntities(entities).build(); + want.SetOperation(*operation); + ElementName elementName; + elementName.SetBundleName(bundleName); + want.SetElement(elementName); + std::vector abilityInfo; + if (!iBundleMgr->QueryAbilityInfos(want, abilityInfo)) { + APP_LOGE("Query ability info failed"); + return false; + } + + std::string icon = ""; + ApplicationInfo appInfo; + ApplicationFlag flag = ApplicationFlag::GET_BASIC_APPLICATION_INFO; + if (!iBundleMgr->GetApplicationInfo(bundleName, flag, Constants::DEFAULT_USERID, appInfo)) { + APP_LOGE("Get application info failed"); + return false; + } + icon = appInfo.iconId; + + int64_t installTime = 0; + BundleFlag flags; + flags = BundleFlag::GET_BUNDLE_WITH_ABILITIES; + BundleInfo bundleInfo; + if (!iBundleMgr->GetBundleInfo(bundleName, flags, bundleInfo)) { + APP_LOGE("Get bundle info failed"); + return false; + } + installTime = bundleInfo.installTime; + + for (auto &ability : abilityInfo) { + LauncherAbilityInfo info; + info.name = ability.name; + info.applicationInfo = ability.applicationInfo; + info.label = ability.label; + ElementName elementName; + elementName.SetBundleName(ability.bundleName); + elementName.SetAbilityName(ability.name); + elementName.SetDeviceID(ability.deviceId); + info.elementname = elementName; + info.icon = icon; + info.userid = userId; + info.installTime = installTime; + launcherAbilityInfos.emplace_back(info); + } + + return true; +} + +bool LauncherService::GetAbilityInfo(const Want &want, const int userId, LauncherAbilityInfo &launcherAbilityInfo) +{ + APP_LOGI("GetAbilityInfo called"); + auto iBundleMgr = GetBundleMgr(); + if (!iBundleMgr) { + APP_LOGE("can not get iBundleMgr"); + return false; + } + ElementName element = want.GetElement(); + if (element.GetBundleName().empty() || element.GetAbilityName().empty()) { + APP_LOGE("GetAbilityInfo elementName is empty"); + return false; + } + AbilityInfo abilityInfo; + if (!iBundleMgr->QueryAbilityInfo(want, abilityInfo)) { + APP_LOGE("Query AbilityInfo failed"); + return false; + } + + std::string bundleName = element.GetBundleName(); + std::string icon = ""; + ApplicationInfo appInfo; + ApplicationFlag flag = ApplicationFlag::GET_BASIC_APPLICATION_INFO; + if (!iBundleMgr->GetApplicationInfo(bundleName, flag, Constants::DEFAULT_USERID, appInfo)) { + APP_LOGE("Get application info failed"); + return false; + } + icon = appInfo.iconId; + + int64_t installTime = 0; + BundleFlag flags; + flags = BundleFlag::GET_BUNDLE_WITH_ABILITIES; + BundleInfo bundleInfo; + if (!iBundleMgr->GetBundleInfo(bundleName, flags, bundleInfo)) { + APP_LOGE("Get bundle info failed"); + return false; + } + installTime = bundleInfo.installTime; + + LauncherAbilityInfo info; + info.name = abilityInfo.name; + info.applicationInfo = abilityInfo.applicationInfo; + info.label = abilityInfo.label; + ElementName elementName; + elementName.SetBundleName(abilityInfo.bundleName); + elementName.SetAbilityName(abilityInfo.name); + elementName.SetDeviceID(abilityInfo.deviceId); + info.elementname = elementName; + info.icon = icon; + info.userid = userId; + info.installTime = installTime; + launcherAbilityInfo = info; + + return true; +} + +bool LauncherService::GetApplicationInfo( + const std::string &bundleName, const ApplicationFlag &flags, const int userId, ApplicationInfo &applicationInfo) +{ + APP_LOGI("GetApplicationInfo called"); + auto iBundleMgr = GetBundleMgr(); + if (!iBundleMgr) { + APP_LOGE("can not get iBundleMgr"); + return false; + } + if (bundleName.empty()) { + APP_LOGE("GetApplicationInfo bundleName is empty"); + return false; + } + + if (!iBundleMgr->GetApplicationInfo(bundleName, flags, userId, applicationInfo)) { + APP_LOGE("Get application info failed"); + return false; + } + + return true; +} + +bool LauncherService::IsBundleEnabled(const std::string &bundleName) +{ + APP_LOGI("IsBundleEnabled called"); + auto iBundleMgr = GetBundleMgr(); + if (!iBundleMgr) { + APP_LOGE("can not get iBundleMgr"); + return false; + } + if (bundleName.empty()) { + APP_LOGE("bundleName is empty"); + return false; + } + + return iBundleMgr->IsApplicationEnabled(bundleName); +} + +bool LauncherService::IsAbilityEnabled(const AbilityInfo &abilityInfo) +{ + APP_LOGI("IsAbilityEnabled called"); + auto iBundleMgr = GetBundleMgr(); + if (!iBundleMgr) { + APP_LOGE("can not get iBundleMgr"); + return false; + } + + return iBundleMgr->IsAbilityEnabled(abilityInfo); +} + +bool LauncherService::GetShortcutInfos( + const std::string &bundleName, std::vector &launcherShortcutInfo) +{ + APP_LOGI("GetShortcutInfos called"); + if (bundleName.empty()) { + APP_LOGE("bundleName is empty"); + return false; + } + auto iBundleMgr = GetBundleMgr(); + if (!iBundleMgr) { + APP_LOGE("can not get iBundleMgr"); + return false; + } + + std::vector infos; + if (!iBundleMgr->GetShortcutInfos(bundleName, infos)) { + APP_LOGE("Get shortcut infos failed"); + return false; + } + if (infos.size() == 0) { + APP_LOGE("ShortcutInfo is not exist in system"); + return false; + } + + for (ShortcutInfo shortcutInfo : infos) { + if (bundleName == shortcutInfo.bundleName) { + LauncherShortcutInfo launchershortcutinfo; + launchershortcutinfo.bundleName = shortcutInfo.bundleName; + launchershortcutinfo.icon = shortcutInfo.icon; + launchershortcutinfo.intents = shortcutInfo.intents; + launchershortcutinfo.label = shortcutInfo.label; + launchershortcutinfo.shortcutid = shortcutInfo.id; + launcherShortcutInfo.emplace_back(launchershortcutinfo); + } + } + return true; +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_core/src/formmgr/form_host_proxy.cpp b/interfaces/innerkits/appexecfwk_core/src/formmgr/form_host_proxy.cpp new file mode 100644 index 0000000000..c414aa5329 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/formmgr/form_host_proxy.cpp @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2021 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 "appexecfwk_errors.h" +#include "form_host_proxy.h" +#include "string_ex.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @brief Request to give back a Form. + * @param formInfo Form info. + */ +void FormHostProxy::OnAcquired(const FormJsInfo &formInfo) +{ + int error; + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!WriteInterfaceToken(data)) { + APP_LOGE("%{public}s, failed to write interface token", __func__); + } + + if (!data.WriteParcelable(&formInfo)) { + APP_LOGE("%{public}s, failed to write formInfo", __func__); + } + + error = Remote()->SendRequest(static_cast(IFormHost::Message::FORM_HOST_ON_ACQUIRED), data, reply, + option); + if (error != ERR_OK) { + APP_LOGE("%{public}s, failed to SendRequest: %{public}d", __func__, error); + } +} + + +/** +* @brief Form is updated. +* @param bundleName Provider ability bundleName. +*/ +void FormHostProxy::OnUpdate(const FormJsInfo &formInfo) +{ + int error; + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!WriteInterfaceToken(data)) { + APP_LOGE("%{public}s, failed to write interface token", __func__); + } + + if (!data.WriteParcelable(&formInfo)) { + APP_LOGE("%{public}s, failed to write formInfo", __func__); + } + + error = Remote()->SendRequest(static_cast(IFormHost::Message::FORM_HOST_ON_UPDATE), data, reply, option); + if (error != ERR_OK) { + APP_LOGE("%{public}s, failed to SendRequest: %{public}d", __func__, error); + } +} + + +/** + * @brief Form provider is uninstalled + * @param formIds The Id list of the forms. + */ +void FormHostProxy::OnUninstall(const std::vector &formIds) +{ + int error; + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!WriteInterfaceToken(data)) { + APP_LOGE("%{public}s, failed to write interface token", __func__); + } + + if (!data.WriteInt64Vector(formIds)) { + APP_LOGE("%{public}s, failed to write formIds", __func__); + } + + error = Remote()->SendRequest(static_cast(IFormHost::Message::FORM_HOST_ON_UNINSTALL), data, reply, + option); + if (error != ERR_OK) { + APP_LOGE("%{public}s, failed to SendRequest: %{public}d", __func__, error); + } +} + +template +int FormHostProxy::GetParcelableInfos(MessageParcel &reply, std::vector &parcelableInfos) +{ + int32_t infoSize = reply.ReadInt32(); + for (int32_t i = 0; i < infoSize; i++) { + std::unique_ptr info(reply.ReadParcelable()); + if (!info) { + APP_LOGE("%{public}s, failed to read Parcelable infos", __func__); + return ERR_NULL_OBJECT; + } + parcelableInfos.emplace_back(*info); + } + APP_LOGI("%{public}s, get parcelable infos success", __func__); + return ERR_OK; +} + +bool FormHostProxy::WriteInterfaceToken(MessageParcel &data) +{ + if (!data.WriteInterfaceToken(FormHostProxy::GetDescriptor())) { + APP_LOGE("%{public}s, failed to write interface token", __func__); + return false; + } + return true; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_core/src/formmgr/form_host_stub.cpp b/interfaces/innerkits/appexecfwk_core/src/formmgr/form_host_stub.cpp new file mode 100644 index 0000000000..ce06121831 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/formmgr/form_host_stub.cpp @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2021 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 "app_log_wrapper.h" +#include "app_scheduler_interface.h" +#include "errors.h" +#include "form_host_stub.h" +#include "ipc_skeleton.h" +#include "ipc_types.h" +#include "iremote_object.h" + +namespace OHOS { +namespace AppExecFwk { +FormHostStub::FormHostStub() +{ + memberFuncMap_[static_cast(IFormHost::Message::FORM_HOST_ON_ACQUIRED)] = + &FormHostStub::HandleAcquired; + memberFuncMap_[static_cast(IFormHost::Message::FORM_HOST_ON_UPDATE)] = + &FormHostStub::HandleOnUpdate; + memberFuncMap_[static_cast(IFormHost::Message::FORM_HOST_ON_UNINSTALL)] = + &FormHostStub::HandleOnUninstall; +} + +FormHostStub::~FormHostStub() +{ + memberFuncMap_.clear(); +} +/** + * @brief handle remote request. + * @param data input param. + * @param reply output param. + * @param option message option. + * @return Returns ERR_OK on success, others on failure. + */ +int FormHostStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + APP_LOGI("FormHostStub::OnReceived, code = %{public}d, flags= %{public}d.", code, option.GetFlags()); + std::u16string descriptor = FormHostStub::GetDescriptor(); + std::u16string remoteDescriptor = data.ReadInterfaceToken(); + if (descriptor != remoteDescriptor) { + APP_LOGE("%{public}s failed, local descriptor is not equal to remote", __func__); + return ERR_INVALID_STATE; + } + + auto itFunc = memberFuncMap_.find(code); + if (itFunc != memberFuncMap_.end()) { + auto memberFunc = itFunc->second; + if (memberFunc != nullptr) { + return (this->*memberFunc)(data, reply); + } + } + + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); +} +/** + * @brief handle OnAcquired event. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ +int FormHostStub::HandleAcquired(MessageParcel &data, MessageParcel &reply) +{ + std::unique_ptr formInfo(data.ReadParcelable()); + if (!formInfo) { + APP_LOGE("%{public}s, failed to ReadParcelable", __func__); + return ERR_NULL_OBJECT; + } + OnAcquired(*formInfo); + reply.WriteInt32(ERR_OK); + return ERR_OK; +} +/** + * @brief handle OnUpdate event. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ +int FormHostStub::HandleOnUpdate(MessageParcel &data, MessageParcel &reply) +{ + std::unique_ptr formInfo(data.ReadParcelable()); + if (!formInfo) { + APP_LOGE("%{public}s, failed to ReadParcelable", __func__); + return ERR_NULL_OBJECT; + } + OnUpdate(*formInfo); + reply.WriteInt32(ERR_OK); + return ERR_OK; +} + +/** + * @brief handle OnUnInstall event. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ +int FormHostStub::HandleOnUninstall(MessageParcel &data, MessageParcel &reply) +{ + std::vector formIds; + bool ret = data.ReadInt64Vector(&formIds); + if (ret) { + OnUninstall(formIds); + reply.WriteInt32(ERR_OK); + return ERR_OK; + } + return ERR_INVALID_DATA; +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_core/src/formmgr/form_mgr_proxy.cpp b/interfaces/innerkits/appexecfwk_core/src/formmgr/form_mgr_proxy.cpp new file mode 100644 index 0000000000..606a06c012 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/formmgr/form_mgr_proxy.cpp @@ -0,0 +1,562 @@ +/* + * Copyright (c) 2021 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 "appexecfwk_errors.h" +#include "app_log_wrapper.h" +#include "form_mgr_proxy.h" +#include "string_ex.h" + +namespace OHOS { +namespace AppExecFwk { +FormMgrProxy::FormMgrProxy(const sptr &impl) : IRemoteProxy(impl) +{} +/** + * @brief Add form with want, send want to form manager service. + * @param formId The Id of the forms to add. + * @param want The want of the form to add. + * @param callerToken Caller ability token. + * @param formInfo Form info. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrProxy::AddForm(const int64_t formId, const Want &want, const sptr &callerToken, +FormJsInfo &formInfo) +{ + MessageParcel data; + if (!WriteInterfaceToken(data)) { + APP_LOGE("%{public}s, failed to write interface token", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteInt64(formId)) { + APP_LOGE("%{public}s, failed to write formId", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteParcelable(&want)) { + APP_LOGE("%{public}s, failed to write want", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + if (!data.WriteParcelable(callerToken)) { + APP_LOGE("%{public}s, failed to write callerToken", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + int error = GetParcelableInfo(IFormMgr::Message::FORM_MGR_ADD_FORM, data, formInfo); + if (error != ERR_OK) { + APP_LOGE("%{public}s, failed to SendRequest: %{public}d", __func__, error); + } + + return error; +} + +/** + * @brief Delete forms with formIds, send formIds to form manager service. + * @param formId The Id of the forms to delete. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrProxy::DeleteForm(const int64_t formId, const sptr &callerToken) +{ + MessageParcel data; + if (!WriteInterfaceToken(data)) { + APP_LOGE("%{public}s, failed to write interface token", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteInt64(formId)) { + APP_LOGE("%{public}s, failed to write want", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteParcelable(callerToken)) { + APP_LOGE("%{public}s, failed to write callerToken", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + MessageParcel reply; + MessageOption option; + int error = Remote()->SendRequest(static_cast(IFormMgr::Message::FORM_MGR_DELETE_FORM), data, reply, + option); + if (error != ERR_OK) { + APP_LOGE("%{public}s, failed to SendRequest: %{public}d", __func__, error); + return error; + } + return reply.ReadInt32(); +} + +/** + * @brief Release forms with formIds, send formIds to form manager service. + * @param formId The Id of the forms to release. + * @param callerToken Caller ability token. + * @param delCache Delete Cache or not. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrProxy::ReleaseForm(const int64_t formId, const sptr &callerToken, const bool delCache) +{ + MessageParcel data; + if (!WriteInterfaceToken(data)) { + APP_LOGE("%{public}s, failed to write interface token", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteInt64(formId)) { + APP_LOGE("%{public}s, failed to write want", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteParcelable(callerToken)) { + APP_LOGE("%{public}s, failed to write callerToken", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteBool(delCache)) { + APP_LOGE("%{public}s, failed to write delCache", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + MessageParcel reply; + MessageOption option; + int error = Remote()->SendRequest(static_cast(IFormMgr::Message::FORM_MGR_RELEASE_FORM), data, reply, + option); + if (error != ERR_OK) { + APP_LOGE("%{public}s, failed to SendRequest: %{public}d", __func__, error); + return error; + } + return reply.ReadInt32(); +} + +/** + * @brief Update form with formId, send formId to form manager service. + * @param formId The Id of the form to update. + * @param bundleName Provider ability bundleName. + * @param FormProviderData Form binding data. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrProxy::UpdateForm(const int64_t formId, const std::string &bundleName, +const FormProviderData &FormProviderData) +{ + MessageParcel data; + if (!WriteInterfaceToken(data)) { + APP_LOGE("%{public}s, failed to write interface token", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteInt64(formId)) { + APP_LOGE("%{public}s, failed to write formId", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + if (!data.WriteString(bundleName)) { + APP_LOGE("%{public}s, failed to write bundleName", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteParcelable(&FormProviderData)) { + APP_LOGE("%{public}s, failed to write formBindingData", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + MessageParcel reply; + MessageOption option; + int error = Remote()->SendRequest(static_cast(IFormMgr::Message::FORM_MGR_UPDATE_FORM), data, reply, + option); + if (error != ERR_OK) { + APP_LOGE("%{public}s, failed to SendRequest: %{public}d", __func__, error); + return error; + } + return reply.ReadInt32(); +} + +/** + * @brief Set next refresh time. + * @param formId The Id of the form to update. + * @param bundleName Provider ability bundleName. + * @param nextTime Next refresh time. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrProxy::SetNextRefreshTime(const int64_t formId, const int64_t nextTime) +{ + MessageParcel data; + MessageParcel reply; + + if (!WriteInterfaceToken(data)) { + APP_LOGE("%{public}s, failed to write interface token", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteInt64(formId)) { + APP_LOGE("%{public}s, failed to write formId", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteInt64(nextTime)) { + APP_LOGE("%{public}s, failed to write nextTime", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + MessageOption option; + int error = Remote()->SendRequest(static_cast(IFormMgr::Message::FORM_MGR_SET_NEXT_REFRESH_TIME), data, + reply, option); + if (error != ERR_OK) { + APP_LOGE("%{public}s, failed to SendRequest: %{public}d", __func__, error); + return error; + } + return reply.ReadInt32(); +} +/** + * @brief Lifecycle update. + * @param formIds The Id of the forms. + * @param callerToken Caller ability token. + * @param updateType update type. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrProxy::LifecycleUpdate(const std::vector &formIds, const sptr &callerToken, +const int32_t updateType) +{ + MessageParcel data; + MessageParcel reply; + + if (!WriteInterfaceToken(data)) { + APP_LOGE("%{public}s, failed to write interface token", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteInt64Vector(formIds)) { + APP_LOGE("%{public}s, failed to write formId", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteParcelable(callerToken)) { + APP_LOGE("%{public}s, failed to write bundleName", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteInt32(updateType)) { + APP_LOGE("%{public}s, failed to write nextTime", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + MessageOption option; + int error = Remote()->SendRequest(static_cast(IFormMgr::Message::FORM_MGR_LIFECYCLE_UPDATE), + data, reply, option); + if (error != ERR_OK) { + APP_LOGE("%{public}s, failed to SendRequest: %{public}d", __func__, error); + return error; + } + + return reply.ReadInt32(); +} +/** + * @brief Request form with formId and want, send formId and want to form manager service. + * @param formId The Id of the form to update. + * @param callerToken Caller ability token. + * @param want The want of the form to add. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrProxy::RequestForm(const int64_t formId, const sptr &callerToken, const Want &want) +{ + APP_LOGI("%{public}s called.", __func__); + + MessageParcel data; + if (!WriteInterfaceToken(data)) { + APP_LOGE("%{public}s, failed to write interface token", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteInt64(formId)) { + APP_LOGE("%{public}s, failed to write formId", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteParcelable(callerToken)) { + APP_LOGE("%{public}s, failed to write callerToken", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteParcelable(&want)) { + APP_LOGE("%{public}s, failed to write want", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + MessageParcel reply; + MessageOption option; + int error = Remote()->SendRequest(static_cast(IFormMgr::Message::FORM_MGR_REQUEST_FORM), + data, reply, option); + if (error != ERR_OK) { + APP_LOGE("%{public}s, failed to SendRequest: %{public}d", __func__, error); + return error; + } + return reply.ReadInt32(); +} + +/** + * @brief Form visible/invisible notify, send formIds to form manager service. + * @param formIds The Id list of the forms to notify. + * @param callerToken Caller ability token. + * @param formVisibleType The form visible type, including FORM_VISIBLE and FORM_INVISIBLE. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrProxy::NotifyWhetherVisibleForms(const std::vector &formIds, +const sptr &callerToken, const int32_t formVisibleType) +{ + MessageParcel data; + if (!WriteInterfaceToken(data)) { + APP_LOGE("%{public}s, failed to write interface token", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + if (!data.WriteInt64Vector(formIds)) { + APP_LOGE("%{public}s, failed to write formIds", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + if (!data.WriteParcelable(callerToken)) { + APP_LOGE("%{public}s, failed to write callerToken", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + if (!data.WriteInt32(formVisibleType)) { + APP_LOGE("%{public}s, failed to write formVisibleType", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + MessageParcel reply; + MessageOption option; + int error = Remote()->SendRequest(static_cast(IFormMgr::Message::FORM_MGR_NOTIFY_FORM_WHETHER_VISIBLE), + data, reply, option); + if (error != ERR_OK) { + APP_LOGE("%{public}s, failed to SendRequest: %{public}d", __func__, error); + return error; + } + return reply.ReadInt32(); +} + +/** + * @brief temp form to normal form. + * @param formId The Id of the form. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrProxy::CastTempForm(const int64_t formId, const sptr &callerToken) +{ + MessageParcel data; + if (!WriteInterfaceToken(data)) { + APP_LOGE("%{public}s, failed to write interface token", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteInt64(formId)) { + APP_LOGE("%{public}s, failed to write want", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteParcelable(callerToken)) { + APP_LOGE("%{public}s, failed to write callerToken", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + MessageParcel reply; + MessageOption option; + int error = Remote()->SendRequest(static_cast(IFormMgr::Message::FORM_MGR_CAST_TEMP_FORM), + data, reply, option); + if (error != ERR_OK) { + APP_LOGE("%{public}s, failed to SendRequest: %{public}d", __func__, error); + return error; + } + return reply.ReadInt32(); +} +/** + * @brief Dump all of form storage infos. + * @param formInfos All of form storage infos. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrProxy::DumpStorageFormInfos(std::string &formInfos) +{ + MessageParcel data; + if (!WriteInterfaceToken(data)) { + APP_LOGE("%{public}s, failed to write interface token", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + int error = GetStringInfo(IFormMgr::Message::FORM_MGR_STORAGE_FORM_INFOS, data, formInfos); + if (error != ERR_OK) { + APP_LOGE("%{public}s, failed to GetStringInfo: %{public}d", __func__, error); + } + + return error; +} +/** + * @brief Dump form info by a bundle name. + * @param bundleName The bundle name of form provider. + * @param formInfos Form infos. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrProxy::DumpFormInfoByBundleName(const std::string &bundleName, std::string &formInfos) +{ + MessageParcel data; + if (!WriteInterfaceToken(data)) { + APP_LOGE("%{public}s, failed to write interface token", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + if (!data.WriteString(bundleName)) { + APP_LOGE("%{public}s, failed to write bundleName", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + int error = GetStringInfo(IFormMgr::Message::FORM_MGR_FORM_INFOS_BY_NAME, data, formInfos); + if (error != ERR_OK) { + APP_LOGE("%{public}s, failed to GetStringInfo: %{public}d", __func__, error); + } + + return error; +} +/** + * @brief Dump form info by a bundle name. + * @param formId The id of the form. + * @param formInfo Form info. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrProxy::DumpFormInfoByFormId(const std::int64_t formId, std::string &formInfo) +{ + MessageParcel data; + if (!WriteInterfaceToken(data)) { + APP_LOGE("%{public}s, failed to write interface token", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteInt64(formId)) { + APP_LOGE("%{public}s, failed to write formId", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + int error = GetStringInfo(IFormMgr::Message::FORM_MGR_FORM_INFOS_BY_ID, data, formInfo); + if (error != ERR_OK) { + APP_LOGE("%{public}s, failed to GetStringInfo: %{public}d", __func__, error); + } + + return error; +} +/** + * @brief Process js message event. + * @param formId Indicates the unique id of form. + * @param want information passed to supplier. + * @param callerToken Caller ability token. + * @return Returns true if execute success, false otherwise. + */ +int FormMgrProxy::MessageEvent(const int64_t formId, const Want &want, const sptr &callerToken) +{ + MessageParcel data; + if (!WriteInterfaceToken(data)) { + APP_LOGE("%{public}s, failed to write interface token", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteInt64(formId)) { + APP_LOGE("%{public}s, failed to write formId", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteParcelable(&want)) { + APP_LOGE("%{public}s, failed to write want", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + if (!data.WriteParcelable(callerToken)) { + APP_LOGE("%{public}s, failed to write callerToken", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + MessageParcel reply; + MessageOption option; + int error = Remote()->SendRequest(static_cast(IFormMgr::Message::FORM_MGR_MESSAGE_EVENT), data, + reply, option); + if (error != ERR_OK) { + APP_LOGE("%{public}s, failed to SendRequest: %{public}d", __func__, error); + return error; + } + return reply.ReadInt32(); +} + +template +int FormMgrProxy::GetParcelableInfos(MessageParcel &reply, std::vector &parcelableInfos) +{ + int32_t infoSize = reply.ReadInt32(); + for (int32_t i = 0; i < infoSize; i++) { + std::unique_ptr info(reply.ReadParcelable()); + if (!info) { + APP_LOGE("%{public}s, failed to Read Parcelable infos", __func__); + return ERR_NULL_OBJECT; + } + parcelableInfos.emplace_back(*info); + } + APP_LOGI("get parcelable infos success"); + return ERR_OK; +} +bool FormMgrProxy::WriteInterfaceToken(MessageParcel &data) +{ + if (!data.WriteInterfaceToken(IFormMgr::GetDescriptor())) { + APP_LOGE("%{public}s, failed to write interface token", __func__); + return false; + } + return true; +} +int FormMgrProxy::GetStringInfo(IFormMgr::Message code, MessageParcel &data, std::string &stringInfo) +{ + int error; + MessageParcel reply; + error = SendTransactCmd(code, data, reply); + if (error != ERR_OK) { + return error; + } + + error = reply.ReadInt32(); + if (error != ERR_OK) { + APP_LOGE("%{public}s, failed to read reply result", __func__); + return error; + } + std::vector stringInfoList; + if (!reply.ReadStringVector(&stringInfoList)) { + APP_LOGE("%{public}s, failed to read string vector from reply", __func__); + return false; + } + if (stringInfoList.empty()) { + APP_LOGI("%{public}s, No string info", __func__); + return ERR_APPEXECFWK_FORM_INFO_NOT_EXIST; + } + for (auto &info : stringInfoList) { + stringInfo += info; + } + APP_LOGD("get string info success"); + return ERR_OK; +} +template +int FormMgrProxy::GetParcelableInfo(IFormMgr::Message code, MessageParcel &data, T &parcelableInfo) +{ + int error; + MessageParcel reply; + error = SendTransactCmd(code, data, reply); + if (error != ERR_OK) { + return error; + } + + error = reply.ReadInt32(); + if (error != ERR_OK) { + APP_LOGE("%{public}s, failed to read reply result", __func__); + return error; + } + + std::unique_ptr info(reply.ReadParcelable()); + if (!info) { + APP_LOGE("%{public}s, failed to readParcelableInfo", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + parcelableInfo = *info; + APP_LOGD("get parcelable info success"); + return ERR_OK; +} +int FormMgrProxy::SendTransactCmd(IFormMgr::Message code, MessageParcel &data, MessageParcel &reply) +{ + MessageOption option(MessageOption::TF_SYNC); + + sptr remote = Remote(); + if (!remote) { + APP_LOGE("%{public}s, failed to get remote object, cmd: %{public}d", __func__, code); + return ERR_APPEXECFWK_SERVICE_NOT_CONNECTED; + } + int32_t result = remote->SendRequest(static_cast(code), data, reply, option); + if (result != ERR_OK) { + APP_LOGE("%{public}s, failed to SendRequest: %{public}d, cmd: %{public}d", __func__, result, code); + return result; + } + return ERR_OK; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_core/src/formmgr/form_mgr_stub.cpp b/interfaces/innerkits/appexecfwk_core/src/formmgr/form_mgr_stub.cpp new file mode 100644 index 0000000000..ce4f6173ab --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/formmgr/form_mgr_stub.cpp @@ -0,0 +1,385 @@ +/* + * Copyright (c) 2021 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 "appexecfwk_errors.h" +#include "app_log_wrapper.h" +#include "form_mgr_stub.h" +#include "ipc_skeleton.h" +#include "ipc_types.h" +#include "iremote_object.h" + +namespace OHOS { +namespace AppExecFwk { +const int32_t LIMIT_PARCEL_SIZE = 1024; + +void SplitString(const std::string &source, std::vector &strings) +{ + int splitSize = (source.size() / LIMIT_PARCEL_SIZE); + if ((source.size() % LIMIT_PARCEL_SIZE) != 0) { + splitSize++; + } + APP_LOGD("the dump string split into %{public}d size", splitSize); + for (int i = 0; i < splitSize; i++) { + int32_t start = LIMIT_PARCEL_SIZE * i; + strings.emplace_back(source.substr(start, LIMIT_PARCEL_SIZE)); + } +} + +FormMgrStub::FormMgrStub() +{ + memberFuncMap_[static_cast(IFormMgr::Message::FORM_MGR_ADD_FORM)] = + &FormMgrStub::HandleAddForm; + memberFuncMap_[static_cast(IFormMgr::Message::FORM_MGR_DELETE_FORM)] = + &FormMgrStub::HandleDeleteForm; + memberFuncMap_[static_cast(IFormMgr::Message::FORM_MGR_RELEASE_FORM)] = + &FormMgrStub::HandleReleaseForm; + memberFuncMap_[static_cast(IFormMgr::Message::FORM_MGR_UPDATE_FORM)] = + &FormMgrStub::HandleUpdateForm; + memberFuncMap_[static_cast(IFormMgr::Message::FORM_MGR_REQUEST_FORM)] = + &FormMgrStub::HandleRequestForm; + memberFuncMap_[static_cast(IFormMgr::Message::FORM_MGR_NOTIFY_FORM_WHETHER_VISIBLE)] = + &FormMgrStub::HandleNotifyWhetherVisibleForms; + memberFuncMap_[static_cast(IFormMgr::Message::FORM_MGR_CAST_TEMP_FORM)] = + &FormMgrStub::HandleCastTempForm; + memberFuncMap_[static_cast(IFormMgr::Message::FORM_MGR_STORAGE_FORM_INFOS)] = + &FormMgrStub::HandleDumpStorageFormInfos; + memberFuncMap_[static_cast(IFormMgr::Message::FORM_MGR_FORM_INFOS_BY_NAME)] = + &FormMgrStub::HandleDumpFormInfoByBundleName; + memberFuncMap_[static_cast(IFormMgr::Message::FORM_MGR_FORM_INFOS_BY_ID)] = + &FormMgrStub::HandleDumpFormInfoByFormId; + memberFuncMap_[static_cast(IFormMgr::Message::FORM_MGR_SET_NEXT_REFRESH_TIME)] = + &FormMgrStub::HandleSetNextRefreshTime; + memberFuncMap_[static_cast(IFormMgr::Message::FORM_MGR_LIFECYCLE_UPDATE)] = + &FormMgrStub::HandleLifecycleUpdate; + memberFuncMap_[static_cast(IFormMgr::Message::FORM_MGR_MESSAGE_EVENT)] = + &FormMgrStub::HandleMessageEvent; +} + +FormMgrStub::~FormMgrStub() +{ + memberFuncMap_.clear(); +} + +/** + * @brief handle remote request. + * @param data input param. + * @param reply output param. + * @param option message option. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + APP_LOGI("FormMgrStub::OnReceived, code = %{public}d, flags= %{public}d.", code, option.GetFlags()); + std::u16string descriptor = FormMgrStub::GetDescriptor(); + std::u16string remoteDescriptor = data.ReadInterfaceToken(); + if (descriptor != remoteDescriptor) { + APP_LOGE("%{public}s failed, local descriptor is not equal to remote", __func__); + return ERR_INVALID_STATE; + } + + auto itFunc = memberFuncMap_.find(code); + if (itFunc != memberFuncMap_.end()) { + auto memberFunc = itFunc->second; + if (memberFunc != nullptr) { + return (this->*memberFunc)(data, reply); + } + } + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); +} +/** + * @brief handle AddForm message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ +int32_t FormMgrStub::HandleAddForm(MessageParcel &data, MessageParcel &reply) +{ + int64_t formId = data.ReadInt64(); + std::unique_ptr want(data.ReadParcelable()); + if (!want) { + APP_LOGE("%{public}s, failed to ReadParcelable", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + sptr client = data.ReadParcelable(); + if (client == nullptr) { + APP_LOGE("%{public}s, failed to RemoteObject invalidate", __func__); + return ERR_APPEXECFWK_SERVICE_NOT_CONNECTED; + } + + FormJsInfo formInfo; + int32_t result = AddForm(formId, *want, client, formInfo); + reply.WriteInt32(result); + reply.WriteParcelable(&formInfo); + + return result; +} +/** + * @brief handle DeleteForm message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ +int32_t FormMgrStub::HandleDeleteForm(MessageParcel &data, MessageParcel &reply) +{ + int64_t formId = data.ReadInt64(); + sptr client = data.ReadParcelable(); + if (client == nullptr) { + return ERR_APPEXECFWK_SERVICE_NOT_CONNECTED; + } + int32_t result = DeleteForm(formId, client); + reply.WriteInt32(result); + return result; +} +/** + * @brief handle ReleaseForm message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ +int32_t FormMgrStub::HandleReleaseForm(MessageParcel &data, MessageParcel &reply) +{ + int64_t formId = data.ReadInt64(); + sptr client = data.ReadParcelable(); + if (client == nullptr) { + return ERR_APPEXECFWK_SERVICE_NOT_CONNECTED; + } + bool delCache = data.ReadBool(); + + int32_t result = ReleaseForm(formId, client, delCache); + reply.WriteInt32(result); + return result; +} +/** + * @brief handle UpdateForm message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ +int32_t FormMgrStub::HandleUpdateForm(MessageParcel &data, MessageParcel &reply) +{ + int64_t formId = data.ReadInt64(); + std::string bundleName = data.ReadString(); + std::unique_ptr formBindingData(data.ReadParcelable()); + int32_t result = UpdateForm(formId, bundleName, *formBindingData); + reply.WriteInt32(result); + return result; +} +/** + * @brief handle SetNextRefreshTime message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ +int32_t FormMgrStub::HandleSetNextRefreshTime(MessageParcel &data, MessageParcel &reply) +{ + int64_t formId = data.ReadInt64(); + int64_t nextTime = data.ReadInt64(); + int32_t result = SetNextRefreshTime(formId, nextTime); + reply.WriteInt32(result); + return result; +} +/** + * @brief handle LifecycleUpdate message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ +int32_t FormMgrStub::HandleLifecycleUpdate(MessageParcel &data, MessageParcel &reply) +{ + std::vector formIds; + bool ret = data.ReadInt64Vector(&formIds); + if (!ret) { + return ERR_APPEXECFWK_PARCEL_ERROR; + } + sptr client = data.ReadParcelable(); + if (client == nullptr) { + APP_LOGE("%{public}s, failed to ReadParcelable", __func__); + return ERR_APPEXECFWK_SERVICE_NOT_CONNECTED; + } + int32_t updateType = data.ReadInt32(); + int32_t result = LifecycleUpdate(formIds, client, updateType); + reply.WriteInt32(result); + return result; +} +/** + * @brief handle RequestForm message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ +int32_t FormMgrStub::HandleRequestForm(MessageParcel &data, MessageParcel &reply) +{ + APP_LOGI("%{public}s called.", __func__); + + int64_t formId = data.ReadInt64(); + + sptr client = data.ReadParcelable(); + if (client == nullptr) { + APP_LOGE("%{public}s, failed to ReadParcelable", __func__); + return ERR_APPEXECFWK_SERVICE_NOT_CONNECTED; + } + + std::unique_ptr want(data.ReadParcelable()); + if (!want) { + APP_LOGE("%{public}s, failed to ReadParcelable", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + int32_t result = RequestForm(formId, client, *want); + reply.WriteInt32(result); + return result; +} +/** + * @brief handle NotifyVisibleForms message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ +int32_t FormMgrStub::HandleNotifyWhetherVisibleForms(MessageParcel &data, MessageParcel &reply) +{ + std::vector formIds; + bool ret = data.ReadInt64Vector(&formIds); + if (!ret) { + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + sptr client = data.ReadParcelable(); + if (client == nullptr) { + return ERR_APPEXECFWK_SERVICE_NOT_CONNECTED; + } + int32_t formVisibleType = data.ReadInt32(); + + int32_t result = NotifyWhetherVisibleForms(formIds, client, formVisibleType); + reply.WriteInt32(result); + return result; +} + +/** + * @brief handle CastTempForm message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ +int32_t FormMgrStub::HandleCastTempForm(MessageParcel &data, MessageParcel &reply) +{ + int64_t formId = data.ReadInt64(); + sptr client = data.ReadParcelable(); + if (client == nullptr) { + return ERR_APPEXECFWK_SERVICE_NOT_CONNECTED; + } + + int32_t result = CastTempForm(formId, client); + reply.WriteInt32(result); + return result; +} +/** + * @brief Handle DumpStorageFormInfos message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ +int32_t FormMgrStub::HandleDumpStorageFormInfos(MessageParcel &data, MessageParcel &reply) +{ + std::string formInfos; + int32_t result = DumpStorageFormInfos(formInfos); + reply.WriteInt32(result); + if (result == ERR_OK) { + std::vector dumpInfos; + SplitString(formInfos, dumpInfos); + if (!reply.WriteStringVector(dumpInfos)) { + APP_LOGE("%{public}s, failed to WriteStringVector", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + } + + return result; +} +/** + * @brief Handle DumpFormInfoByBundleName message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ +int32_t FormMgrStub::HandleDumpFormInfoByBundleName(MessageParcel &data, MessageParcel &reply) +{ + std::string bundleName = data.ReadString(); + std::string formInfos; + int32_t result = DumpFormInfoByBundleName(bundleName, formInfos); + reply.WriteInt32(result); + if (result == ERR_OK) { + APP_LOGD("%{public}s, formInfos: %{public}s", __func__, formInfos.c_str()); + std::vector dumpInfos; + SplitString(formInfos, dumpInfos); + if (!reply.WriteStringVector(dumpInfos)) { + APP_LOGE("%{public}s, failed to WriteStringVector", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + } + + return result; +} +/** + * @brief Handle DumpFormInfoByFormId message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ +int32_t FormMgrStub::HandleDumpFormInfoByFormId(MessageParcel &data, MessageParcel &reply) +{ + int64_t formId = data.ReadInt64(); + std::string formInfo; + int32_t result = DumpFormInfoByFormId(formId, formInfo); + reply.WriteInt32(result); + if (result == ERR_OK) { + std::vector dumpInfos; + SplitString(formInfo, dumpInfos); + if (!reply.WriteStringVector(dumpInfos)) { + APP_LOGE("%{public}s, failed to WriteStringVector", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + } + return result; +} +/** + * @brief Handle DumpFormInfoByFormId message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ +int32_t FormMgrStub::HandleMessageEvent(MessageParcel &data, MessageParcel &reply) +{ + APP_LOGI("%{public}s called.", __func__); + + int64_t formId = data.ReadInt64(); + + std::unique_ptr want(data.ReadParcelable()); + if (!want) { + APP_LOGE("%{public}s, failed to ReadParcelable", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + sptr client = data.ReadParcelable(); + if (client == nullptr) { + APP_LOGE("%{public}s, failed to ReadParcelable", __func__); + return ERR_APPEXECFWK_SERVICE_NOT_CONNECTED; + } + + int32_t result = MessageEvent(formId, *want, client); + reply.WriteInt32(result); + return result; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_core/src/formmgr/form_provider_proxy.cpp b/interfaces/innerkits/appexecfwk_core/src/formmgr/form_provider_proxy.cpp new file mode 100644 index 0000000000..9d94e233bc --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/formmgr/form_provider_proxy.cpp @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2021 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 "appexecfwk_errors.h" +#include "form_provider_proxy.h" +#include "string_ex.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @brief Acquire to give back an ProviderFormInfo. This is sync API. + * @param formId The Id of the from. + * @param want Indicates the {@link Want} structure containing form info. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ +int FormProviderProxy::AcquireProviderFormInfo(const int64_t formId, const Want &want, +const sptr &callerToken) +{ + int error; + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!WriteInterfaceToken(data)) { + APP_LOGE("%{public}s, failed to write interface token", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteInt64(formId)) { + APP_LOGE("%{public}s fail, write want error", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteParcelable(&want)) { + APP_LOGE("%{public}s, failed to write want", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + if (!data.WriteParcelable(callerToken)) { + APP_LOGE("%{public}s, failed to write callerToken", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + error = Remote()->SendRequest(static_cast(IFormProvider::Message::FORM_ACQUIRE_PROVIDER_FORM_INFO), + data, reply, option); + if (error != ERR_OK) { + APP_LOGE("%{public}s, failed to SendRequest: %{public}d", __func__, error); + return error; + } + return ERR_OK; +} + +/** + * @brief Notify provider when the form was deleted. + * @param formIds The id list of forms. + * @param want Indicates the structure containing form info. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ +int FormProviderProxy::NotifyFormDelete(const int64_t formId, const Want &want, const sptr &callerToken) +{ + int error; + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!WriteInterfaceToken(data)) { + APP_LOGE("%{public}s, failed to write interface token", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteInt64(formId)) { + APP_LOGE("%{public}s, failed to write formId", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteParcelable(&want)) { + APP_LOGE("%{public}s, failed to write want", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteParcelable(callerToken)) { + APP_LOGE("%{public}s, failed to write callerToken", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + error = Remote()->SendRequest(static_cast(IFormProvider::Message::FORM_PROVIDER_NOTIFY_FORM_DELETE), + data, reply, option); + if (error != ERR_OK) { + APP_LOGE("%{public}s, failed to SendRequest: %{public}d", __func__, error); + return error; + } + return ERR_OK; +} +/** + * @brief Notify provider when the forms was deleted. + * @param formIds The id list of forms. + * @param want Indicates the structure containing form info. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ +int FormProviderProxy::NotifyFormsDelete(const std::vector &formIds, const Want &want, +const sptr &callerToken) +{ + int error; + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!WriteInterfaceToken(data)) { + APP_LOGE("%{public}s, failed to write interface token", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteInt64Vector(formIds)) { + APP_LOGE("%{public}s, failed to write formIds", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteParcelable(&want)) { + APP_LOGE("%{public}s, failed to write want", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteParcelable(callerToken)) { + APP_LOGE("%{public}s, failed to write callerToken", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + error = Remote()->SendRequest(static_cast(IFormProvider::Message::FORM_PROVIDER_NOTIFY_FORMS_DELETE), + data, reply, option); + if (error != ERR_OK) { + APP_LOGE("%{public}s, failed to SendRequest: %{public}d", __func__, error); + return error; + } + return ERR_OK; +} + +/** + * @brief Notify provider when the form need update. + * @param formId The Id of the form. + * @param want Indicates the structure containing form info. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ +int FormProviderProxy::NotifyFormUpdate(const int64_t formId, const Want &want, const sptr &callerToken) +{ + int error; + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!WriteInterfaceToken(data)) { + APP_LOGE("%{public}s, failed to write interface token.", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteInt64(formId)) { + APP_LOGE("%{public}s, failed to write formId.", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + if (!data.WriteParcelable(&want)) { + APP_LOGE("%{public}s, failed to write want.", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + if (!data.WriteParcelable(callerToken)) { + APP_LOGE("%{public}s, failed to write callerToken.", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + error = Remote()->SendRequest(static_cast(IFormProvider::Message::FORM_PROVIDER_NOTIFY_FORM_UPDATE), + data, reply, option); + if (error != ERR_OK) { + APP_LOGE("%{public}s, failed to SendRequest: %{public}d", __func__, error); + return error; + } + return ERR_OK; +} + +/** + * @brief Event notify when change the form visible. + * + * @param formIds The vector of form ids. + * @param formVisibleType The form visible type, including FORM_VISIBLE and FORM_INVISIBLE. + * @param want Indicates the structure containing form info. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ +int FormProviderProxy::EventNotify(const std::vector &formIds, const int32_t formVisibleType, + const Want &want, const sptr &callerToken) +{ + int error; + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!WriteInterfaceToken(data)) { + APP_LOGE("%{public}s, failed to write interface token.", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + if (!data.WriteInt64Vector(formIds)) { + APP_LOGE("%{public}s, failed to write formIds.", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + if (!data.WriteInt32(formVisibleType)) { + APP_LOGE("%{public}s, failed to write formVisibleType.", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + if (!data.WriteParcelable(&want)) { + APP_LOGE("%{public}s, failed to write want.", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + if (!data.WriteParcelable(callerToken)) { + APP_LOGE("%{public}s, failed to write callerToken.", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + error = Remote()->SendRequest(static_cast(IFormProvider::Message::FORM_PROVIDER_EVENT_NOTIFY), + data, reply, option); + if (error != ERR_OK) { + APP_LOGE("%{public}s, failed to SendRequest: %{public}d", __func__, error); + return error; + } + return ERR_OK; +} + +/** + * @brief Notify provider when the temp form was cast to normal form. + * @param formId The Id of the form to update. + * @param want Indicates the structure containing form info. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ +int FormProviderProxy::NotifyFormCastTempForm(const int64_t formId, const Want &want, +const sptr &callerToken) +{ + int error; + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!WriteInterfaceToken(data)) { + APP_LOGE("%{public}s, failed to write interface token", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + if (!data. WriteInt64(formId)) { + APP_LOGE("%{public}s, failed to write formId", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteParcelable(&want)) { + APP_LOGE("%{public}s, failed to write want", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteParcelable(callerToken)) { + APP_LOGE("%{public}s, failed to write callerToken", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + error = Remote()->SendRequest(static_cast(IFormProvider::Message::FORM_PROVIDER_NOTIFY_TEMP_FORM_CAST), + data, reply, option); + if (error != ERR_OK) { + APP_LOGE("%{public}s, failed to SendRequest: %{public}d", __func__, error); + return error; + } + return ERR_OK; +} + +/** + * @brief Fire message event to form provider. + * @param formId The Id of the from. + * @param message Event message. + * @param want The want of the request. + * @param callerToken Form provider proxy object. + * @return Returns ERR_OK on success, others on failure. + */ +int FormProviderProxy::FireFormEvent(const int64_t formId, const std::string &message, const Want &want, +const sptr &callerToken) +{ + MessageParcel data; + if (!WriteInterfaceToken(data)) { + APP_LOGE("%{public}s, failed to write interface token", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteInt64(formId)) { + APP_LOGE("%{public}s, failed to write formId", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteString(message)) { + APP_LOGE("%{public}s, failed to write message", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteParcelable(&want)) { + APP_LOGE("%{public}s, failed to write want", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteParcelable(callerToken)) { + APP_LOGE("%{public}s, failed to write callerToken", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + MessageParcel reply; + MessageOption option; + int error = Remote()->SendRequest(static_cast(IFormProvider::Message::FORM_PROVIDER_NOTIFY_FORM_DELETE), + data, reply, option); + if (error != ERR_OK) { + APP_LOGE("%{public}s, failed to SendRequest: %{public}d", __func__, error); + return error; + } + return ERR_OK; +} + +template +int FormProviderProxy::GetParcelableInfos(MessageParcel &reply, std::vector &parcelableInfos) +{ + int32_t infoSize = reply.ReadInt32(); + for (int32_t i = 0; i < infoSize; i++) { + std::unique_ptr info(reply.ReadParcelable()); + if (!info) { + APP_LOGE("%{public}s, failed to Read Parcelable infos", __func__); + return ERR_NULL_OBJECT; + } + parcelableInfos.emplace_back(*info); + } + APP_LOGI("%{public}s, get parcelable infos success", __func__); + return ERR_OK; +} + +bool FormProviderProxy::WriteInterfaceToken(MessageParcel &data) +{ + if (!data.WriteInterfaceToken(FormProviderProxy::GetDescriptor())) { + APP_LOGE("%{public}s, failed to write interface token", __func__); + return false; + } + return true; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_core/src/formmgr/form_provider_stub.cpp b/interfaces/innerkits/appexecfwk_core/src/formmgr/form_provider_stub.cpp new file mode 100644 index 0000000000..95203261c7 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/formmgr/form_provider_stub.cpp @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2021 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 "app_log_wrapper.h" +#include "app_scheduler_interface.h" +#include "errors.h" +#include "form_provider_stub.h" +#include "ipc_skeleton.h" +#include "ipc_types.h" +#include "iremote_object.h" + +namespace OHOS { +namespace AppExecFwk { +FormProviderStub::FormProviderStub() +{ + memberFuncMap_[static_cast(IFormProvider::Message::FORM_ACQUIRE_PROVIDER_FORM_INFO)] = + &FormProviderStub::HandleAcquireProviderFormInfo; + memberFuncMap_[static_cast(IFormProvider::Message::FORM_PROVIDER_NOTIFY_FORM_DELETE)] = + &FormProviderStub::HandleNotifyFormDelete; + memberFuncMap_[static_cast(IFormProvider::Message::FORM_PROVIDER_NOTIFY_FORMS_DELETE)] = + &FormProviderStub::HandleNotifyFormsDelete; + memberFuncMap_[static_cast(IFormProvider::Message::FORM_PROVIDER_NOTIFY_FORM_UPDATE)] = + &FormProviderStub::HandleNotifyFormUpdate; + memberFuncMap_[static_cast(IFormProvider::Message::FORM_PROVIDER_EVENT_NOTIFY)] = + &FormProviderStub::HandleEventNotify; + memberFuncMap_[static_cast(IFormProvider::Message::FORM_PROVIDER_NOTIFY_TEMP_FORM_CAST)] = + &FormProviderStub::HandleNotifyFormCastTempForm; + memberFuncMap_[static_cast(IFormProvider::Message::FORM_PROVIDER_EVENT_MESSAGE)] = + &FormProviderStub::HandleFireFormEvent; +} + +FormProviderStub::~FormProviderStub() +{ + memberFuncMap_.clear(); +} +/** + * @brief handle remote request. + * @param data input param. + * @param reply output param. + * @param option message option. + * @return Returns ERR_OK on success, others on failure. + */ +int FormProviderStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + APP_LOGI("FormProviderStub::OnReceived, code = %{public}d, flags= %{public}d.", code, option.GetFlags()); + std::u16string descriptor = FormProviderStub::GetDescriptor(); + std::u16string remoteDescriptor = data.ReadInterfaceToken(); + if (descriptor != remoteDescriptor) { + APP_LOGE("%{public}s failed, local descriptor is not equal to remote", __func__); + return ERR_INVALID_STATE; + } + + auto itFunc = memberFuncMap_.find(code); + if (itFunc != memberFuncMap_.end()) { + auto memberFunc = itFunc->second; + if (memberFunc != nullptr) { + return (this->*memberFunc)(data, reply); + } + } + + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); +} +/** + * @brief handle AcquireProviderFormInfo message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ +int FormProviderStub::HandleAcquireProviderFormInfo(MessageParcel &data, MessageParcel &reply) +{ + int64_t formId = data.ReadInt64(); + std::unique_ptr want(data.ReadParcelable()); + if (!want) { + APP_LOGE("%{public}s, failed to ReadParcelable", __func__); + return ERR_NULL_OBJECT; + } + + sptr client = data.ReadParcelable(); + if (client == nullptr) { + APP_LOGE("%{public}s, failed to ReadParcelable", __func__); + return ERR_NULL_OBJECT; + } + + int32_t result = AcquireProviderFormInfo(formId, *want, client); + reply.WriteInt32(result); + return result; +} +/** + * @brief handle NotifyFormDelete message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ +int FormProviderStub::HandleNotifyFormDelete(MessageParcel &data, MessageParcel &reply) +{ + int64_t formId = data.ReadInt64(); + std::unique_ptr want(data.ReadParcelable()); + if (!want) { + APP_LOGE("%{public}s fail, ReadParcelable failed", __func__); + return ERR_NULL_OBJECT; + } + + sptr client = data.ReadParcelable(); + if (client == nullptr) { + APP_LOGE("%{public}s, failed to ReadParcelable", __func__); + return ERR_NULL_OBJECT; + } + + int32_t result = NotifyFormDelete(formId, *want, client); + reply.WriteInt32(result); + return result; +} +/** + * @brief handle NotifyFormsDelete message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ +int FormProviderStub::HandleNotifyFormsDelete(MessageParcel &data, MessageParcel &reply) +{ + std::vector formIds; + bool ret = data.ReadInt64Vector(&formIds); + if (ret) { + std::unique_ptr want(data.ReadParcelable()); + if (!want) { + APP_LOGE("%{public}s fail, ReadParcelable failed", __func__); + return ERR_NULL_OBJECT; + } + + sptr client = data.ReadParcelable(); + if (client == nullptr) { + APP_LOGE("%{public}s, failed to ReadParcelable", __func__); + return ERR_NULL_OBJECT; + } + + int32_t result = NotifyFormsDelete(formIds, *want, client); + reply.WriteInt32(result); + return result; + } + + return ERR_INVALID_DATA; +} +/** + * @brief handle NotifyFormUpdate message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ +int FormProviderStub::HandleNotifyFormUpdate(MessageParcel &data, MessageParcel &reply) +{ + int64_t formId = data.ReadInt64(); + + std::unique_ptr want(data.ReadParcelable()); + if (!want) { + APP_LOGE("%{public}s, failed to ReadParcelable", __func__); + return ERR_NULL_OBJECT; + } + + sptr client = data.ReadParcelable(); + if (client == nullptr) { + APP_LOGE("%{public}s, failed to ReadParcelable", __func__); + return ERR_NULL_OBJECT; + } + + int32_t result = NotifyFormUpdate(formId, *want, client); + reply.WriteInt32(result); + return result; +} + +/** + * @brief handle EventNotify message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ +int FormProviderStub::HandleEventNotify(MessageParcel &data, MessageParcel &reply) +{ + std::vector formIds; + bool ret = data.ReadInt64Vector(&formIds); + if (ret) { + int32_t formVisibleType = data.ReadInt32(); + + std::unique_ptr want(data.ReadParcelable()); + if (!want) { + APP_LOGE("%{public}s, failed to ReadParcelable", __func__); + return ERR_NULL_OBJECT; + } + + sptr client = data.ReadParcelable(); + if (client == nullptr) { + APP_LOGE("%{public}s, failed to ReadParcelable", __func__); + return ERR_NULL_OBJECT; + } + + int32_t result = EventNotify(formIds, formVisibleType, *want, client); + reply.WriteInt32(result); + return result; + } + + return ERR_INVALID_DATA; +} + +/** + * @brief handle NotifyFormCastTempForm message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ +int FormProviderStub::HandleNotifyFormCastTempForm(MessageParcel &data, MessageParcel &reply) +{ + int64_t formId = data.ReadInt64(); + + std::unique_ptr want(data.ReadParcelable()); + if (!want) { + APP_LOGE("%{public}s fail, ReadParcelable failed", __func__); + return ERR_NULL_OBJECT; + } + + sptr client = data.ReadParcelable(); + if (client == nullptr) { + APP_LOGE("%{public}s, failed to ReadParcelable", __func__); + return ERR_NULL_OBJECT; + } + + int32_t result = NotifyFormCastTempForm(formId, *want, client); + reply.WriteInt32(result); + return result; +} +/** + * @brief handle NotifyFormCastTempForm message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ +int FormProviderStub::HandleFireFormEvent(MessageParcel &data, MessageParcel &reply) +{ + int64_t formId = data.ReadInt64(); + std::string message = data.ReadString(); + std::unique_ptr want(data.ReadParcelable()); + if (!want) { + APP_LOGE("%{public}s fail, ReadParcelable failed", __func__); + return ERR_NULL_OBJECT; + } + + sptr client = data.ReadParcelable(); + if (client == nullptr) { + APP_LOGE("%{public}s, failed to ReadParcelable", __func__); + return ERR_NULL_OBJECT; + } + + int32_t result = FireFormEvent(formId, message, *want, client); + reply.WriteInt32(result); + return result; +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_core/src/formmgr/form_supply_proxy.cpp b/interfaces/innerkits/appexecfwk_core/src/formmgr/form_supply_proxy.cpp new file mode 100644 index 0000000000..190f65c535 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/formmgr/form_supply_proxy.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2021 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 "appexecfwk_errors.h" +#include "form_constants.h" +#include "form_supply_proxy.h" +#include "string_ex.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @brief Send form binding data from form provider to fms. + * @param providerFormInfo Form binding data. + * @param want input data. + * @return Returns ERR_OK on success, others on failure. + */ +int FormSupplyProxy::OnAcquire(const FormProviderInfo &formInfo, const Want& want) +{ + MessageParcel data; + if (!WriteInterfaceToken(data)) { + APP_LOGE("%{public}s, failed to WriteInterfaceToken", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (!data.WriteParcelable(&want)) { + APP_LOGE("%{public}s, failed to write want", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + if (want.GetIntParam(Constants::PROVIDER_FLAG, ERR_OK) == ERR_OK) { + if (!data.WriteParcelable(&formInfo)) { + APP_LOGE("%{public}s, failed to write formInfo", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + } + + MessageParcel reply; + MessageOption option; + int error = Remote()->SendRequest(static_cast(IFormSupply::Message::TRANSACTION_FORM_ACQUIRED), + data, reply, option); + if (error != ERR_OK) { + APP_LOGE("%{public}s, failed to SendRequest: %{public}d", __func__, error); + } + return error; +} + + +/** + * @brief Send other event to fms. + * @param want input data. + * @return Returns ERR_OK on success, others on failure. + */ +int FormSupplyProxy::OnEventHandle(const Want& want) +{ + MessageParcel data; + + if (!WriteInterfaceToken(data)) { + APP_LOGE("%{public}s, failed to write interface token", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + if (!data.WriteParcelable(&want)) { + APP_LOGE("%{public}s, failed to write want", __func__); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + MessageParcel reply; + MessageOption option; + int error = Remote()->SendRequest(static_cast(IFormSupply::Message::TRANSACTION_EVENT_HANDLE), + data, reply, option); + if (error != ERR_OK) { + APP_LOGE("%{public}s, failed to SendRequest: %{public}d", __func__, error); + } + return error; +} + +template +int FormSupplyProxy::GetParcelableInfos(MessageParcel &reply, std::vector &parcelableInfos) +{ + int32_t infoSize = reply.ReadInt32(); + for (int32_t i = 0; i < infoSize; i++) { + std::unique_ptr info(reply.ReadParcelable()); + if (!info) { + APP_LOGE("%{public}s, failed to ReadParcelable", __func__); + return ERR_INVALID_VALUE; + } + parcelableInfos.emplace_back(*info); + } + APP_LOGI("get parcelable infos success"); + return ERR_OK; +} + +bool FormSupplyProxy::WriteInterfaceToken(MessageParcel &data) +{ + if (!data.WriteInterfaceToken(FormSupplyProxy::GetDescriptor())) { + APP_LOGE("%{public}s, failed to write interface token failed", __func__); + return false; + } + return true; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_core/src/formmgr/form_supply_stub.cpp b/interfaces/innerkits/appexecfwk_core/src/formmgr/form_supply_stub.cpp new file mode 100644 index 0000000000..89061b1607 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/formmgr/form_supply_stub.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2021 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 "appexecfwk_errors.h" +#include "app_log_wrapper.h" +#include "form_constants.h" +#include "form_supply_stub.h" +#include "ipc_skeleton.h" +#include "ipc_types.h" +#include "iremote_object.h" + +namespace OHOS { +namespace AppExecFwk { +FormSupplyStub::FormSupplyStub() +{ + memberFuncMap_[static_cast(IFormSupply::Message::TRANSACTION_FORM_ACQUIRED)] = + &FormSupplyStub::HandleOnAcquire; + memberFuncMap_[static_cast(IFormSupply::Message::TRANSACTION_EVENT_HANDLE)] = + &FormSupplyStub::HandleOnEventHandle; +} + +FormSupplyStub::~FormSupplyStub() +{ + memberFuncMap_.clear(); +} +/** + * @brief handle remote request. + * @param data input param. + * @param reply output param. + * @param option message option. + * @return Returns ERR_OK on success, others on failure. + */ +int FormSupplyStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + APP_LOGI("FormSupplyStub::OnReceived, code = %{public}d, flags= %{public}d.", code, option.GetFlags()); + std::u16string descriptor = FormSupplyStub::GetDescriptor(); + std::u16string remoteDescriptor = data.ReadInterfaceToken(); + if (descriptor != remoteDescriptor) { + APP_LOGE("%{public}s failed, local descriptor is not equal to remote", __func__); + return ERR_INVALID_STATE; + } + + auto itFunc = memberFuncMap_.find(code); + if (itFunc != memberFuncMap_.end()) { + auto memberFunc = itFunc->second; + if (memberFunc != nullptr) { + return (this->*memberFunc)(data, reply); + } + } + + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); +} +/** + * @brief handle OnAcquire message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ +int FormSupplyStub::HandleOnAcquire(MessageParcel &data, MessageParcel &reply) +{ + std::unique_ptr want(data.ReadParcelable()); + if (!want) { + APP_LOGE("%{public}s, failed to ReadParcelable", __func__); + reply.WriteInt32(ERR_INVALID_VALUE); + return ERR_INVALID_VALUE; + } + + int errCode = ERR_OK; + do { + errCode = want->GetIntParam(Constants::PROVIDER_FLAG, ERR_OK); + if (errCode != ERR_OK) { + APP_LOGE("%{public}s, provider error", __func__); + break; + } + std::unique_ptr formInfo(data.ReadParcelable()); + if (formInfo == nullptr) { + APP_LOGE("%{public}s, failed to ReadParcelable", __func__); + errCode = ERR_INVALID_VALUE; + break; + } + int32_t result = OnAcquire(*formInfo, *want); + reply.WriteInt32(result); + return result; + } while (true); + + FormProviderInfo formProviderInfo; + want->SetParam(Constants::PROVIDER_FLAG, errCode); + OnAcquire(formProviderInfo, *want); + reply.WriteInt32(errCode); + return errCode; +} +/** + * @brief handle OnEventHandle message. + * @param data input param. + * @param reply output param. + * @return Returns ERR_OK on success, others on failure. + */ +int FormSupplyStub::HandleOnEventHandle(MessageParcel &data, MessageParcel &reply) +{ + std::unique_ptr want(data.ReadParcelable()); + if (!want) { + APP_LOGE("%{public}s, failed to ReadParcelable", __func__); + reply.WriteInt32(ERR_INVALID_VALUE); + return ERR_INVALID_VALUE; + } + + int32_t result = OnEventHandle(*want); + reply.WriteInt32(result); + return result; +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_core/src/formmgr/provider_connect_proxy.cpp b/interfaces/innerkits/appexecfwk_core/src/formmgr/provider_connect_proxy.cpp new file mode 100644 index 0000000000..e966e7b095 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/formmgr/provider_connect_proxy.cpp @@ -0,0 +1,107 @@ + +/* + * Copyright (c) 2021 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 "app_log_wrapper.h" +#include "ipc_types.h" +#include "message_parcel.h" +#include "provider_connect_proxy.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @brief OnAbilityConnectDone, AbilityMs notify caller ability the result of connect. + * @param element service ability's ElementName. + * @param remoteObject the session proxy of service ability. + * @param resultCode ERR_OK on success, others on failure. + */ +void ProviderConnectProxy::OnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) +{ + APP_LOGD("%{public}s, abilityName:%{public}s,resultCode:%{public}d", __func__, element.GetAbilityName().c_str(), resultCode); + int error; + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!WriteInterfaceToken(data)) { + APP_LOGE("%{public}s, failed to write interface token", __func__); + return; + } + + if (!data.WriteParcelable(&element)) { + APP_LOGE("%{public}s, failed to write element", __func__); + return; + } + + if (!data.WriteParcelable(remoteObject)) { + APP_LOGE("%{public}s, failed to write remote object ", __func__); + return; + } + + if (!data.WriteInt32(resultCode)) { + APP_LOGE("%{public}s, failed to write resultCode", __func__); + return; + } + + error = Remote()->SendRequest(IAbilityConnection::ON_ABILITY_CONNECT_DONE, data, reply, option); + if (error != ERR_OK) { + APP_LOGE("%{public}s, failed to SendRequest: %{public}d", __func__, error); + return; + } +} +/** + * @brief OnAbilityDisconnectDone, AbilityMs notify caller ability the result of disconnect. + * @param element service ability's ElementName. + * @param resultCode ERR_OK on success, others on failure. + */ +void ProviderConnectProxy::OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode) +{ + APP_LOGD("%{public}s, element:%{public}s, resultCode:%{public}d", __func__, element.GetURI().c_str(), resultCode); + int error; + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!WriteInterfaceToken(data)) { + APP_LOGE("%{public}s, failed to write interface token", __func__); + return; + } + if (!data.WriteParcelable(&element)) { + APP_LOGE("%{public}s, failed to write element", __func__); + return; + } + if (!data.WriteInt32(resultCode)) { + APP_LOGE("%{public}s, failed to write resultCode", __func__); + return; + } + + error = Remote()->SendRequest(IAbilityConnection::ON_ABILITY_DISCONNECT_DONE, data, reply, option); + if (error != ERR_OK) { + APP_LOGE("%{public}s, failed to SendRequest: %{public}d", __func__, error); + return; + } +} + +bool ProviderConnectProxy::WriteInterfaceToken(MessageParcel &data) +{ + if (!data.WriteInterfaceToken(ProviderConnectProxy::GetDescriptor())) { + APP_LOGE("%{public}s, failed to write interface token", __func__); + return false; + } + return true; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_core/src/formmgr/provider_connect_stub.cpp b/interfaces/innerkits/appexecfwk_core/src/formmgr/provider_connect_stub.cpp new file mode 100644 index 0000000000..54323fdac8 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/formmgr/provider_connect_stub.cpp @@ -0,0 +1,74 @@ + +/* + * Copyright (c) 2021 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 "app_log_wrapper.h" +#include "ipc_types.h" +#include "message_parcel.h" +#include "provider_connect_stub.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @brief handle remote request. + * @param data input param. + * @param reply output param. + * @param option message option. + * @return Returns ERR_OK on success, others on failure. + */ +int ProviderConnectStub::OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + std::u16string descriptor = ProviderConnectStub::GetDescriptor(); + std::u16string remoteDescriptor = data.ReadInterfaceToken(); + if (descriptor != remoteDescriptor) { + APP_LOGI("%{public}s failed, local descriptor is not equal to remote", __func__); + return ERR_INVALID_STATE; + } + + auto element = data.ReadParcelable(); + switch (code) { + case IAbilityConnection::ON_ABILITY_CONNECT_DONE: { + if (element == nullptr) { + APP_LOGE("%{public}s failed, callback stub receive element is nullptr", __func__); + return ERR_INVALID_VALUE; + } + auto remoteObject = data.ReadParcelable(); + auto resultCode = data.ReadInt32(); + OnAbilityConnectDone(*element, remoteObject, resultCode); + delete element; + return ERR_OK; + } + case IAbilityConnection::ON_ABILITY_DISCONNECT_DONE: { + if (element == nullptr) { + APP_LOGE("%{public}s failed, callback stub receive element is nullptr", __func__); + return ERR_INVALID_VALUE; + } + auto resultCode = data.ReadInt32(); + OnAbilityDisconnectDone(*element, resultCode); + delete element; + return ERR_OK; + } + default: { + if (element != nullptr) { + delete element; + } + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); + } + } +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/fmskit/BUILD.gn b/interfaces/innerkits/fmskit/BUILD.gn new file mode 100644 index 0000000000..8a3085fa9b --- /dev/null +++ b/interfaces/innerkits/fmskit/BUILD.gn @@ -0,0 +1,63 @@ +# Copyright (c) 2021 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") +SUBSYSTEM_DIR = "//foundation/appexecfwk/standard" + +config("fmskit_config") { + defines = [ + "APP_LOG_TAG = \"FmskitNative\"", + "LOG_DOMAIN = 0xD001151", + ] + + include_dirs = [ "//foundation/appexecfwk/standard/interfaces/innerkits/fmskit/native/include" ] +} +config("public_fmskit_config") { + include_dirs = [ + "$SUBSYSTEM_DIR/common/log/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/formmgr", + "//foundation/aafwk/standard/interfaces/innerkits/want/include", + "//utils/system/safwk/native/include", + ] +} + +# build so +ohos_shared_library("fmskit_native") { + configs = [ ":fmskit_config" ] + public_configs = [ ":public_fmskit_config" ] + sources = [ + "$SUBSYSTEM_DIR/interfaces/innerkits/fmskit/native/src/form_host_client.cpp", + "$SUBSYSTEM_DIR/interfaces/innerkits/fmskit/native/src/form_mgr.cpp", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "$SUBSYSTEM_DIR/common:libappexecfwk_common", + "$SUBSYSTEM_DIR/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "$SUBSYSTEM_DIR/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] + + subsystem_name = "appexecfwk" + part_name = "appexecfwk_standard" +} diff --git a/interfaces/innerkits/fmskit/native/include/form_callback_interface.h b/interfaces/innerkits/fmskit/native/include/form_callback_interface.h new file mode 100644 index 0000000000..458a143986 --- /dev/null +++ b/interfaces/innerkits/fmskit/native/include/form_callback_interface.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_OHOS_FORM_ABILITY_INTERFACE_H +#define FOUNDATION_APPEXECFWK_OHOS_FORM_ABILITY_INTERFACE_H + +#include "form_js_info.h" + +namespace OHOS { +namespace AppExecFwk { +class FormCallbackInterface { +public: + /** + * @brief Update form. + * + * @param formJsInfo Indicates the obtained {@code FormJsInfo} instance. + */ + virtual void ProcessFormUpdate(const FormJsInfo &formJsInfo) = 0; + + /** + * @brief Uninstall form. + * + * @param formId Indicates the ID of the form to uninstall. + */ + virtual void ProcessFormUninstall(const int64_t formId) = 0; + + /** + * @brief Form service death event. + * + */ + virtual void OnDeathReceived() = 0; +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_OHOS_FORM_ABILITY_INTERFACE_H diff --git a/interfaces/innerkits/fmskit/native/include/form_host_client.h b/interfaces/innerkits/fmskit/native/include/form_host_client.h new file mode 100755 index 0000000000..beebbe2c12 --- /dev/null +++ b/interfaces/innerkits/fmskit/native/include/form_host_client.h @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_OHOS_FORM_HOST_CLIENT_H +#define FOUNDATION_APPEXECFWK_OHOS_FORM_HOST_CLIENT_H + +#include +#include +#include +#include +#include "form_callback_interface.h" +#include "form_host_stub.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @class FormHostClient + * The service of the form host. + */ +class HostForms; +class FormHostClient : public FormHostStub { +public: + FormHostClient(); + virtual ~FormHostClient(); + + /** + * @brief Get FormHostClient instance. + * + * @return FormHostClient instance. + */ + static sptr GetInstance(); + + /** + * @brief Add form. + * + * @param formCallback the host's form callback. + * @param formId The Id of the form. + * @return none. + */ + void AddForm(std::shared_ptr formCallback, const int64_t formId); + + /** + * @brief Remove form. + * + * @param formCallback the host's form callback. + * @param formId The Id of the form. + * @return none. + */ + void RemoveForm(std::shared_ptr formCallback, const int64_t formId); + + /** + * @brief Check whether the form exist in the formhosts. + * + * @param formId The Id of the form. + * @return Returns true if contains form; returns false otherwise. + */ + bool ContainsForm(int64_t formId); + + /** + * @brief Request to give back a form. + * + * @param formJsInfo Form js info. + * @return none. + */ + virtual void OnAcquired(const FormJsInfo &formJsInfo); + + /** + * @brief Update form. + * + * @param formJsInfo Form js info. + * @return none. + */ + virtual void OnUpdate(const FormJsInfo &formJsInfo); + + /** + * @brief UnInstall the forms. + * + * @param formIds The Id of the forms. + * @return none. + */ + virtual void OnUninstall(const std::vector &formIds); + +private: + static sptr instance_; + static std::mutex instanceMutex_; + mutable std::mutex lockMutex_; + std::vector keyVector_; + std::map> recordCallback_; + std::map recordHostForms_; + int32_t key_ = 0; + +private: + /** + * @brief Find callback by formId. + * + * @param formId The Id of the form. + * @return target callback + */ + std::shared_ptr FindTargetCallback(int64_t formId); + + /** + * @brief Find Key By form callback. + * + * @param formCallback The form callback. + * @return callback's key + */ + int32_t FindKeyByCallback(std::shared_ptr formCallback); + + /** + * @brief Compare callback. + * + * @param formCallback1 The form callback1. + * @param formCallback2 The callback to be compared with form callback1. + * @return Returns true if the two callback are equal to each other, returns false otherwise. + */ + bool Compare(std::shared_ptr formCallback1, std::shared_ptr formCallback2); + + DISALLOW_COPY_AND_MOVE(FormHostClient); +}; + +class HostForms { +public: + /** + * @brief Add form by formId. + * + * @param formId The Id of the form. + */ + void AddForm(const int64_t formId) + { + std::map::iterator it = forms_.find(formId); + if (it != forms_.end()) { + return; + } + forms_.insert(std::pair(formId, true)); + } + + /** + * @brief Delete form by formId. + * + * @param formId The Id of the form. + */ + void DelForm(const int64_t formId) + { + forms_.erase(formId); + } + + /** + * @brief Check whether the form is empty. + */ + bool IsEmpty() + { + return forms_.empty(); + } + + /** + * @brief Check whether the form exist in the forms. + * + * @param formId The Id of the form. + * @return Returns true if contains form; returns false otherwise. + */ + bool Contains(const int64_t formId) + { + std::map::iterator it = forms_.find(formId); + return (it == forms_.end()) ? false : true; + } + +private: + std::map forms_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_OHOS_FORM_HOST_CLIENT_H diff --git a/interfaces/innerkits/fmskit/native/include/form_mgr.h b/interfaces/innerkits/fmskit/native/include/form_mgr.h new file mode 100644 index 0000000000..4eaca5087e --- /dev/null +++ b/interfaces/innerkits/fmskit/native/include/form_mgr.h @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_OHOS_FORM_MGR_H +#define FOUNDATION_APPEXECFWK_OHOS_FORM_MGR_H + +#include +#include + +#include "form_callback_interface.h" +#include "form_constants.h" +#include "form_death_callback.h" +#include "form_js_info.h" +#include "form_mgr_interface.h" +#include "form_provider_data.h" +#include "iremote_object.h" +#include "want.h" + +namespace OHOS { +namespace AppExecFwk { +using OHOS::AAFwk::Want; + +static volatile int recoverStatus_ = Constants::NOT_IN_RECOVERY; + +/** + * @class FormMgr + * FormMgr is used to access form manager services. + */ +class FormMgr final : public DelayedRefSingleton { + DECLARE_DELAYED_REF_SINGLETON(FormMgr) +public: + DISALLOW_COPY_AND_MOVE(FormMgr); + + /** + * @brief Add form with want, send want to form manager service. + * @param formId The Id of the forms to add. + * @param want The want of the form to add. + * @param callerToken Caller ability token. + * @param formInfo Form info. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int AddForm(const int64_t formId, const Want &want, const sptr &callerToken, + FormJsInfo &formInfo); + + /** + * @brief Delete forms with formIds, send formIds to form manager service. + * @param formId The Id of the forms to delete. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + int DeleteForm(const int64_t formId, const sptr &callerToken); + + /** + * @brief Release forms with formIds, send formIds to form manager service. + * @param formId The Id of the forms to release. + * @param callerToken Caller ability token. + * @param delCache Delete Cache or not. + * @return Returns ERR_OK on success, others on failure. + */ + int ReleaseForm(const int64_t formId, const sptr &callerToken, const bool delCache); + + /** + * @brief Update form with formId, send formId to form manager service. + * @param formId The Id of the form to update. + * @param bundleName Provider ability bundleName. + * @param formBindingData Form binding data. + * @return Returns ERR_OK on success, others on failure. + */ + int UpdateForm(const int64_t formId, const std::string &bundleName, const FormProviderData &formBindingData); + + /** + * @brief Notify the form service that the form user's lifecycle is updated. + * + * This should be called when form user request form. + * + * @param formId Indicates the unique id of form. + * @param callerToken Indicates the callback remote object of specified form user. + * @param want information passed to supplier. + * @return Returns true if execute success, false otherwise. + */ + int RequestForm(const int64_t formId, const sptr &callerToken, const Want &want); + + /** + * @brief Form visible/invisible notify, send formIds to form manager service. + * @param formIds The Id list of the forms to notify. + * @param callerToken Caller ability token. + * @param formVisibleType The form visible type, including FORM_VISIBLE and FORM_INVISIBLE. + * @return Returns ERR_OK on success, others on failure. + */ + int NotifyWhetherVisibleForms(const std::vector &formIds, const sptr &callerToken, + const int32_t formVisibleType); + + /** + * @brief temp form to normal form. + * @param formId The Id of the form. + * @param callerToken Caller ability token. + * @return None. + */ + int CastTempForm(const int64_t formId, const sptr &callerToken); + + /** + * @brief Dump all of form storage infos. + * @param formInfos All of form storage infos. + * @return Returns ERR_OK on success, others on failure. + */ + int DumpStorageFormInfos(std::string &formInfos); + /** + * @brief Dump form info by a bundle name. + * @param bundleName The bundle name of form provider. + * @param formInfos Form infos. + * @return Returns ERR_OK on success, others on failure. + */ + int DumpFormInfoByBundleName(const std::string bundleName, std::string &formInfos); + /** + * @brief Dump form info by a bundle name. + * @param formId The id of the form. + * @param formInfo Form info. + * @return Returns ERR_OK on success, others on failure. + */ + int DumpFormInfoByFormId(const std::int64_t formId, std::string &formInfo); + /** + * @brief Process js message event. + * @param formId Indicates the unique id of form. + * @param want information passed to supplier. + * @param callerToken Caller ability token. + * @return Returns true if execute success, false otherwise. + */ + int MessageEvent(const int64_t formId, const Want &want, const sptr &callerToken); + + /** + * @brief Get fms recoverStatus. + * + * @return The current recover status. + */ + static int GetRecoverStatus(); + + /** + * @brief Register death callback. + * + * @param formDeathCallback The death callback. + */ + void RegisterDeathCallback(const std::shared_ptr &formDeathCallback); + + /** + * @brief UnRegister death callback. + * + * @param formDeathCallback The death callback. + */ + void UnRegisterDeathCallback(const std::shared_ptr &formDeathCallback); + + int SetNextRefreshTime(const int64_t formId, const int64_t nextTime); + + /** + * @brief Lifecycle Update. + * @param formIds The id of the forms. + * @param callerToken Host client. + * @param updateType Next refresh time. + * @return Returns ERR_OK on success, others on failure. + */ + int LifecycleUpdate(const std::vector &formIds, const sptr &callerToken, + const int32_t updateType); + + /** + * @brief Set fms recoverStatus. + * + * @param recoverStatus The recover status. + */ + static void SetRecoverStatus(int recoverStatus); + + /** + * @brief Set form mgr service for test. + */ + void SetFormMgrService(sptr formMgrService); + + /** + * @brief Get death recipient. + * @return deathRecipient_. + */ + sptr GetDeathRecipient() const; + + /** + * @brief Check whether the specified death callback is registered in form mgr. + * @param formDeathCallback The specified death callback for checking. + * @return Return true on success, false on failure. + */ + bool CheckIsDeathCallbackRegistered(const std::shared_ptr &formDeathCallback); + +private: + /** + * @brief Connect form manager service. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode Connect(); + + /** + * @brief Reconnect form manager service once per 1000 milliseconds, + * until the connection succeeds or reaching the max retry times. + * @return Returns true if execute success, false otherwise. + */ + bool Reconnect(); + /** + * @brief Reset proxy. + * @param remote remote object. + */ + void ResetProxy(const wptr &remote); + +public: + friend class FormMgrDeathRecipient; + +private: + /** + * @class FormMgrDeathRecipient + * FormMgrDeathRecipient notices IRemoteBroker died. + */ + class FormMgrDeathRecipient : public IRemoteObject::DeathRecipient { + public: + FormMgrDeathRecipient() = default; + ~FormMgrDeathRecipient() = default; + + /** + * @brief Notices IRemoteBroker died. + * @param remote remote object. + */ + void OnRemoteDied(const wptr &remote) override; + private: + DISALLOW_COPY_AND_MOVE(FormMgrDeathRecipient); + }; + + std::mutex connectMutex_; + sptr remoteProxy_; + + sptr deathRecipient_ {nullptr}; + + // True: need to get a new fms remote object, + // False: no need to get a new fms remote object. + volatile bool resetFlag_ = false; + + std::vector> formDeathCallbacks_; +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_OHOS_FORM_MGR_H \ No newline at end of file diff --git a/interfaces/innerkits/fmskit/native/src/form_host_client.cpp b/interfaces/innerkits/fmskit/native/src/form_host_client.cpp new file mode 100755 index 0000000000..a506bb158d --- /dev/null +++ b/interfaces/innerkits/fmskit/native/src/form_host_client.cpp @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2021 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 "app_log_wrapper.h" +#include "form_host_client.h" + +namespace OHOS { +namespace AppExecFwk { +sptr FormHostClient::instance_ = nullptr; +std::mutex FormHostClient::instanceMutex_; + +FormHostClient::FormHostClient() +{ +} + +FormHostClient::~FormHostClient() +{ +} + +/** + * @brief Get FormHostClient instance. + * + * @return FormHostClient instance. + */ +sptr FormHostClient::GetInstance() +{ + if (instance_ == nullptr) { + std::lock_guard lock_l(instanceMutex_); + if (instance_ == nullptr) { + instance_ = new FormHostClient(); + } + } + return instance_; +} + +/** + * @brief Add form. + * + * @param formCallback the host's form callback. + * @param formId The Id of the form. + * @return none. + */ +void FormHostClient::AddForm(std::shared_ptr formCallback, const int64_t formId) +{ + APP_LOGI("%{public}s called.", __func__); + + if (formId <= 0) { + APP_LOGE("%{public}s error, the passed form id can't be negative or zero.", __func__); + return; + } + + { + std::lock_guard lock(lockMutex_); + int64_t key = FindKeyByCallback(formCallback); + if (key == -1) { + HostForms hostForms; + int64_t tempKey = key_; + if (!keyVector_.empty()) { + tempKey = keyVector_.back(); + keyVector_.pop_back(); + } + hostForms.AddForm(formId); + recordCallback_.insert(std::make_pair(tempKey, formCallback)); + recordHostForms_.insert(std::make_pair(tempKey, hostForms)); + + if (tempKey == key_) { + key_++; + } + } else { + recordHostForms_[key].AddForm(formId); + } + } +} + +/** + * @brief Remove form. + * + * @param formCallback the host's form callback. + * @param formId The Id of the form. + * @return none. + */ +void FormHostClient::RemoveForm(std::shared_ptr formCallback, const int64_t formId) +{ + APP_LOGI("%{public}s called.", __func__); + + if (formId <= 0 || formCallback == nullptr) { + APP_LOGE("%{public}s, invalid param.", __func__); + return; + } + + { + std::lock_guard lock(lockMutex_); + int64_t key = FindKeyByCallback(formCallback); + if(key == -1) { + APP_LOGE("%{public}s, failed to find callback.", __func__); + return; + } + + if (recordHostForms_[key].IsEmpty()) { + recordCallback_.erase(key); + recordHostForms_.erase(key); + keyVector_.push_back(key); + APP_LOGI("%{public}s, clear data.", __func__); + return; + } + + recordHostForms_[key].DelForm(formId); + if (recordHostForms_[key].IsEmpty()) { + recordCallback_.erase(key); + recordHostForms_.erase(key); + keyVector_.push_back(key); + APP_LOGI("%{public}s, clear data.", __func__); + } + } + APP_LOGI("%{public}s end.", __func__); +} + +/** + * @brief Check whether the form exist in the formhosts. + * + * @param formId The Id of the form. + * @return Returns true if contains form; returns false otherwise. + */ +bool FormHostClient::ContainsForm(int64_t formId) +{ + APP_LOGI("%{public}s called.", __func__); + + std::lock_guard lock(lockMutex_); + for (auto recordHostForm : recordHostForms_) { + if (recordHostForm.second.Contains(formId)) { + return true; + } + } + return false; +} + +/** + * @brief Request to give back a form. + * + * @param formJsInfo Form js info. + * @return none. + */ +void FormHostClient::OnAcquired(const FormJsInfo &formJsInfo) +{ + APP_LOGI("%{public}s called.", __func__); + int64_t formId = formJsInfo.formId; + if (formId < 0) { + APP_LOGE("%{public}s error, the passed form id can't be negative.", __func__); + return; + } + std::shared_ptr targetCallback = FindTargetCallback(formId); + if (targetCallback == nullptr) { + APP_LOGE("%{public}s error, can't find target callback. formId: %{public}lld.", __func__, formId); + return; + } + APP_LOGI("%{public}s, formId: %{public}lld, data: %{public}s", __func__, formId, formJsInfo.formData.c_str()); + targetCallback->ProcessFormUpdate(formJsInfo); +} + +/** + * @brief Update form. + * + * @param formJsInfo Form js info. + * @return none. + */ +void FormHostClient::OnUpdate(const FormJsInfo &formJsInfo) +{ + APP_LOGI("%{public}s called.", __func__); + int64_t formId = formJsInfo.formId; + if (formId < 0) { + APP_LOGE("%{public}s error, the passed form id can't be negative.", __func__); + return; + } + std::shared_ptr targetCallback = FindTargetCallback(formId); + if (targetCallback == nullptr) { + APP_LOGE("%{public}s error, can't find target callback. formId: %{public}lld.", __func__, formId); + return; + } + targetCallback->ProcessFormUpdate(formJsInfo); +} + +/** + * @brief UnInstall the forms. + * + * @param formIds The Id of the forms. + * @return none. + */ +void FormHostClient::OnUninstall(const std::vector &formIds) +{ + APP_LOGI("%{public}s called.", __func__); + if (formIds.size() <= 0) { + APP_LOGE("%{public}s error, formIds is empty.", __func__); + return; + } + for(auto &formId : formIds) { + if (formId < 0) { + APP_LOGE("%{public}s error, the passed form id can't be negative.", __func__); + continue; + } + std::shared_ptr targetCallback = FindTargetCallback(formId); + if (targetCallback == nullptr) { + APP_LOGE("%{public}s error, can't find target callback. formId: %{public}lld.", __func__, formId); + continue; + } + targetCallback->ProcessFormUninstall(formId); + } +} + +/** + * @brief Find callback by formId. + * + * @param formId The Id of the form. + * @return target callback + */ +std::shared_ptr FormHostClient::FindTargetCallback(int64_t formId) +{ + std::lock_guard lock(lockMutex_); + for (auto record : recordHostForms_) { + if (record.second.Contains(formId)) { + return recordCallback_[record.first]; + } + } + return nullptr; +} + +/** + * @brief Find Key By form callback. + * + * @param formCallback The form callback. + * @return callback's key + */ +int32_t FormHostClient::FindKeyByCallback(std::shared_ptr formCallback) +{ + for (auto recordCallback : recordCallback_) { + if (Compare(recordCallback.second, formCallback)) { + return recordCallback.first; + } + } + return -1; +} + +/** + * @brief Compare form callback. + * + * @param formCallback1 The form callback. + * @param formCallback2 The form callback to be compared with form callback1. + * @return Returns true if the two form callback are equal to each other, returns false otherwise. + */ +bool FormHostClient::Compare(std::shared_ptr formCallback1, + std::shared_ptr formCallback2) +{ + return (formCallback1 == formCallback2) ? true : false; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/fmskit/native/src/form_mgr.cpp b/interfaces/innerkits/fmskit/native/src/form_mgr.cpp new file mode 100644 index 0000000000..6531c5afe7 --- /dev/null +++ b/interfaces/innerkits/fmskit/native/src/form_mgr.cpp @@ -0,0 +1,488 @@ +/* + * Copyright (c) 2021 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 "appexecfwk_errors.h" +#include "app_log_wrapper.h" +#include "form_mgr.h" +#include "if_system_ability_manager.h" +#include "ipc_skeleton.h" +#include "iservice_registry.h" +#include "string_ex.h" +#include "system_ability_definition.h" + +namespace OHOS { +namespace AppExecFwk { +FormMgr::FormMgr(){} +FormMgr::~FormMgr() +{ + if (remoteProxy_ != nullptr) { + auto remoteObject = remoteProxy_->AsObject(); + if (remoteObject != nullptr) { + remoteObject->RemoveDeathRecipient(deathRecipient_); + } + } +} +/** + * @brief Add form with want, send want to form manager service. + * @param formId The Id of the forms to add. + * @param want The want of the form to add. + * @param callerToken Caller ability token. + * @param formInfo Form info. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgr::AddForm(const int64_t formId, const Want &want, const sptr &callerToken, +FormJsInfo &formInfo) +{ + APP_LOGI("%{public}s called.", __func__); + + int errCode = Connect(); + if (errCode != ERR_OK) { + return errCode; + } + + return remoteProxy_->AddForm(formId, want, callerToken, formInfo); +} + +/** + * @brief Delete forms with formIds, send formIds to form manager service. + * @param formId The Id of the forms to delete. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgr::DeleteForm(const int64_t formId, const sptr &callerToken) +{ + APP_LOGI("%{public}s called.", __func__); + + int errCode = Connect(); + if (errCode != ERR_OK) { + return errCode; + } + + return remoteProxy_->DeleteForm(formId, callerToken); +} + +/** + * @brief Release forms with formIds, send formIds to form manager service. + * @param formId The Id of the forms to release. + * @param callerToken Caller ability token. + * @param delCache Delete Cache or not. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgr::ReleaseForm(const int64_t formId, const sptr &callerToken, const bool delCache) +{ + APP_LOGI("%{public}s called.", __func__); + + int errCode = Connect(); + if (errCode != ERR_OK) { + return errCode; + } + + return remoteProxy_->ReleaseForm(formId, callerToken, delCache); +} + +/** + * @brief Update form with formId, send formId to form manager service. + * @param formId The Id of the form to update. + * @param bundleName Provider ability bundleName. + * @param formBindingData Form binding data. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgr::UpdateForm(const int64_t formId, const std::string &bundleName, const FormProviderData &formBindingData) +{ + APP_LOGI("%{public}s called.", __func__); + + int errCode = Connect(); + if (errCode != ERR_OK) { + return errCode; + } + + // update form + return remoteProxy_->UpdateForm(formId, bundleName, formBindingData); +} + +/** + * @brief Notify the form service that the form user's lifecycle is updated. + * + * This should be called when form user request form. + * + * @param formId Indicates the unique id of form. + * @param callerToken Indicates the callback remote object of specified form user. + * @param want information passed to supplier. + * @return Returns true if execute success, false otherwise. + */ +int FormMgr::RequestForm(const int64_t formId, const sptr &callerToken, const Want &want) +{ + APP_LOGI("%{public}s called.", __func__); + + int errCode = Connect(); + if (errCode != ERR_OK) { + return errCode; + } + + return remoteProxy_->RequestForm(formId, callerToken, want); +} + +/** + * @brief Form visible/invisible notify, send formIds to form manager service. + * @param formIds The Id list of the forms to notify. + * @param callerToken Caller ability token. + * @param formVisibleType The form visible type, including FORM_VISIBLE and FORM_INVISIBLE. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgr::NotifyWhetherVisibleForms(const std::vector &formIds, const sptr &callerToken, +const int32_t formVisibleType) +{ + int errCode = Connect(); + if (errCode != ERR_OK) { + return errCode; + } + + return remoteProxy_->NotifyWhetherVisibleForms(formIds, callerToken, formVisibleType); +} + +/** + * @brief temp form to normal form. + * @param formId The Id of the form. + * @param callerToken Caller ability token. + * @return None. + */ +int FormMgr::CastTempForm(const int64_t formId, const sptr &callerToken) +{ + APP_LOGI("%{public}s called.", __func__); + + int errCode = Connect(); + if (errCode != ERR_OK) { + return errCode; + } + + return remoteProxy_->CastTempForm(formId, callerToken); +} + +/** + * @brief Dump all of form storage infos. + * @param formInfos All of form storage infos. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgr::DumpStorageFormInfos(std::string &formInfos) +{ + int errCode = Connect(); + if (errCode != ERR_OK) { + return errCode; + } + + return remoteProxy_->DumpStorageFormInfos(formInfos); +} +/** + * @brief Dump form info by a bundle name. + * @param bundleName The bundle name of form provider. + * @param formInfos Form infos. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgr::DumpFormInfoByBundleName(const std::string bundleName, std::string &formInfos) +{ + int errCode = Connect(); + if (errCode != ERR_OK) { + return errCode; + } + + return remoteProxy_->DumpFormInfoByBundleName(bundleName, formInfos); +} +/** + * @brief Dump form info by a bundle name. + * @param formId The id of the form. + * @param formInfo Form info. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgr::DumpFormInfoByFormId(const std::int64_t formId, std::string &formInfo) +{ + int errCode = Connect(); + if (errCode != ERR_OK) { + return errCode; + } + + return remoteProxy_->DumpFormInfoByFormId(formId, formInfo); +} +/** + * @brief Process js message event. + * @param formId Indicates the unique id of form. + * @param want information passed to supplier. + * @param callerToken Caller ability token. + * @return Returns true if execute success, false otherwise. + */ +int FormMgr::MessageEvent(const int64_t formId, const Want &want, const sptr &callerToken) +{ + int errCode = Connect(); + if (errCode != ERR_OK) { + return errCode; + } + + return remoteProxy_->MessageEvent(formId, want, callerToken); +} + +/** + * @brief Set Next Refresh Time. + * @param formId The id of the form. + * @param bundleName The bundle name of form provider. + * @param nextTime Next refresh time. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgr::SetNextRefreshTime(const int64_t formId, const int64_t nextTime) +{ + int errCode = Connect(); + if (errCode != ERR_OK) { + return errCode; + } + + return remoteProxy_->SetNextRefreshTime(formId, nextTime); +} + +/** + * @brief Lifecycle Update. + * @param formIds The id of the forms. + * @param callerToken Host client. + * @param updateType Next refresh time. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgr::LifecycleUpdate(const std::vector &formIds, const sptr &callerToken, +const int32_t updateType) +{ + int errCode = Connect(); + if (errCode != ERR_OK) { + return errCode; + } + + return remoteProxy_->LifecycleUpdate(formIds, callerToken, updateType); +} +/** + * @brief Get fms recoverStatus. + * + * @return The current recover status. + */ +int FormMgr::GetRecoverStatus() +{ + APP_LOGI("%{public}s called.", __func__); + + return recoverStatus_; +} + +/** + * @brief Set fms recoverStatus. + * + * @param recoverStatus The recover status. + */ +void FormMgr::SetRecoverStatus(int recoverStatus) +{ + APP_LOGI("%{public}s called.", __func__); + + recoverStatus_ = recoverStatus; +} + +/** + * @brief Register death callback. + * + * @param deathCallback Death callback. + */ +void FormMgr::RegisterDeathCallback(const std::shared_ptr &formDeathCallback) +{ + APP_LOGI("%{public}s called.", __func__); + + if (formDeathCallback == nullptr) { + APP_LOGE("%{public}s error, form death callback is nullptr.", __func__); + return; + } + + formDeathCallbacks_.emplace_back(formDeathCallback); +} + +/** + * @brief UnRegister death callback. + * + * @param deathCallback Death callback. + */ +void FormMgr::UnRegisterDeathCallback(const std::shared_ptr &formDeathCallback) +{ + APP_LOGI("%{public}s called.", __func__); + + if (formDeathCallback == nullptr) { + APP_LOGE("%{public}s error, form death callback is nullptr.", __func__); + return; + } + + // Remove the specified death callback in the vector of death callback + auto iter = std::find(formDeathCallbacks_.begin(), formDeathCallbacks_.end(), formDeathCallback); + if (iter != formDeathCallbacks_.end()) { + formDeathCallbacks_.erase(iter); + } + APP_LOGI("%{public}s end.", __func__); +} + +/** + * @brief Get death recipient. + * @return deathRecipient_. + */ +sptr FormMgr::GetDeathRecipient() const +{ + return deathRecipient_; +} + +/** + * @brief Check whether the specified death callback is registered in form mgr. + * @param formDeathCallback The specified death callback for checking. + * @return Return true on success, false on failure. + */ +bool FormMgr::CheckIsDeathCallbackRegistered(const std::shared_ptr &formDeathCallback) +{ + APP_LOGI("%{public}s called.", __func__); + + auto iter = std::find(formDeathCallbacks_.begin(), formDeathCallbacks_.end(), formDeathCallback); + if (iter != formDeathCallbacks_.end()) { + return true; + } + + return false; +} + +/** + * @brief Notices IRemoteBroker died. + * @param remote remote object. + */ +void FormMgr::FormMgrDeathRecipient::OnRemoteDied(const wptr &remote) +{ + APP_LOGI("%{public}s called.", __func__); + + if (remote == nullptr) { + APP_LOGE("%{public}s failed, remote is nullptr.", __func__); + return; + } + + if (FormMgr::GetInstance().GetRecoverStatus() == Constants::IN_RECOVERING) { + APP_LOGW("%{public}s, fms in recovering.", __func__); + return; + } + // Reset proxy + FormMgr::GetInstance().ResetProxy(remote); + + if (!FormMgr::GetInstance().Reconnect()) { + APP_LOGE("%{public}s, form mgr service died, try to reconnect to fms failed.", __func__); + FormMgr::GetInstance().SetRecoverStatus(Constants::RECOVER_FAIL); + return; + } + + // refresh form host. + for (auto &deathCallback : FormMgr::GetInstance().formDeathCallbacks_) { + deathCallback->OnDeathReceived(); + } + FormMgr::GetInstance().SetRecoverStatus(Constants::NOT_IN_RECOVERY); +} + +/** + * @brief Reconnect form manager service once per 1000 milliseconds, + * until the connection succeeds or reaching the max retry times. + * @return Returns true if execute success, false otherwise. + */ +bool FormMgr::Reconnect() +{ + APP_LOGI("%{public}s called.", __func__); + + for (int i = 0; i < Constants::MAX_RETRY_TIME; i++) { + // Sleep 1000 milliseconds before reconnect. + std::this_thread::sleep_for(std::chrono::milliseconds(Constants::SLEEP_TIME)); + + // try to connect fms + if (Connect() != ERR_OK) { + APP_LOGE("%{public}s, get fms proxy fail, try again.", __func__); + continue; + } + + APP_LOGI("%{public}s, get fms proxy success.", __func__); + return true; + } + + return false; +} + +/** + * @brief Connect form manager service. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormMgr::Connect() +{ + std::lock_guard lock(connectMutex_); + if (remoteProxy_ != nullptr && !resetFlag_) { + return ERR_OK; + } + + sptr systemManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (systemManager == nullptr) { + APP_LOGE("%{private}s:fail to get registry", __func__); + return ERR_APPEXECFWK_FORM_GET_SYSMGR_FAILED; + } + sptr remoteObject = systemManager->GetSystemAbility(FORM_MGR_SERVICE_ID); + if (remoteObject == nullptr) { + APP_LOGE("%{private}s:fail to connect FormMgrService", __func__); + return ERR_APPEXECFWK_FORM_GET_FMS_FAILED; + } + deathRecipient_ = sptr(new FormMgrDeathRecipient()); + if (deathRecipient_ == nullptr) { + APP_LOGE("%{public}s :Failed to create FormMgrDeathRecipient!", __func__); + return ERR_NO_MEMORY; + } + if ((remoteObject->IsProxyObject()) && (!remoteObject->AddDeathRecipient(deathRecipient_))) { + APP_LOGE("%{public}s :Add death recipient to FormMgrService failed.", __func__); + return ERR_APPEXECFWK_FORM_ADD_DEATH_RECIPIENT_FAILED; + } + + remoteProxy_ = iface_cast(remoteObject); + APP_LOGD("%{public}s :Connecting FormMgrService success.", __func__); + return ERR_OK; +} + +/** + * @brief Reset proxy. + * @param remote remote object. + */ +void FormMgr::ResetProxy(const wptr &remote) +{ + APP_LOGI("%{public}s called.", __func__); + + std::lock_guard lock(connectMutex_); + if (remoteProxy_ == nullptr) { + APP_LOGE("%{public}s failed, remote proxy is nullptr.", __func__); + return; + } + + // set formMgr's recover status to IN_RECOVERING. + recoverStatus_ = Constants::IN_RECOVERING; + + // remove the death recipient + auto serviceRemote = remoteProxy_->AsObject(); + if ((serviceRemote != nullptr) && (serviceRemote == remote.promote())) { + serviceRemote->RemoveDeathRecipient(deathRecipient_); + } + // clearn the remote proxy + remoteProxy_ = nullptr; +} + +/** + * @brief Set form mgr service for test. + */ +void FormMgr::SetFormMgrService(sptr formMgrService) +{ + APP_LOGI("%{public}s called.", __func__); + remoteProxy_ = formMgrService; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/task_dispatcher/include/dispatcher/blocking_queue.h b/interfaces/innerkits/task_dispatcher/include/dispatcher/blocking_queue.h index 64d9111fd2..74d6605ba8 100644 --- a/interfaces/innerkits/task_dispatcher/include/dispatcher/blocking_queue.h +++ b/interfaces/innerkits/task_dispatcher/include/dispatcher/blocking_queue.h @@ -80,7 +80,7 @@ public: { std::unique_lock lock(mutex_); while (queue_.empty() && !stopFlag_) { - APP_LOGD("BlockingQueue::Take empty_wait"); + APP_LOGI("BlockingQueue::Take empty_wait"); empty_.wait(lock); } @@ -98,7 +98,7 @@ public: std::unique_lock lock(mutex_); while (queue_.empty() && !stopFlag_) { if (empty_.wait_until(lock, timeout) == std::cv_status::timeout) { - APP_LOGD("BlockingQueue::Poll timeout"); + APP_LOGI("BlockingQueue::Poll timeout"); break; } } diff --git a/interfaces/innerkits/task_dispatcher/include/dispatcher/global_task_dispatcher.h b/interfaces/innerkits/task_dispatcher/include/dispatcher/global_task_dispatcher.h index 20706e4112..01479ebc4a 100644 --- a/interfaces/innerkits/task_dispatcher/include/dispatcher/global_task_dispatcher.h +++ b/interfaces/innerkits/task_dispatcher/include/dispatcher/global_task_dispatcher.h @@ -24,8 +24,6 @@ namespace OHOS { namespace AppExecFwk { /** * Dispatcher for global thread model. - * - * */ class GlobalTaskDispatcher : public ParallelTaskDispatcherBase { private: diff --git a/interfaces/innerkits/task_dispatcher/include/dispatcher/parallel_task_dispatcher.h b/interfaces/innerkits/task_dispatcher/include/dispatcher/parallel_task_dispatcher.h index 09673a88cd..57e9a5598e 100644 --- a/interfaces/innerkits/task_dispatcher/include/dispatcher/parallel_task_dispatcher.h +++ b/interfaces/innerkits/task_dispatcher/include/dispatcher/parallel_task_dispatcher.h @@ -32,13 +32,9 @@ namespace OHOS { namespace AppExecFwk { /** * Customed parallel TaskDispatcher which means it can be created multi times. - * - * */ class ParallelTaskDispatcher : public ParallelTaskDispatcherBase { public: - // ParallelTaskDispatcher(); - ParallelTaskDispatcher(const std::string &name, TaskPriority priority, std::shared_ptr &executor); ~ParallelTaskDispatcher(){}; diff --git a/interfaces/innerkits/task_dispatcher/include/dispatcher/parallel_task_dispatcher_base.h b/interfaces/innerkits/task_dispatcher/include/dispatcher/parallel_task_dispatcher_base.h index 8eac6d8887..22b248f0df 100644 --- a/interfaces/innerkits/task_dispatcher/include/dispatcher/parallel_task_dispatcher_base.h +++ b/interfaces/innerkits/task_dispatcher/include/dispatcher/parallel_task_dispatcher_base.h @@ -35,14 +35,10 @@ namespace OHOS { namespace AppExecFwk { /** * Base implementation for parallel TaskDispatcher - * - * */ class ParallelTaskDispatcherBase : public BaseTaskDispatcher, public std::enable_shared_from_this { public: - // ParallelTaskDispatcherBase(); - ParallelTaskDispatcherBase( TaskPriority taskPriority, std::shared_ptr &executor, const std::string &dispatcherName); virtual ~ParallelTaskDispatcherBase() = default; @@ -108,7 +104,7 @@ private: void OnChanged(const TaskStage &stage) { if (stage.IsDone()) { - APP_LOGD("task done."); + APP_LOGI("ParallelTaskDispatcherBase task done."); callback_(); } } diff --git a/interfaces/innerkits/task_dispatcher/include/dispatcher/serial_task_dispatcher.h b/interfaces/innerkits/task_dispatcher/include/dispatcher/serial_task_dispatcher.h index ef51a1f030..9388e9ce0c 100644 --- a/interfaces/innerkits/task_dispatcher/include/dispatcher/serial_task_dispatcher.h +++ b/interfaces/innerkits/task_dispatcher/include/dispatcher/serial_task_dispatcher.h @@ -33,8 +33,6 @@ namespace AppExecFwk { /** * Dispatcher for serial thread model. - * - * */ class SerialTaskDispatcher : public BaseTaskDispatcher, public std::enable_shared_from_this { private: @@ -123,7 +121,7 @@ public: /** * Called when post a task group to the TaskDispatcher and without waiting * - * @param runnable is the job to execute + * @param runnable is the job to execute * @param delayMs indicate the delay time to execute * @return an interface for revoke the task if it hasn't been invoked. * diff --git a/interfaces/innerkits/task_dispatcher/include/dispatcher/spec_task_dispatcher.h b/interfaces/innerkits/task_dispatcher/include/dispatcher/spec_task_dispatcher.h index b3f5a22676..8052d0d6b6 100644 --- a/interfaces/innerkits/task_dispatcher/include/dispatcher/spec_task_dispatcher.h +++ b/interfaces/innerkits/task_dispatcher/include/dispatcher/spec_task_dispatcher.h @@ -29,18 +29,13 @@ namespace OHOS { namespace AppExecFwk { class EventRunner; -/** - * Dispatcher for specific thread model like UI / Main / IO and so on. - * - * - */ class SpecTaskDispatcher : public BaseTaskDispatcher, public std::enable_shared_from_this { public: /** * constructor for special task dispatchers * * @param config which is the config of this dispatcher - * @param looper task looper + * @param runner event runner * */ SpecTaskDispatcher(std::shared_ptr config, std::shared_ptr runner); @@ -50,7 +45,7 @@ public: * Called when post a task to the TaskDispatcher with waiting Attention: Call * this function of Specific dispatcher on the corresponding thread will lock. * - * @param task is the job to execute + * @param runnable is the job to execute * */ ErrCode SyncDispatch(const std::shared_ptr &runnable); @@ -58,7 +53,7 @@ public: /** * Called when post a task to the TaskDispatcher without waiting * - * @param task is the job to execute + * @param runnable is the job to execute * @return an interface for revoke the task if it hasn't been invoked. * */ @@ -67,7 +62,7 @@ public: /** * Called when post a task group to the TaskDispatcher and without waiting * - * @param task is the job to execute + * @param runnable is the job to execute * @param delayMs indicate the delay time in milliseconds to execute * @return an interface for revoke the task if it hasn't been invoked. * diff --git a/interfaces/innerkits/task_dispatcher/include/dispatcher/task_dispatcher_context.h b/interfaces/innerkits/task_dispatcher/include/dispatcher/task_dispatcher_context.h index 0d8ee8edd8..c7516d2b1f 100644 --- a/interfaces/innerkits/task_dispatcher/include/dispatcher/task_dispatcher_context.h +++ b/interfaces/innerkits/task_dispatcher/include/dispatcher/task_dispatcher_context.h @@ -34,8 +34,6 @@ namespace OHOS { namespace AppExecFwk { /** * Dispatcher management for all kinds dispatchers and executor. - * - * */ class TaskDispatcherContext { public: diff --git a/interfaces/innerkits/task_dispatcher/include/task/barrier_handler.h b/interfaces/innerkits/task_dispatcher/include/task/barrier_handler.h index 89bb5cdf2a..a8f5d070aa 100644 --- a/interfaces/innerkits/task_dispatcher/include/task/barrier_handler.h +++ b/interfaces/innerkits/task_dispatcher/include/task/barrier_handler.h @@ -68,7 +68,7 @@ private: void OnChanged(const TaskStage &stage) { if (stage.IsDone()) { - APP_LOGI("task done."); + APP_LOGI("BarrierHandler task done."); callback_(); } }; diff --git a/interfaces/innerkits/task_dispatcher/include/task/sync_task.h b/interfaces/innerkits/task_dispatcher/include/task/sync_task.h index 6c2cca11bd..7a53ff8222 100644 --- a/interfaces/innerkits/task_dispatcher/include/task/sync_task.h +++ b/interfaces/innerkits/task_dispatcher/include/task/sync_task.h @@ -34,27 +34,11 @@ namespace AppExecFwk { class SyncTask final : public Task { public: - /** - *@brief Constructs the object. - *@param runnable The task. - *@param priority The priority - *@return - - */ SyncTask(const std::shared_ptr &runnable, TaskPriority priority, const std::shared_ptr &baseTaskDispatcher); - /** - *@brief invoke the function to execute the task - *@param - - *@return void - */ void Run() override; - /** - *@brief wait the task to run completely - *@param - - *@return void - */ void WaitTask(); private: diff --git a/interfaces/innerkits/task_dispatcher/include/task/task.h b/interfaces/innerkits/task_dispatcher/include/task/task.h index caa5df0b74..82a5c0d4a8 100644 --- a/interfaces/innerkits/task_dispatcher/include/task/task.h +++ b/interfaces/innerkits/task_dispatcher/include/task/task.h @@ -31,12 +31,6 @@ namespace AppExecFwk { class BaseTaskDispatcher; class Task : public Revocable { public: - /** - * @brief Constructs the object. - * @param runnable The user task wrapped in. - * @param priority The priority - * @return - - */ Task(const std::shared_ptr &runnable, const TaskPriority priority, const std::shared_ptr &baseTaskDispatcher); @@ -44,36 +38,29 @@ public: /** *@brief invoke the function to execute the task - *@param - - *@return void */ virtual void Run(); /** * @brief Gets the priority. - * @param - * @return The priority. */ TaskPriority GetPriority() const; /** * @brief Sets the sequence. - * @param - * @param sequence The sequence - * @return void */ void SetSequence(long sequence); /** *@brief Gets the sequence. - *@param - *@return The sequence. */ long GetSequence() const; /** *@brief Revoke this task if hasn't run. - *@param - *@return true if set revoked or already revoked. False if the task has start executing. */ bool Revoke() override; @@ -81,44 +68,27 @@ public: /** *@brief Adds a task listener. *@param listener The listener - *@return void */ void AddTaskListener(const std::shared_ptr &listener); /** *@brief Called when task is about to run. - *@param - - *@return void */ void BeforeTaskExecute(); /** *@brief Called when task is done. - *@param - - *@return void */ void AfterTaskExecute(); /** *@brief Called when task is canceled. - *@param - - *@return void */ void OnTaskCanceled(); - /** - *@brief Save traceId for using on task running thread. - *@param hiTraceId The traceId. - *@return void - */ - // void SetTaskHiTraceId(HiTraceId &hiTraceId); - bool operator==(std::shared_ptr &rec) const; protected: - /** - * The user task wrapped in. - */ std::shared_ptr runnable_; private: @@ -143,10 +113,10 @@ private: void ConcurrentQueueStatusUpdate(const TaskStage::TASKSTAGE taskstage); private: - const static int EXECUTED = (1 << 0); - const static int REVOKED = (1 << 1); - long sequence_; - std::atomic state_; + const static unsigned int EXECUTED = (1 << 0); + const static unsigned int REVOKED = (1 << 1); + long sequence_ = 0; + std::atomic state_; TaskPriority priority_; std::shared_ptr revocable_ = nullptr; ConcurrentQueue> taskListeners_; diff --git a/interfaces/innerkits/task_dispatcher/include/task/task_handler_libevent_adapter.h b/interfaces/innerkits/task_dispatcher/include/task/task_handler_libevent_adapter.h index 9105aa34a1..732b5e17a4 100644 --- a/interfaces/innerkits/task_dispatcher/include/task/task_handler_libevent_adapter.h +++ b/interfaces/innerkits/task_dispatcher/include/task/task_handler_libevent_adapter.h @@ -24,28 +24,24 @@ #include "event_queue.h" namespace OHOS { namespace AppExecFwk { - -/** - * Dispatcher for serial thread model. - * - * - */ class TaskHandlerLibeventAdapter final : public EventHandler, public TaskDispatcherHandler { public: - TaskHandlerLibeventAdapter(const std::shared_ptr &eventRunner) : EventHandler(eventRunner) - {} + TaskHandlerLibeventAdapter(const std::shared_ptr &eventRunner) : EventHandler(eventRunner){}; virtual ~TaskHandlerLibeventAdapter(){}; bool Dispatch(const std::shared_ptr &runnable) override { + APP_LOGI("TaskHandlerLibeventAdapter::Dispatch called."); return EventHandler::PostTask(*(runnable.get()), EventQueue::Priority::HIGH); } bool Dispatch(const std::shared_ptr &runnable, long delayMs) override { + APP_LOGI("TaskHandlerLibeventAdapter::Delay Dispatch called."); return EventHandler::PostTask(*(runnable.get()), delayMs, EventQueue::Priority::HIGH); } bool DispatchSync(const std::shared_ptr &runnable) override { + APP_LOGI("TaskHandlerLibeventAdapter::Delay Dispatch Sync called."); return EventHandler::PostSyncTask(*(runnable.get()), EventQueue::Priority::HIGH); } }; diff --git a/interfaces/innerkits/task_dispatcher/include/task/task_stage.h b/interfaces/innerkits/task_dispatcher/include/task/task_stage.h index 00678029d0..d7c678dcd8 100644 --- a/interfaces/innerkits/task_dispatcher/include/task/task_stage.h +++ b/interfaces/innerkits/task_dispatcher/include/task/task_stage.h @@ -17,11 +17,6 @@ namespace OHOS { namespace AppExecFwk { -/** - * Enumeration for task execute stage. - * Attention: |REVOKED| is conflict with |AFTER_EXECUTE| and |BEFORE_EXECUTE|, which means, - * once |REVOKED|, the other stage will not be notified. So use |isDone| for judging. - */ class TaskStage { public: TaskStage() : index_(0) @@ -30,7 +25,11 @@ public: { index_ = index; } - + /** + * Enumeration for task execute stage. + * Attention: |REVOKED| is conflict with |AFTER_EXECUTE| and |BEFORE_EXECUTE|, which means, + * once |REVOKED|, the other stage will not be notified. So use |isDone| for judging. + */ enum TASKSTAGE { BEFORE_EXECUTE = 0, AFTER_EXECUTE = 1, REVOKED = 2 }; /** * Gets the index. diff --git a/interfaces/innerkits/task_dispatcher/include/threading/concurrent_queue.h b/interfaces/innerkits/task_dispatcher/include/threading/concurrent_queue.h index ee26ee8a75..1885cddd81 100644 --- a/interfaces/innerkits/task_dispatcher/include/threading/concurrent_queue.h +++ b/interfaces/innerkits/task_dispatcher/include/threading/concurrent_queue.h @@ -27,8 +27,7 @@ namespace AppExecFwk { template class ConcurrentQueue { public: - ConcurrentQueue() : empty_() - {} + ConcurrentQueue() : empty_(){}; /** * get data without block @@ -52,7 +51,7 @@ public: { std::unique_lock lock(mutex_); while (queue_.empty()) { - APP_LOGD("ConcurrentQueue::Take blocked"); + APP_LOGI("ConcurrentQueue::Take blocked"); empty_.wait(lock); } @@ -64,7 +63,7 @@ public: { std::unique_lock lock(mutex_); if (queue_.empty()) { - APP_LOGD("ConcurrentQueue::Poll empty"); + APP_LOGI("ConcurrentQueue::Poll empty"); return nullptr; } T front(queue_.front()); diff --git a/interfaces/innerkits/task_dispatcher/include/threading/delay_queue.h b/interfaces/innerkits/task_dispatcher/include/threading/delay_queue.h index 3726faf8b7..49b72d4a5e 100644 --- a/interfaces/innerkits/task_dispatcher/include/threading/delay_queue.h +++ b/interfaces/innerkits/task_dispatcher/include/threading/delay_queue.h @@ -65,11 +65,12 @@ public: while (true) { std::unique_lock lock(mutex_); while (taskQueue_.empty() && !stopFlag_) { - APP_LOGD("DelayQueue::taskQueue_ is empty"); + APP_LOGI("DelayQueue::taskQueue_ is empty"); emptyWait_.wait(lock); } if (taskQueue_.empty() && stopFlag_) { + APP_LOGI("DelayQueue::taskQueue is empty and stopFlag is true"); return nullptr; } diff --git a/interfaces/innerkits/task_dispatcher/include/threading/thread_factory.h b/interfaces/innerkits/task_dispatcher/include/threading/thread_factory.h index 3b3985edbd..ff2e777983 100644 --- a/interfaces/innerkits/task_dispatcher/include/threading/thread_factory.h +++ b/interfaces/innerkits/task_dispatcher/include/threading/thread_factory.h @@ -37,8 +37,6 @@ public: /** * ThreadFactory is an interface for producing thread. - * - * */ class ThreadFactory { public: diff --git a/interfaces/innerkits/task_dispatcher/include/threading/work_thread.h b/interfaces/innerkits/task_dispatcher/include/threading/work_thread.h index e62d98dd8c..ebdbf20085 100644 --- a/interfaces/innerkits/task_dispatcher/include/threading/work_thread.h +++ b/interfaces/innerkits/task_dispatcher/include/threading/work_thread.h @@ -29,7 +29,6 @@ namespace AppExecFwk { class WorkerThread; /** * Interface for a work delegate. - * */ class Delegate { public: @@ -44,7 +43,6 @@ public: /** * WorkerThread is a thread with a loop which can execute incoming tasks. - * */ class WorkerThread : public std::enable_shared_from_this { public: diff --git a/interfaces/innerkits/task_dispatcher/include/threading/worker_pool.h b/interfaces/innerkits/task_dispatcher/include/threading/worker_pool.h index 0377427ea1..edf8a97adc 100644 --- a/interfaces/innerkits/task_dispatcher/include/threading/worker_pool.h +++ b/interfaces/innerkits/task_dispatcher/include/threading/worker_pool.h @@ -76,15 +76,15 @@ private: void InterruptWorkers(void); - static int GetWorkingThreadNum(int ctl); + static unsigned int GetWorkingThreadNum(unsigned int ctl); static bool IsRunning(int ctl); static int GetStateFromControl(int ctl); - static int CombineToControl(int state, int count); + static int CombineToControl(unsigned int state, unsigned int count); - void AdvanceStateTo(int target); + void AdvanceStateTo(unsigned int target); bool CompareAndIncThreadNum(int expect); @@ -97,7 +97,7 @@ private: static const int MAX_THREAD_LOWER_LIMIT; static const int CORE_THREAD_LOWER_LIMIT; static const int COUNT_BITS; - static const int CAPACITY; + static const unsigned int CAPACITY; static const int RUNNING; static const int CLOSING; static const int INTERRUPT; diff --git a/interfaces/innerkits/task_dispatcher/src/dispatcher/base_task_dispatcher.cpp b/interfaces/innerkits/task_dispatcher/src/dispatcher/base_task_dispatcher.cpp index 6a0dc0171e..d007d4aa03 100644 --- a/interfaces/innerkits/task_dispatcher/src/dispatcher/base_task_dispatcher.cpp +++ b/interfaces/innerkits/task_dispatcher/src/dispatcher/base_task_dispatcher.cpp @@ -31,30 +31,37 @@ BaseTaskDispatcher::BaseTaskDispatcher(const std::string &dispatcherName, const ErrCode BaseTaskDispatcher::SyncDispatchBarrier(const std::shared_ptr &task) { + APP_LOGI("BaseTaskDispatcher::SyncDispatchBarrier called"); return SyncDispatch(task); } ErrCode BaseTaskDispatcher::AsyncDispatchBarrier(const std::shared_ptr &task) { + APP_LOGI("BaseTaskDispatcher::AsyncDispatchBarrier start"); std::shared_ptr revocable = AsyncDispatch(task); if (revocable != nullptr) { + APP_LOGI("BaseTaskDispatcher::AsyncDispatchBarrier end"); return ERR_OK; } + APP_LOGE("BaseTaskDispatcher::AsyncDispatchBarrier revocable is nullptr"); return ERR_APPEXECFWK_CHECK_FAILED; } std::shared_ptr BaseTaskDispatcher::CreateDispatchGroup() { + APP_LOGI("BaseTaskDispatcher::CreateDispatchGroup called."); return std::make_shared(); } std::shared_ptr BaseTaskDispatcher::AsyncGroupDispatch( const std::shared_ptr &group, const std::shared_ptr &task) { + APP_LOGI("BaseTaskDispatcher::AsyncGroupDispatch called."); return AsyncDispatch(task); } bool BaseTaskDispatcher::GroupDispatchWait(const std::shared_ptr &group, long timeout) { + APP_LOGI("BaseTaskDispatcher::GroupDispatchWait start"); if (group == nullptr) { APP_LOGE("BaseTaskDispatcher::GroupDispatchWait group is nullptr"); return false; @@ -64,58 +71,60 @@ bool BaseTaskDispatcher::GroupDispatchWait(const std::shared_ptr &group, APP_LOGE("BaseTaskDispatcher::GroupDispatchWait groupImpl is nullptr"); return false; } - return groupImpl->AwaitAllTasks(timeout); + bool result = groupImpl->AwaitAllTasks(timeout); + APP_LOGI("BaseTaskDispatcher::GroupDispatchWait start"); + return result; } ErrCode BaseTaskDispatcher::GroupDispatchNotify( const std::shared_ptr &group, const std::shared_ptr &task) { - bool flag = true; + APP_LOGI("BaseTaskDispatcher::GroupDispatchNotify start"); if (group == nullptr) { - APP_LOGE("group cannot be null."); - flag = false; + APP_LOGE("BaseTaskDispatcher::GroupDispatchNotify group cannot be null."); + return ERR_APPEXECFWK_CHECK_FAILED; } if (task == nullptr) { - APP_LOGE("task cannot be null"); - flag = false; + APP_LOGE("BaseTaskDispatcher::GroupDispatchNotify task cannot be null"); + return ERR_APPEXECFWK_CHECK_FAILED; } const std::function asyncDispatch = std::bind(&BaseTaskDispatcher::AsyncDispatch, this, task); if (asyncDispatch == nullptr) { APP_LOGE("BaseTaskDispatcher::GroupDispatchNotify asyncDispatch is nullptr"); + return ERR_APPEXECFWK_CHECK_FAILED; } std::shared_ptr ptrCallback = std::make_shared(asyncDispatch); if (ptrCallback == nullptr) { APP_LOGE("BaseTaskDispatcher::GroupDispatchNotify runnable is nullptr"); - flag = false; + return ERR_APPEXECFWK_CHECK_FAILED; } if (group == nullptr) { APP_LOGE("BaseTaskDispatcher::GroupDispatchNotify group is nullptr"); - flag = false; + return ERR_APPEXECFWK_CHECK_FAILED; } std::shared_ptr groupImpl = CastToGroupImpl(group); if (groupImpl == nullptr) { APP_LOGE("BaseTaskDispatcher::GroupDispatchNotify groupImpl is nullptr"); - flag = false; - } - if (!flag) { return ERR_APPEXECFWK_CHECK_FAILED; } - if (groupImpl->AddNotification(ptrCallback)) { + APP_LOGI("BaseTaskDispatcher::GroupDispatchNotify end"); return ERR_OK; }; + APP_LOGE("BaseTaskDispatcher::GroupDispatchNotify addNotification failed"); return ERR_APPEXECFWK_CHECK_FAILED; } ErrCode BaseTaskDispatcher::ApplyDispatch(const std::shared_ptr> &task, long iterations) { + APP_LOGI("BaseTaskDispatcher::ApplyDispatch start"); if (task == nullptr) { - APP_LOGE("task object is not set"); + APP_LOGE("BaseTaskDispatcher::ApplyDispatch task object is not set"); return ERR_APPEXECFWK_CHECK_FAILED; } if (iterations <= 0) { - APP_LOGE("iterations must giant than 0"); + APP_LOGE("BaseTaskDispatcher::ApplyDispatch iterations must giant than 0"); return ERR_APPEXECFWK_CHECK_FAILED; } @@ -128,18 +137,21 @@ ErrCode BaseTaskDispatcher::ApplyDispatch(const std::shared_ptr revocable = AsyncDispatch(ptrCallback); if (revocable == nullptr) { - APP_LOGE("BaseTaskDispatcher::ApplyDispatch revocable is nullptr"); + APP_LOGE("BaseTaskDispatcher::ApplyDispatch revocable is nullptr, index:%{public}ld", i); flag = false; } } if (flag) { + APP_LOGI("BaseTaskDispatcher::ApplyDispatch end"); return ERR_OK; } + APP_LOGI("BaseTaskDispatcher::ApplyDispatch failed"); return ERR_APPEXECFWK_CHECK_FAILED; } ErrCode BaseTaskDispatcher::Check(const std::shared_ptr &task) const { + APP_LOGI("BaseTaskDispatcher::Check called"); if (task == nullptr) { APP_LOGE("dispatch task cannot be null."); return ERR_APPEXECFWK_CHECK_FAILED; @@ -149,6 +161,7 @@ ErrCode BaseTaskDispatcher::Check(const std::shared_ptr &task) const std::shared_ptr BaseTaskDispatcher::CastToGroupImpl(const std::shared_ptr &group) { + APP_LOGI("BaseTaskDispatcher::CastToGroupImpl called"); std::shared_ptr groupImpl_ptr = std::static_pointer_cast(group); if (groupImpl_ptr != nullptr) { return groupImpl_ptr; @@ -170,14 +183,15 @@ TaskPriority BaseTaskDispatcher::GetPriority() const void BaseTaskDispatcher::TracePointBeforePost( std::shared_ptr &task, bool isAsyncTask, const std::string &dispatcherName) const { - + APP_LOGI("BaseTaskDispatcher::TracePointBeforePost called"); if (task == nullptr) { - APP_LOGE("tracePointBeforePost the task is null"); + APP_LOGE("BaseTaskDispatcher::TracePointBeforePost the task is nullptr"); return; } std::string taskType = isAsyncTask ? "ASYNC_TASK_STRING" : "SYNC_TASK_STRING"; long seq = task->GetSequence(); - APP_LOGD("tracePointBeforePost log---TaskType:%{public}s,TaskSeq::%{public}ld,DispatcherName::%{public}s", + APP_LOGI("BaseTaskDispatcher::TracePointBeforePost " + "log---TaskType:%{public}s,TaskSeq:%{public}ld,DispatcherName::%{public}s", taskType.c_str(), seq, dispatcherName.c_str()); @@ -186,13 +200,15 @@ void BaseTaskDispatcher::TracePointBeforePost( void BaseTaskDispatcher::TracePointAfterPost( std::shared_ptr &task, bool isAsyncTask, const std::string &dispatcherName) const { + APP_LOGI("BaseTaskDispatcher::TracePointAfterPost called"); if (task == nullptr) { - APP_LOGE("TracePointAfterPost the task is null"); + APP_LOGE("BaseTaskDispatcher::TracePointAfterPost the task is nullptr"); return; } std::string taskType = isAsyncTask ? "ASYNC_TASK_STRING" : "SYNC_TASK_STRING"; long seq = task->GetSequence(); - APP_LOGD("tracePointBeforePost log---TaskType:%{public}s,TaskSeq::%{public}ld,DispatcherName::%{public}s", + APP_LOGI("BaseTaskDispatcher::TracePointAfterPost " + "log---TaskType:%{public}s,TaskSeq:%{public}ld,DispatcherName::%{public}s", taskType.c_str(), seq, dispatcherName.c_str()); diff --git a/interfaces/innerkits/task_dispatcher/src/dispatcher/group_impl.cpp b/interfaces/innerkits/task_dispatcher/src/dispatcher/group_impl.cpp index d44df5bace..ed3b982aca 100644 --- a/interfaces/innerkits/task_dispatcher/src/dispatcher/group_impl.cpp +++ b/interfaces/innerkits/task_dispatcher/src/dispatcher/group_impl.cpp @@ -30,11 +30,13 @@ GroupImpl::GroupImpl() */ bool GroupImpl::AwaitAllTasks(long timeout) { + APP_LOGI("GroupImpl::AwaitAllTasks start"); if (count_.load() == 0) { - APP_LOGD("GroupImpl::AwaitAllTasks number of count_ is zero"); + APP_LOGI("GroupImpl::AwaitAllTasks number of count_ is zero"); return true; } if (timeout <= 0L) { + APP_LOGW("GroupImpl::AwaitAllTasks timeout<=0"); return false; } bool success = true; @@ -42,34 +44,31 @@ bool GroupImpl::AwaitAllTasks(long timeout) while (count_.load() > 0) { if (condition_.wait_for(lock, std::chrono::milliseconds(timeout)) == std::cv_status::timeout) { success = false; - APP_LOGD("GroupImpl::awaitAllTasks timeout"); + APP_LOGI("GroupImpl::awaitAllTasks timeout"); break; } - APP_LOGD("GroupImpl::awaitAllTasks success"); + APP_LOGI("GroupImpl::awaitAllTasks success"); } + APP_LOGI("GroupImpl::AwaitAllTasks end"); return success; } /** - * @brief Associates a task to this group. + * @brief Associates a task to this group. * - * @return None */ void GroupImpl::Associate() { - APP_LOGD("GroupImpl::Associate called add a task"); - // count_++; + APP_LOGI("GroupImpl::Associate called add a task"); count_.fetch_add(1); } /** * @brief Notify group that a task is done or canceled. * - * @return None */ void GroupImpl::NotifyTaskDone() { - APP_LOGD("GroupImpl::NotifyTaskDone called notify a task to complete"); - // int newValue = (--count_); + APP_LOGI("GroupImpl::NotifyTaskDone start. Called notify a task to complete"); count_.fetch_sub(1); int newValue = count_.load(); if (newValue > 0) { @@ -78,6 +77,8 @@ void GroupImpl::NotifyTaskDone() std::unique_lock lock(dataMutex_); condition_.notify_all(); DrainNotifications(); + + APP_LOGI("GroupImpl::NotifyTaskDone end"); } /** * @brief Adds the |notification| to notification list. @@ -86,10 +87,10 @@ void GroupImpl::NotifyTaskDone() * * @param notification Called when all tasks done. * - * @return None */ bool GroupImpl::AddNotification(const std::shared_ptr ¬ification) { + APP_LOGI("GroupImpl::AddNotification start"); if (count_.load() != 0) { std::unique_lock lock(dataMutex_); if (notifications_.size() == MAX_TASK) { @@ -97,30 +98,32 @@ bool GroupImpl::AddNotification(const std::shared_ptr ¬ification) return false; } if (count_.load() != 0) { - APP_LOGD("GroupImpl::AddNotification called add task"); + APP_LOGI("GroupImpl::AddNotification called add task"); notifications_.push_back(notification); return true; } } if (notification) { + APP_LOGI("GroupImpl::AddNotification notification execute"); (*notification)(); } + APP_LOGI("GroupImpl::AddNotification end"); return true; } /** - *@brief Notify all tasks and remove from queue. + * @brief Notify all tasks and remove from queue. * Attention: Notifications added after all tasks done is not guaranteed. - * - * @return None */ void GroupImpl::DrainNotifications() { - APP_LOGD("GroupImpl::DrainNotifications called task execution"); + APP_LOGI("GroupImpl::DrainNotifications start"); while (notifications_.size() > 0) { std::shared_ptr notification = notifications_.front(); notifications_.pop_front(); + APP_LOGI("GroupImpl::DrainNotifications execute notification"); (*notification)(); } + APP_LOGI("GroupImpl::DrainNotifications end"); } } // namespace AppExecFwk diff --git a/interfaces/innerkits/task_dispatcher/src/dispatcher/parallel_task_dispatcher.cpp b/interfaces/innerkits/task_dispatcher/src/dispatcher/parallel_task_dispatcher.cpp index a5514bc1c6..2f417c8d5d 100644 --- a/interfaces/innerkits/task_dispatcher/src/dispatcher/parallel_task_dispatcher.cpp +++ b/interfaces/innerkits/task_dispatcher/src/dispatcher/parallel_task_dispatcher.cpp @@ -34,6 +34,7 @@ std::shared_ptr ParallelTaskDispatcher::GetInterceptor() ErrCode ParallelTaskDispatcher::SyncDispatchBarrier(const std::shared_ptr &runnable) { + APP_LOGI("ParallelTaskDispatcher::SyncDispatchBarrier start"); if (Check(runnable) != ERR_OK) { APP_LOGE("ParallelTaskDispatcher::SyncDispatchBarrier Check failed"); return ERR_APPEXECFWK_CHECK_FAILED; @@ -62,7 +63,9 @@ ErrCode ParallelTaskDispatcher::SyncDispatchBarrier(const std::shared_ptr &runnable) { + APP_LOGI("ParallelTaskDispatcher::AsyncDispatchBarrier start"); if (Check(runnable) != ERR_OK) { + APP_LOGE("ParallelTaskDispatcher::AsyncDispatchBarrier check failed"); return ERR_APPEXECFWK_CHECK_FAILED; } if (barrierHandler_ == nullptr) { @@ -70,13 +73,14 @@ ErrCode ParallelTaskDispatcher::AsyncDispatchBarrier(const std::shared_ptr innerTask = std::make_shared(runnable, GetPriority(), shared_from_this()); - APP_LOGD("ParallelTaskDispatcher::AsyncDispatchBarrier into new async task"); + APP_LOGI("ParallelTaskDispatcher::AsyncDispatchBarrier into new async task"); if (innerTask == nullptr) { APP_LOGE("ParallelTaskDispatcher::AsyncDispatchBarrier innerTask is nullptr"); return ERR_APPEXECFWK_CHECK_FAILED; } barrierHandler_->AddBarrier(innerTask); + APP_LOGI("ParallelTaskDispatcher::AsyncDispatchBarrier end"); return ERR_OK; } diff --git a/interfaces/innerkits/task_dispatcher/src/dispatcher/parallel_task_dispatcher_base.cpp b/interfaces/innerkits/task_dispatcher/src/dispatcher/parallel_task_dispatcher_base.cpp index 6e6e64189d..de9e3e011b 100644 --- a/interfaces/innerkits/task_dispatcher/src/dispatcher/parallel_task_dispatcher_base.cpp +++ b/interfaces/innerkits/task_dispatcher/src/dispatcher/parallel_task_dispatcher_base.cpp @@ -32,6 +32,7 @@ ParallelTaskDispatcherBase::ParallelTaskDispatcherBase( } ErrCode ParallelTaskDispatcherBase::InterceptedExecute(std::shared_ptr &task) { + APP_LOGI("ParallelTaskDispatcherBase::InterceptedExecute start"); if (executor_ == nullptr) { APP_LOGE("ParallelTaskDispatcherBase::InterceptedExecute executor_ is nullptr"); return ERR_APPEXECFWK_CHECK_FAILED; @@ -44,11 +45,13 @@ ErrCode ParallelTaskDispatcherBase::InterceptedExecute(std::shared_ptr &ta } executor_->Execute(task); + APP_LOGI("ParallelTaskDispatcherBase::InterceptedExecute end"); return ERR_OK; } ErrCode ParallelTaskDispatcherBase::SyncDispatch(const std::shared_ptr &runnable) { + APP_LOGI("ParallelTaskDispatcherBase::SyncDispatch start"); if (Check(runnable) != ERR_OK) { APP_LOGE("ParallelTaskDispatcherBase::SyncDispatch check failed"); return ERR_APPEXECFWK_CHECK_FAILED; @@ -64,40 +67,45 @@ ErrCode ParallelTaskDispatcherBase::SyncDispatch(const std::shared_ptr APP_LOGE("ParallelTaskDispatcherBase::SyncDispatch innerTask is nullptr"); return ERR_APPEXECFWK_CHECK_FAILED; } - APP_LOGD("ParallelTaskDispatcherBase::SyncDispatch into new sync task"); + APP_LOGI("ParallelTaskDispatcherBase::SyncDispatch into new sync task"); ErrCode execute = InterceptedExecute(innerTask); if (execute != ERR_OK) { APP_LOGE("ParallelTaskDispatcherBase::SyncDispatch execute failed"); return execute; } innerSyncTask->WaitTask(); - APP_LOGD("ParallelTaskDispatcherBase::SyncDispatch end"); + APP_LOGI("ParallelTaskDispatcherBase::SyncDispatch end"); return ERR_OK; } std::shared_ptr ParallelTaskDispatcherBase::AsyncDispatch(const std::shared_ptr &runnable) { + APP_LOGI("ParallelTaskDispatcherBase::AsyncDispatch start"); if (Check(runnable) != ERR_OK) { + APP_LOGE("ParallelTaskDispatcherBase::AsyncDispatch check failed."); return nullptr; } std::shared_ptr innerTask = std::make_shared(runnable, GetPriority(), shared_from_this()); if (innerTask == nullptr) { + APP_LOGE("ParallelTaskDispatcherBase::AsyncDispatch innerTask is nullptr."); return nullptr; } TracePointBeforePost(innerTask, true, ASYNC_DISPATCHER_TAG); - APP_LOGD("ParallelTaskDispatcherBase::AsyncDispatch into new async task"); + APP_LOGI("ParallelTaskDispatcherBase::AsyncDispatch into new async task"); ErrCode execute = InterceptedExecute(innerTask); if (execute != ERR_OK) { APP_LOGE("ParallelTaskDispatcherBase::AsyncDispatch execute failed"); return nullptr; } + APP_LOGI("ParallelTaskDispatcherBase::AsyncDispatch end"); return innerTask; } std::shared_ptr ParallelTaskDispatcherBase::DelayDispatch( const std::shared_ptr &runnable, long delayMs) { + APP_LOGI("ParallelTaskDispatcherBase::DelayDispatch start"); if (Check(runnable) != ERR_OK) { APP_LOGE("ParallelTaskDispatcherBase::DelayDispatch Check failed"); return nullptr; @@ -110,6 +118,7 @@ std::shared_ptr ParallelTaskDispatcherBase::DelayDispatch( std::shared_ptr innerTask = std::make_shared(runnable, GetPriority(), shared_from_this()); if (innerTask == nullptr) { + APP_LOGE("ParallelTaskDispatcherBase::DelayDispatch innerTask is nullptr"); return nullptr; } TracePointBeforePost(innerTask, true, DELAY_DISPATCHER_TAG); @@ -120,12 +129,14 @@ std::shared_ptr ParallelTaskDispatcherBase::DelayDispatch( APP_LOGE("ParallelTaskDispatcherBase::DelayDispatch execute failed"); return nullptr; } + APP_LOGI("ParallelTaskDispatcherBase::DelayDispatch end"); return innerTask; } std::shared_ptr ParallelTaskDispatcherBase::AsyncGroupDispatch( const std::shared_ptr &group, const std::shared_ptr &runnable) { + APP_LOGI("ParallelTaskDispatcherBase::AsyncGroupDispatch start"); if (group == nullptr) { APP_LOGE("ParallelTaskDispatcherBase::AsyncGroupDispatch group is nullptr"); return nullptr; @@ -161,6 +172,7 @@ std::shared_ptr ParallelTaskDispatcherBase::AsyncGroupDispatch( APP_LOGE("ParallelTaskDispatcherBase::AsyncGroupDispatch execute failed"); return nullptr; } + APP_LOGI("ParallelTaskDispatcherBase::AsyncGroupDispatch end"); return innerTask; } diff --git a/interfaces/innerkits/task_dispatcher/src/dispatcher/serial_task_dispatcher.cpp b/interfaces/innerkits/task_dispatcher/src/dispatcher/serial_task_dispatcher.cpp index 6e8c40eb17..48e37f068e 100644 --- a/interfaces/innerkits/task_dispatcher/src/dispatcher/serial_task_dispatcher.cpp +++ b/interfaces/innerkits/task_dispatcher/src/dispatcher/serial_task_dispatcher.cpp @@ -44,7 +44,7 @@ std::string SerialTaskDispatcher::GetDispatcherName() ErrCode SerialTaskDispatcher::SyncDispatch(const std::shared_ptr &runnable) { - APP_LOGD("SerialTaskDispatcher::SyncDispatch begin"); + APP_LOGI("SerialTaskDispatcher::SyncDispatch start"); if (Check(runnable) != ERR_OK) { APP_LOGE("SerialTaskDispatcher::SyncDispatch check failed"); return ERR_APPEXECFWK_CHECK_FAILED; @@ -65,12 +65,13 @@ ErrCode SerialTaskDispatcher::SyncDispatch(const std::shared_ptr &runn innerSyncTask->WaitTask(); TracePointAfterPost(innerTask, false, DISPATCHER_TAG); - APP_LOGD("SerialTaskDispatcher::SyncDispatch end"); + APP_LOGI("SerialTaskDispatcher::SyncDispatch end"); return ERR_OK; } std::shared_ptr SerialTaskDispatcher::AsyncDispatch(const std::shared_ptr &runnable) { + APP_LOGI("SerialTaskDispatcher::AsyncDispatch start"); if (Check(runnable) != ERR_OK) { APP_LOGE("SerialTaskDispatcher::AsyncDispatch Check failed"); return nullptr; @@ -82,13 +83,15 @@ std::shared_ptr SerialTaskDispatcher::AsyncDispatch(const std::shared return nullptr; } TracePointBeforePost(innerTask, true, ASYNC_DISPATCHER_TAG); - APP_LOGD("SerialTaskDispatcher::AsyncDispatch into new async task"); + APP_LOGI("SerialTaskDispatcher::AsyncDispatch into new async task"); OnNewTaskIn(innerTask); + APP_LOGI("SerialTaskDispatcher::AsyncDispatch end"); return innerTask; } std::shared_ptr SerialTaskDispatcher::DelayDispatch(const std::shared_ptr &runnable, long delayMs) { + APP_LOGI("SerialTaskDispatcher::DelayDispatch start"); if (executor_ == nullptr) { APP_LOGE("SerialTaskDispatcher::DelayDispatch executor_ is nullptr"); return nullptr; @@ -111,14 +114,13 @@ std::shared_ptr SerialTaskDispatcher::DelayDispatch(const std::shared APP_LOGE("SerialTaskDispatcher::DelayDispatch execute failed"); return nullptr; } - + APP_LOGI("SerialTaskDispatcher::DelayDispatch end"); return innerTask; } ErrCode SerialTaskDispatcher::OnNewTaskIn(std::shared_ptr &task) { - APP_LOGD("SerialTaskDispatcher::OnNewTaskIn begin"); - + APP_LOGI("SerialTaskDispatcher::OnNewTaskIn start"); ErrCode code = Prepare(task); if (code != ERR_OK) { APP_LOGE("SerialTaskDispatcher::OnNewTaskIn Prepare failed"); @@ -132,12 +134,13 @@ ErrCode SerialTaskDispatcher::OnNewTaskIn(std::shared_ptr &task) } Schedule(); - APP_LOGD("SerialTaskDispatcher::OnNewTaskIn end"); + APP_LOGI("SerialTaskDispatcher::OnNewTaskIn end"); return ERR_OK; } ErrCode SerialTaskDispatcher::Prepare(std::shared_ptr &task) { + APP_LOGI("SerialTaskDispatcher::Prepare start"); if (task == nullptr) { APP_LOGE("SerialTaskDispatcher::Prepare task is nullptr"); return ERR_APPEXECFWK_CHECK_FAILED; @@ -170,48 +173,51 @@ ErrCode SerialTaskDispatcher::Prepare(std::shared_ptr &task) const std::function onTaskDone = [&]() { OnTaskDone(); }; ptrlistener->Callback(onTaskDone); task->AddTaskListener(ptrlistener); + APP_LOGI("SerialTaskDispatcher::Prepare end"); return ERR_OK; } void SerialTaskDispatcher::OnTaskDone() { - // isExhausted: is an inaccurate judge indicate that the workingTasks is empty.If true, do double - check. + APP_LOGI("SerialTaskDispatcher::OnTaskDone start"); bool isExhausted = workingTasks_.Empty(); DoNext(isExhausted); - // APP_LOGD("SerialTaskDispatcher::OnTaskDone end, running=%d", running.load()); + APP_LOGI("SerialTaskDispatcher::OnTaskDone end"); } bool SerialTaskDispatcher::Schedule() { bool init = false; if (!running_.compare_exchange_strong(init, true)) { - APP_LOGD("SerialTaskDispatcher::schedule already running"); + APP_LOGW("SerialTaskDispatcher::schedule already running"); return false; } - APP_LOGD("SerialTaskDispatcher::Schedule do next"); + APP_LOGI("SerialTaskDispatcher::Schedule do next"); return DoNext(false); } bool SerialTaskDispatcher::DoNext(bool isExhausted) { + APP_LOGI("SerialTaskDispatcher::DoNext start"); std::shared_ptr nextptr = nullptr; { std::unique_lock lock(mutex_); nextptr = workingTasks_.Poll(); if (nextptr == nullptr) { running_.store(false); - APP_LOGD("SerialTaskDispatcher::DoNext no more task"); + APP_LOGW("SerialTaskDispatcher::DoNext no more task"); return false; } } DoWork(nextptr); - APP_LOGD("SerialTaskDispatcher::DoNext end"); + APP_LOGI("SerialTaskDispatcher::DoNext end"); return true; } void SerialTaskDispatcher::DoWork(std::shared_ptr &task) { + APP_LOGI("SerialTaskDispatcher::DoWork called."); // |task| mustn't be null executor_->Execute(task); } diff --git a/interfaces/innerkits/task_dispatcher/src/dispatcher/spec_task_dispatcher.cpp b/interfaces/innerkits/task_dispatcher/src/dispatcher/spec_task_dispatcher.cpp index d81c259024..e6e176164b 100644 --- a/interfaces/innerkits/task_dispatcher/src/dispatcher/spec_task_dispatcher.cpp +++ b/interfaces/innerkits/task_dispatcher/src/dispatcher/spec_task_dispatcher.cpp @@ -31,53 +31,74 @@ SpecTaskDispatcher::SpecTaskDispatcher( ErrCode SpecTaskDispatcher::SyncDispatch(const std::shared_ptr &runnable) { - APP_LOGD("SpecTaskDispatcher::SyncDispatch begin"); - if (Check(runnable) != ERR_OK || handler_ == nullptr) { + APP_LOGI("SpecTaskDispatcher::SyncDispatch start"); + if (handler_ == nullptr) { + APP_LOGE("SpecTaskDispatcher::SyncDispatch handler is nullptr"); + return ERR_APPEXECFWK_CHECK_FAILED; + } + if (Check(runnable) != ERR_OK) { + APP_LOGE("SpecTaskDispatcher::SyncDispatch check failed"); return ERR_APPEXECFWK_CHECK_FAILED; } std::shared_ptr innerTask = std::make_shared(runnable, GetPriority(), shared_from_this()); if (innerTask == nullptr) { + APP_LOGE("SpecTaskDispatcher::SyncDispatch innerTask is nullptr"); return ERR_APPEXECFWK_CHECK_FAILED; } TracePointBeforePost(innerTask, false, SYNC_DISPATCHER_TAG); - APP_LOGD("SpecTaskDispatcher::SyncDispatch into new sync task"); + APP_LOGI("SpecTaskDispatcher::SyncDispatch into new sync task"); handler_->DispatchSync(runnable); - // innerSyncTask->WaitTask(); TracePointAfterPost(innerTask, false, DISPATCHER_TAG); - APP_LOGD("SpecTaskDispatcher::SyncDispatch end"); + APP_LOGI("SpecTaskDispatcher::SyncDispatch end"); return ERR_OK; } std::shared_ptr SpecTaskDispatcher::AsyncDispatch(const std::shared_ptr &runnable) { - if (Check(runnable) != ERR_OK || handler_ == nullptr) { + APP_LOGI("SpecTaskDispatcher::AsyncDispatch start"); + if (handler_ == nullptr) { + APP_LOGE("SpecTaskDispatcher::AsyncDispatch handler is nullptr"); + return nullptr; + } + if (Check(runnable) != ERR_OK) { + APP_LOGE("SpecTaskDispatcher::AsyncDispatch check failed"); return nullptr; } std::shared_ptr innerTask = std::make_shared(runnable, GetPriority(), shared_from_this()); if (innerTask == nullptr) { + APP_LOGE("SpecTaskDispatcher::AsyncDispatch innerTask is nullptr"); return nullptr; } TracePointBeforePost(innerTask, true, ASYNC_DISPATCHER_TAG); - APP_LOGD("SpecTaskDispatcher::AsyncDispatch into new async task"); + APP_LOGI("SpecTaskDispatcher::AsyncDispatch into new async task"); handler_->Dispatch(runnable); + APP_LOGI("SpecTaskDispatcher::AsyncDispatch end"); return innerTask; } std::shared_ptr SpecTaskDispatcher::DelayDispatch(const std::shared_ptr &runnable, long delayMs) { - if (Check(runnable) != ERR_OK || handler_ == nullptr) { + APP_LOGI("SpecTaskDispatcher::DelayDispatch start"); + if (handler_ == nullptr) { + APP_LOGE("SpecTaskDispatcher::DelayDispatch handler is nullptr"); + return nullptr; + } + if (Check(runnable) != ERR_OK) { + APP_LOGE("SpecTaskDispatcher::DelayDispatch check failed"); return nullptr; } std::shared_ptr innerTask = std::make_shared(runnable, GetPriority(), shared_from_this()); if (innerTask == nullptr) { + APP_LOGE("SpecTaskDispatcher::DelayDispatch innerTask is nullptr"); return nullptr; } TracePointBeforePost(innerTask, true, DELAY_DISPATCHER_TAG); handler_->Dispatch(runnable, delayMs); + APP_LOGI("SpecTaskDispatcher::DelayDispatch end"); return innerTask; } } // namespace AppExecFwk diff --git a/interfaces/innerkits/task_dispatcher/src/dispatcher/task_dispatcher_context.cpp b/interfaces/innerkits/task_dispatcher/src/dispatcher/task_dispatcher_context.cpp index 237bc31930..9e22e53a26 100644 --- a/interfaces/innerkits/task_dispatcher/src/dispatcher/task_dispatcher_context.cpp +++ b/interfaces/innerkits/task_dispatcher/src/dispatcher/task_dispatcher_context.cpp @@ -23,6 +23,7 @@ TaskDispatcherContext::TaskDispatcherContext() globalDispatchers_.resize(PRIORITY_COUNT); config_ = std::make_shared(); if (config_ == nullptr) { + APP_LOGE("TaskDispatcherContext::TaskDispatcherContext config is nullptr"); executor_ = nullptr; } else { executor_ = std::make_shared(config_); @@ -40,12 +41,11 @@ TaskDispatcherContext::TaskDispatcherContext(const std::shared_ptr TaskDispatcherContext::~TaskDispatcherContext() { - if (executor_) { - APP_LOGD("TaskDispatcherContext::~TaskDispatcherContext() terminate"); + APP_LOGI("TaskDispatcherContext::~TaskDispatcherContext() terminate"); executor_->Terminate(false); } - APP_LOGD("TaskDispatcherContext::~TaskDispatcherContext"); + APP_LOGI("TaskDispatcherContext::~TaskDispatcherContext end"); } std::shared_ptr TaskDispatcherContext::GetWorkerPoolConfig() const @@ -55,54 +55,67 @@ std::shared_ptr TaskDispatcherContext::GetWorkerPoolConfig() c std::map TaskDispatcherContext::GetWorkerThreadsInfo() const { + APP_LOGI("TaskDispatcherContext::GetWorkerThreadsInfo called"); if (executor_ != nullptr) { return executor_->GetWorkerThreadsInfo(); } std::map map; + APP_LOGE("TaskDispatcherContext::GetWorkerThreadsInfo executor is nullptr"); return map; } std::map, std::string> TaskDispatcherContext::GetSerialDispatchers() const { + APP_LOGI("TaskDispatcherContext::GetSerialDispatchers called"); return serialDispatchers_; } int TaskDispatcherContext::GetWaitingTasksCount() const { + APP_LOGI("TaskDispatcherContext::GetWaitingTasksCount called"); if (executor_ != nullptr) { return executor_->GetPendingTasksSize(); } + APP_LOGE("TaskDispatcherContext::GetWaitingTasksCount executor is nullptr"); return 0; } long TaskDispatcherContext::GetTaskCounter() const { + APP_LOGI("TaskDispatcherContext::GetTaskCounter called"); if (executor_ != nullptr) { return executor_->GetTaskCounter(); } + APP_LOGE("TaskDispatcherContext::GetTaskCounter executor is nullptr"); return 0; } std::shared_ptr TaskDispatcherContext::CreateSerialDispatcher( const std::string &name, TaskPriority priority) { + APP_LOGI("TaskDispatcherContext::CreateSerialDispatcher start"); if (executor_ == nullptr) { + APP_LOGE("TaskDispatcherContext::CreateSerialDispatcher executor is nullptr"); return nullptr; } std::shared_ptr serialDispatcher = std::make_shared(name, priority, executor_); serialDispatchers_.insert(std::pair, std::string>(serialDispatcher, name)); + APP_LOGI("TaskDispatcherContext::CreateSerialDispatcher end"); return serialDispatcher; } std::shared_ptr TaskDispatcherContext::CreateParallelDispatcher( const std::string &name, TaskPriority priority) { + APP_LOGI("TaskDispatcherContext::CreateParallelDispatcher start"); if (executor_ == nullptr) { + APP_LOGE("TaskDispatcherContext::CreateParallelDispatcher executor is nullptr"); return nullptr; } std::shared_ptr parallelTaskDispatcher = std::make_shared(name, priority, executor_); + APP_LOGI("TaskDispatcherContext::CreateParallelDispatcher end"); return parallelTaskDispatcher; } @@ -123,32 +136,35 @@ int TaskDispatcherContext::MapPriorityIndex(TaskPriority priority) const std::shared_ptr TaskDispatcherContext::GetGlobalTaskDispatcher(TaskPriority priority) { + APP_LOGI("TaskDispatcherContext::GetGlobalTaskDispatcher start"); std::unique_lock lock(mtx_); int index = MapPriorityIndex(priority); std::shared_ptr dispatcher = globalDispatchers_[index]; if (dispatcher == nullptr) { - APP_LOGD("GetGlobalTaskDispatcher dispatcher is nullptr "); + APP_LOGI("TaskDispatcherContext::GetGlobalTaskDispatcher dispatcher is nullptr "); if (executor_ == nullptr) { - APP_LOGE("GetGlobalTaskDispatcher executor_ is nullptr "); + APP_LOGE("TaskDispatcherContext::GetGlobalTaskDispatcher executor_ is nullptr "); return nullptr; } dispatcher = std::make_shared(priority, executor_); if (globalDispatchers_[index] == nullptr) { - APP_LOGD("GetGlobalTaskDispatcher dispatcher compareAndSet "); + APP_LOGI("TaskDispatcherContext::GetGlobalTaskDispatcher dispatcher compareAndSet "); globalDispatchers_.insert((globalDispatchers_.begin() + index), dispatcher); } } - + APP_LOGI("TaskDispatcherContext::GetGlobalTaskDispatcher end"); return dispatcher; } ErrCode TaskDispatcherContext::Shutdown(bool force) { + APP_LOGI("TaskDispatcherContext::Shutdown start"); if (executor_ == nullptr) { APP_LOGE("TaskDispatcherContext::Shutdown executor_ is nullptr"); return ERR_APPEXECFWK_CHECK_FAILED; } executor_->Terminate(force); + APP_LOGI("TaskDispatcherContext::Shutdown end"); return ERR_OK; } } // namespace AppExecFwk diff --git a/interfaces/innerkits/task_dispatcher/src/task/barrier_handler.cpp b/interfaces/innerkits/task_dispatcher/src/task/barrier_handler.cpp index caf0aa9517..a8d0c7a42f 100644 --- a/interfaces/innerkits/task_dispatcher/src/task/barrier_handler.cpp +++ b/interfaces/innerkits/task_dispatcher/src/task/barrier_handler.cpp @@ -24,8 +24,9 @@ BarrierHandler::BarrierHandler(const std::shared_ptr &executor) ErrCode BarrierHandler::AddBarrier(std::shared_ptr &barrierTask) { + APP_LOGI("BarrierHandler::AddBarrier start"); if (ListenToTask(barrierTask) != ERR_OK) { - APP_LOGE("BarrierHandler::addBarrier listenToTask failed"); + APP_LOGE("BarrierHandler::AddBarrier listenToTask failed"); return ERR_APPEXECFWK_CHECK_FAILED; }; @@ -35,44 +36,51 @@ ErrCode BarrierHandler::AddBarrier(std::shared_ptr &barrierTask) std::shared_ptr pair = barrierQueue_.size() == 0 ? nullptr : barrierQueue_.back(); if ((pair == nullptr) || ((!HasTask(pair->tasks_)) && (pair->barrier_ == nullptr))) { execNow = true; + APP_LOGI("BarrierHandler::AddBarrier need execute now"); } if ((pair == nullptr) || (pair->barrier_ != nullptr)) { std::set> tmp; std::shared_ptr barrierPair = std::make_shared(tmp, barrierTask); if (barrierPair == nullptr) { + APP_LOGE("BarrierHandler::AddBarrier barrierPair is nullptr"); return ERR_APPEXECFWK_CHECK_FAILED; } barrierQueue_.push_back(barrierPair); - + APP_LOGI("BarrierHandler::AddBarrier barrierQueue push barrierPair"); } else { pair->barrier_ = barrierTask; } } - APP_LOGD("Barrier.addBarrier need execute now: %{public}d", execNow); if (execNow) { + APP_LOGI("BarrierHandler::AddBarrier execute task"); executor_->Execute(barrierTask); } + APP_LOGI("BarrierHandler::AddBarrier end"); return ERR_OK; } ErrCode BarrierHandler::Intercept(std::shared_ptr &task) { + APP_LOGI("BarrierHandler::Intercept start"); if (ListenToTask(task) != ERR_OK) { - APP_LOGE("BarrierHandler::intercept listenToTask failed"); + APP_LOGE("BarrierHandler::Intercept listenToTask failed"); return ERR_APPEXECFWK_CHECK_FAILED; }; // afterBarrier means is intercepted. bool intercepted = AddTaskAfterBarrier(task); if (intercepted) { - APP_LOGD("Barrier.intercept intercepted a task."); + APP_LOGI("BarrierHandler::Intercept intercepted a task."); } - return intercepted ? ERR_APPEXECFWK_INTERCEPT_TASK_EXECUTE_SUCCESS : ERR_APPEXECFWK_CHECK_FAILED; + ErrCode result = intercepted ? ERR_APPEXECFWK_INTERCEPT_TASK_EXECUTE_SUCCESS : ERR_APPEXECFWK_CHECK_FAILED; + APP_LOGI("BarrierHandler::Intercept end, result:%{public}d", result); + return result; } ErrCode BarrierHandler::ListenToTask(std::shared_ptr &task) { + APP_LOGI("BarrierHandler::ListenToTask start"); std::shared_ptr ptrlistener = std::make_shared(); if (ptrlistener == nullptr) { APP_LOGE("BarrierHandler::listenToTask make shared MyTaskListener is nullptr"); @@ -81,11 +89,13 @@ ErrCode BarrierHandler::ListenToTask(std::shared_ptr &task) const std::function onTaskDone = std::bind(&BarrierHandler::OnTaskDone, this, task); ptrlistener->Callback(onTaskDone); task->AddTaskListener(ptrlistener); + APP_LOGI("BarrierHandler::ListenToTask end"); return ERR_OK; } void BarrierHandler::OnTaskDone(std::shared_ptr &task) { + APP_LOGI("BarrierHandler::OnTaskDone start"); // remove from head of queue. // Under the premise that task cannot be reused. bool removed = false; @@ -96,11 +106,11 @@ void BarrierHandler::OnTaskDone(std::shared_ptr &task) if (HasTask(barrierPair->tasks_)) { removed = barrierPair->tasks_.erase(task) == 0 ? false : true; if (barrierPair->tasks_.empty() && (barrierPair->barrier_ != nullptr)) { - APP_LOGD("Barrier.onTaskDone execute barrier task after task done."); + APP_LOGI("Barrier.onTaskDone execute barrier task after task done."); executor_->Execute(barrierPair->barrier_); } } else if (task == (barrierPair->barrier_)) { - APP_LOGD("Barrier.onTaskDone remove a barrier."); + APP_LOGI("Barrier.onTaskDone remove a barrier."); barrierPair->barrier_ = nullptr; removed = true; // Driven to next barrier. @@ -116,11 +126,10 @@ void BarrierHandler::OnTaskDone(std::shared_ptr &task) } } else if (nextPair->barrier_ != nullptr) { - APP_LOGD("Barrier.onTaskDone execute barrier task after barrier done."); + APP_LOGI("Barrier.onTaskDone execute barrier task after barrier done."); executor_->Execute(nextPair->barrier_); } else { - // NOTREACHED. - APP_LOGD("Barrier.onTaskDone: Detected an empty node."); + APP_LOGW("Barrier.onTaskDone: Detected an empty node."); } } } @@ -128,12 +137,14 @@ void BarrierHandler::OnTaskDone(std::shared_ptr &task) } if (!removed) { - APP_LOGD("Barrier.onTaskDone: Task remove failed."); + APP_LOGI("Barrier.onTaskDone: Task remove failed."); } + APP_LOGI("BarrierHandler::OnTaskDone end"); } bool BarrierHandler::AddTaskAfterBarrier(std::shared_ptr &task) { + APP_LOGI("BarrierHandler::AddTaskAfterBarrier start"); std::unique_lock lock(barrierLock_); std::shared_ptr pair = barrierQueue_.size() == 0 ? nullptr : barrierQueue_.back(); if ((pair == nullptr) || (pair->barrier_ != nullptr)) { @@ -149,6 +160,7 @@ bool BarrierHandler::AddTaskAfterBarrier(std::shared_ptr &task) } else { pair->tasks_.insert(task); } + APP_LOGI("BarrierHandler::AddTaskAfterBarrier end"); return (barrierQueue_.size() > 1); } diff --git a/interfaces/innerkits/task_dispatcher/src/task/sync_task.cpp b/interfaces/innerkits/task_dispatcher/src/task/sync_task.cpp index ebe4759e83..bb005a0a77 100644 --- a/interfaces/innerkits/task_dispatcher/src/task/sync_task.cpp +++ b/interfaces/innerkits/task_dispatcher/src/task/sync_task.cpp @@ -38,26 +38,26 @@ void SyncTask::Run() { std::unique_lock lock(mutex_); auto threadId = std::this_thread::get_id(); - APP_LOGD("SyncTask::Run begin thread=%{public}zu", CalculateHashCode(threadId)); + APP_LOGI("SyncTask::Run begin thread=%{public}zu", CalculateHashCode(threadId)); Task::Run(); executed_.store(true); // |waitTask| may have been multi invoked. condition_variable_.notify_all(); - APP_LOGD("SyncTask::Run end thread=%{public}zu", CalculateHashCode(threadId)); + APP_LOGI("SyncTask::Run end thread=%{public}zu", CalculateHashCode(threadId)); } void SyncTask::WaitTask() { auto threadId = std::this_thread::get_id(); - APP_LOGD("SyncTask::WaitTask begin thread=%{public}zu", CalculateHashCode(threadId)); + APP_LOGI("SyncTask::WaitTask begin thread=%{public}zu", CalculateHashCode(threadId)); std::unique_lock lock(mutex_); while (executed_ == false) { condition_variable_.wait(lock); } - APP_LOGD("SyncTask::WaitTask end thread=%{public}zu", CalculateHashCode(threadId)); + APP_LOGI("SyncTask::WaitTask end thread=%{public}zu", CalculateHashCode(threadId)); } } // namespace AppExecFwk diff --git a/interfaces/innerkits/task_dispatcher/src/task/task.cpp b/interfaces/innerkits/task_dispatcher/src/task/task.cpp index 9f3ce15443..dd23ef89d6 100644 --- a/interfaces/innerkits/task_dispatcher/src/task/task.cpp +++ b/interfaces/innerkits/task_dispatcher/src/task/task.cpp @@ -30,8 +30,8 @@ Task::Task(const std::shared_ptr &runnable, const TaskPriority priorit runnable_ = runnable; priority_ = priority; baseTaskDispatcher_ = baseTaskDispatcher; - std::atomic_init(&state_, 0); - APP_LOGD("Task::Task init listener count=%{public}zu", taskListeners_.Size()); + std::atomic_init(&state_, 0U); + APP_LOGI("Task::Task init listener count=%{public}zu", taskListeners_.Size()); } Task::~Task() {} @@ -43,17 +43,17 @@ Task::~Task() */ void Task::Run() { - APP_LOGD("Task::Run task run called start"); + APP_LOGI("Task::Run task run called start"); if (runnable_ == nullptr) { APP_LOGI("Task::Run called runnable_ is null"); return; } // Task cannot be reused. if (EnterExecute()) { - APP_LOGD("Task::Run runnable_ Run called start"); + APP_LOGI("Task::Run runnable_ Run called start"); (*runnable_.get())(); } - APP_LOGD("Task::Run runnable_ Run called end"); + APP_LOGI("Task::Run runnable_ Run called end"); } /** @@ -95,11 +95,11 @@ long Task::GetSequence() const bool Task::Revoke() { if (runnable_ == nullptr) { - APP_LOGI("Task.Revoke called runnable_ is null"); + APP_LOGE("Task.Revoke called runnable_ is null"); return false; } RevokeResult result = SetRevoked(); - APP_LOGD("Task.Revoke result: %{public}u", result); + APP_LOGI("Task.Revoke result: %{public}u", result); if (result == SUCCESS) { OnTaskCanceled(); } @@ -113,7 +113,7 @@ bool Task::Revoke() */ void Task::AddTaskListener(const std::shared_ptr &listener) { - APP_LOGD("Task.AddTaskListener listener called start"); + APP_LOGI("Task.AddTaskListener listener called start"); taskListeners_.Offer(listener); } @@ -137,7 +137,7 @@ void Task::BeforeTaskExecute() void Task::AfterTaskExecute() { if ((state_ & EXECUTED) == EXECUTED) { - APP_LOGD("Task.AfterTaskExecute taskStage called AFTER_EXECUTE"); + APP_LOGI("Task.AfterTaskExecute taskStage called AFTER_EXECUTE"); ConcurrentQueueStatusUpdate(TaskStage::AFTER_EXECUTE); } } @@ -149,7 +149,7 @@ void Task::AfterTaskExecute() */ void Task::OnTaskCanceled() { - APP_LOGD("Task.OnTaskCanceled taskStage called REVOKED"); + APP_LOGI("Task.OnTaskCanceled taskStage called REVOKED"); ConcurrentQueueStatusUpdate(TaskStage::REVOKED); } @@ -160,17 +160,17 @@ void Task::OnTaskCanceled() */ bool Task::EnterExecute() { - int stateNotIn = EXECUTED | REVOKED; + unsigned int stateNotIn = EXECUTED | REVOKED; while (true) { - int value = state_.load(); + unsigned int value = state_.load(); if ((state_ & stateNotIn) == 0) { // Not executed or revoked if (state_.compare_exchange_strong(value, EXECUTED)) { - APP_LOGD("Task.EnterExecute return success"); + APP_LOGI("Task.EnterExecute return success"); return true; } } else { - APP_LOGD("Task.EnterExecute return fail, state=%{public}d, stateNotIn=%{public}d", value, stateNotIn); + APP_LOGE("Task.EnterExecute return fail, state=%{public}d, stateNotIn=%{public}d", value, stateNotIn); return false; } } @@ -179,18 +179,18 @@ bool Task::EnterExecute() Task::RevokeResult Task::SetRevoked() { while (true) { - int value = state_.load(); + unsigned int value = state_.load(); if ((value & REVOKED) == REVOKED) { - APP_LOGD("Task.SetRevoked return ALREADY_REVOKED"); + APP_LOGW("Task.SetRevoked return ALREADY_REVOKED"); return ALREADY_REVOKED; } if ((value & EXECUTED) == 0) { if (state_.compare_exchange_strong(value, REVOKED)) { - APP_LOGD("Task.SetRevoked return SUCCESS"); + APP_LOGI("Task.SetRevoked return SUCCESS"); return SUCCESS; } } else { - APP_LOGD("Task.SetRevoked return FAIL"); + APP_LOGE("Task.SetRevoked return FAIL"); return FAIL; } } @@ -198,7 +198,7 @@ Task::RevokeResult Task::SetRevoked() void Task::ConcurrentQueueStatusUpdate(const TaskStage::TASKSTAGE taskstage) { - APP_LOGD("Task.ConcurrentQueueStatusUpdate taskListeners_ called start"); + APP_LOGI("Task.ConcurrentQueueStatusUpdate taskListeners_ called start"); for (auto iter = taskListeners_.Begin(); iter != taskListeners_.End(); iter++) { (*iter)->OnChanged(taskstage); } diff --git a/interfaces/innerkits/task_dispatcher/src/threading/default_thread_factory.cpp b/interfaces/innerkits/task_dispatcher/src/threading/default_thread_factory.cpp index 8f1bad5e07..7b8d379181 100644 --- a/interfaces/innerkits/task_dispatcher/src/threading/default_thread_factory.cpp +++ b/interfaces/innerkits/task_dispatcher/src/threading/default_thread_factory.cpp @@ -28,9 +28,9 @@ std::shared_ptr DefaultThreadFactory::Create() int value = std::atomic_fetch_add(&index_, 1); std::string name = std::string("PoolThread-") + std::to_string(value); pThread->thread_name_ = name; - APP_LOGD("DefaultThreadFactory::Create thread name is %{public}s", name.c_str()); + APP_LOGI("DefaultThreadFactory::Create thread name is %{public}s", name.c_str()); } else { - APP_LOGD("DefaultThreadFactory::Create error"); + APP_LOGE("DefaultThreadFactory::Create error, thread is nullptr"); } return pThread; diff --git a/interfaces/innerkits/task_dispatcher/src/threading/task_executor.cpp b/interfaces/innerkits/task_dispatcher/src/threading/task_executor.cpp index 4aec05bb92..406f79dd31 100644 --- a/interfaces/innerkits/task_dispatcher/src/threading/task_executor.cpp +++ b/interfaces/innerkits/task_dispatcher/src/threading/task_executor.cpp @@ -30,15 +30,15 @@ TaskExecutor::TaskExecutor(const std::shared_ptr &config) : Wo TaskExecutor::~TaskExecutor() { if ((consumer_) && consumer_->joinable()) { - APP_LOGD("TaskExecutor::~TaskExecutor consumer is running"); + APP_LOGI("TaskExecutor::~TaskExecutor consumer is running"); consumer_->join(); } - APP_LOGD("TaskExecutor::~TaskExecutor"); + APP_LOGI("TaskExecutor::~TaskExecutor"); } void TaskExecutor::Execute(const std::shared_ptr &task) { - APP_LOGD("TaskExecutor::Execute begin"); + APP_LOGI("TaskExecutor::Execute begin"); task->SetSequence(GetAndIncrement(sequence)); std::shared_ptr executor = shared_from_this(); @@ -50,12 +50,12 @@ void TaskExecutor::Execute(const std::shared_ptr &task) APP_LOGW("TaskExecutor::Execute rejected a task"); } } - APP_LOGD("TaskExecutor::Execute end"); + APP_LOGI("TaskExecutor::Execute end"); } ErrCode TaskExecutor::DoWorks(const std::shared_ptr &worker) { - APP_LOGD("TaskExecutor::DoWorks begin"); + APP_LOGI("TaskExecutor::DoWorks begin"); if (worker == nullptr) { APP_LOGE("TaskExecutor::DoWorks worker is nullptr"); return ERR_APPEXECFWK_CHECK_FAILED; @@ -70,7 +70,7 @@ ErrCode TaskExecutor::DoWorks(const std::shared_ptr &worker) bool isInterrupted = false; bool done = false; while (((task != nullptr && done == false) || ((task = GetTask(worker)) != nullptr))) { - APP_LOGD("TaskExecutor::DoWorks loop tasks."); + APP_LOGI("TaskExecutor::DoWorks loop tasks."); BeforeRun(task); @@ -85,7 +85,7 @@ ErrCode TaskExecutor::DoWorks(const std::shared_ptr &worker) done = true; } OnWorkerExit(worker, isInterrupted); - APP_LOGD("TaskExecutor::DoWorks end"); + APP_LOGI("TaskExecutor::DoWorks end"); return ERR_OK; } std::shared_ptr TaskExecutor::GetTask(const std::shared_ptr &workerThread) @@ -96,33 +96,33 @@ std::shared_ptr TaskExecutor::GetTask(const std::shared_ptr for (;;) { if (terminated_.load() && pendingTasks_->Empty()) { - APP_LOGD("TaskExecutor::GetTask end: loop thread %{public}s is terminated", + APP_LOGI("TaskExecutor::GetTask end: loop thread %{public}s is terminated", workerThread->GetThreadName().c_str()); DecrementThread(); return nullRunnable; } int workerCount = GetWorkCount(); - APP_LOGD("TaskExecutor::GetTask workerCount:%{public}d, GetCoreThreadCount: %{public}d", + APP_LOGI("TaskExecutor::GetTask workerCount:%{public}d, GetCoreThreadCount: %{public}d", workerCount, GetCoreThreadCount()); bool needCheckTimeout = (workerCount > GetCoreThreadCount()); if (isTimeout && needCheckTimeout && pendingTasks_->Empty()) { - APP_LOGD("TaskExecutor::GetTask isTimeout is true"); + APP_LOGI("TaskExecutor::GetTask isTimeout is true"); if (CompareAndDecNum(workerCount)) { - APP_LOGD("TaskExecutor::GetTask end: loop thread %{public}s is timeout", + APP_LOGI("TaskExecutor::GetTask end: loop thread %{public}s is timeout", workerThread->GetThreadName().c_str()); return nullRunnable; } continue; } - APP_LOGD("TaskExecutor::GetTask need timeout=%{public}d", needCheckTimeout); + APP_LOGI("TaskExecutor::GetTask need timeout=%{public}d", needCheckTimeout); std::shared_ptr next = needCheckTimeout ? pendingTasks_->Poll(GetKeepAliveTime()) : pendingTasks_->Take(); if (next != nullptr && next->task_ != nullptr) { - APP_LOGD("TaskExecutor::GetTask end: loop thread %{public}s get next task", + APP_LOGI("TaskExecutor::GetTask end: loop thread %{public}s get next task", workerThread->GetThreadName().c_str()); return next->task_; } @@ -132,10 +132,10 @@ std::shared_ptr TaskExecutor::GetTask(const std::shared_ptr void TaskExecutor::Terminate(bool force) { - APP_LOGD("TaskExecutor::Terminate begin"); + APP_LOGI("TaskExecutor::Terminate begin"); TerminateConsumer(); ClosePool(force); - APP_LOGD("TaskExecutor::Terminate end"); + APP_LOGI("TaskExecutor::Terminate end"); } void TaskExecutor::AfterRun(const std::shared_ptr &task) @@ -152,7 +152,7 @@ bool TaskExecutor::DelayExecute(const Runnable &task, long delayMs) { if (delayMs <= 0) { task(); - APP_LOGD("TaskExecutor::DelayExecute end and delayMs less than 0"); + APP_LOGI("TaskExecutor::DelayExecute end and delayMs less than 0"); return true; } if (terminated_.load()) { @@ -192,10 +192,10 @@ bool TaskExecutor::EnsureConsumeStarted() if (consumer_ == nullptr) { consumer_ = std::make_shared(&TaskExecutor::Consume, this); if (consumer_ == nullptr) { - APP_LOGD("TaskExecutor::EnsureConsumeStarted consumer_ is nullptr"); + APP_LOGE("TaskExecutor::EnsureConsumeStarted consumer_ is nullptr"); return false; } - APP_LOGD("TaskExecutor::EnsureConsumeStarted start a delay task consumer"); + APP_LOGI("TaskExecutor::EnsureConsumeStarted start a delay task consumer"); } } } @@ -206,16 +206,16 @@ void TaskExecutor::Consume() { for (;;) { if (terminated_.load() && delayTasks_->Empty()) { - APP_LOGD("TaskExecutor::Consume delay task is empty"); + APP_LOGI("TaskExecutor::Consume delay task is empty"); break; } std::shared_ptr delayTaskWrapper = delayTasks_->Take(); if (delayTaskWrapper == nullptr || delayTaskWrapper->runnable_ == nullptr) { - APP_LOGD("TaskExecutor::Consume delayTaskWrapper is nullptr"); + APP_LOGE("TaskExecutor::Consume delayTaskWrapper is nullptr"); return; }; (delayTaskWrapper->runnable_)(); - APP_LOGD("TaskExecutor::Consume after run"); + APP_LOGI("TaskExecutor::Consume after run"); } } diff --git a/interfaces/innerkits/task_dispatcher/src/threading/work_thread.cpp b/interfaces/innerkits/task_dispatcher/src/threading/work_thread.cpp index 04f135a5cf..ece157d5ba 100644 --- a/interfaces/innerkits/task_dispatcher/src/threading/work_thread.cpp +++ b/interfaces/innerkits/task_dispatcher/src/threading/work_thread.cpp @@ -30,10 +30,10 @@ WorkerThread::WorkerThread(const std::shared_ptr &delegate, const std: void WorkerThread::Join() { if ((thread_) && (thread_->thread_) && thread_->thread_->joinable()) { - APP_LOGD("WorkerThread::Join joinable thread"); + APP_LOGI("WorkerThread::Join joinable thread"); thread_->thread_->join(); } - APP_LOGD("WorkerThread::Join end"); + APP_LOGI("WorkerThread::Join end"); } void WorkerThread::CreateThread() @@ -48,7 +48,7 @@ void WorkerThread::CreateThread() // start a thread to run task function. thread_->thread_ = std::make_shared(task); - APP_LOGD("WorkerThread::CreateThread start thread. "); + APP_LOGI("WorkerThread::CreateThread start thread. "); } void WorkerThread::IncTaskCount() diff --git a/interfaces/innerkits/task_dispatcher/src/threading/worker_pool.cpp b/interfaces/innerkits/task_dispatcher/src/threading/worker_pool.cpp index 4bdfa2289e..1376449706 100644 --- a/interfaces/innerkits/task_dispatcher/src/threading/worker_pool.cpp +++ b/interfaces/innerkits/task_dispatcher/src/threading/worker_pool.cpp @@ -23,7 +23,7 @@ const int WorkerPool::THREAD_UPPER_LIMIT = 256; const int WorkerPool::MAX_THREAD_LOWER_LIMIT = 1; const int WorkerPool::CORE_THREAD_LOWER_LIMIT = 0; const int WorkerPool::COUNT_BITS = sizeof(int) * __CHAR_BIT__ - 3; -const int WorkerPool::CAPACITY = (1 << COUNT_BITS) - 1; +const unsigned int WorkerPool::CAPACITY = (1 << COUNT_BITS) - 1; const int WorkerPool::RUNNING = (-(1 << COUNT_BITS)); const int WorkerPool::CLOSING = (0 << COUNT_BITS); const int WorkerPool::INTERRUPT = (1 << COUNT_BITS); @@ -44,7 +44,7 @@ WorkerPool::~WorkerPool() { control_ = 0; - APP_LOGD("WorkerPool::~WorkerPool"); + APP_LOGI("WorkerPool::~WorkerPool"); } bool WorkerPool::Init(const std::shared_ptr &config) @@ -128,7 +128,7 @@ int WorkerPool::GetMaxThreadCount(void) const int WorkerPool::GetWorkCount(void) const { - int value = control_.load(); + unsigned int value = control_.load(); return GetWorkingThreadNum(value); } @@ -147,19 +147,20 @@ std::map WorkerPool::GetWorkerThreadsInfo(void) void WorkerPool::ClosePool(bool interrupt) { - APP_LOGD("WorkerPool::ClosePool begin interrupt=%{public}d", interrupt); + APP_LOGI("WorkerPool::ClosePool begin interrupt=%{public}d", interrupt); std::unique_lock mLock(poolLock_); AdvanceStateTo(CLOSING); InterruptWorkers(); - APP_LOGD("WorkerPool::ClosePool end"); + APP_LOGI("WorkerPool::ClosePool end"); } void WorkerPool::InterruptWorkers(void) { - APP_LOGD("WorkerPool::InterruptWorkers begin"); + APP_LOGI("WorkerPool::InterruptWorkers begin"); if (guardThread_ == nullptr) { + APP_LOGE("WorkerPool::InterruptWorkers guardThread is nullptr"); return; } poolLock_.unlock(); @@ -174,18 +175,19 @@ void WorkerPool::InterruptWorkers(void) std::unique_lock lock(exitPoolLock_); exitGuard_.wait(lock); if (guardThread_->joinable()) { - APP_LOGD("WorkerPool::InterruptWorkers guardThread_ joinable"); + APP_LOGI("WorkerPool::InterruptWorkers guardThread_ joinable"); guardThread_->join(); - guardThread_ = nullptr; // 防止再次手动调用 + // Prevent manual call again + guardThread_ = nullptr; } } - APP_LOGD("WorkerPool::InterruptWorkers end"); + APP_LOGI("WorkerPool::InterruptWorkers end"); } void WorkerPool::CreateGuardThread() { - APP_LOGD("WorkerPool::CreateGuardThread START"); + APP_LOGI("WorkerPool::CreateGuardThread START"); if (guardThread_ != nullptr) { APP_LOGW("WorkerPool::CreateGuardThread guardThread_ is not nullptr"); return; @@ -205,11 +207,11 @@ void WorkerPool::CreateGuardThread() } if (stop_.load() && exitPool_.empty() && pool_.empty()) { exitGuard_.notify_all(); - APP_LOGD("WorkerPool::CreateGuardThread break while"); + APP_LOGI("WorkerPool::CreateGuardThread break while"); break; } } - APP_LOGD("WorkerPool::CreateGuardThread STOP"); + APP_LOGI("WorkerPool::CreateGuardThread STOP"); }; guardThread_ = std::make_shared(guardTask); @@ -238,16 +240,16 @@ bool WorkerPool::AddWorker(const std::shared_ptr &delegate, const std: std::shared_ptr newThread = nullptr; for (;;) { - int value = control_.load(); + unsigned int value = control_.load(); int num = GetWorkingThreadNum(value); if (num >= thread_limit_) { - APP_LOGD("WorkerPool::AddWorker thread count exceed limits, num=%{public}d, limits=%{public}d", + APP_LOGI("WorkerPool::AddWorker thread count exceed limits, num=%{public}d, limits=%{public}d", num, thread_limit_); break; } if (!IsRunning(value)) { - APP_LOGD("WorkerPool::AddWorker thread pool is not running. value=%{public}d, closing=%{public}d, " + APP_LOGI("WorkerPool::AddWorker thread pool is not running. value=%{public}d, closing=%{public}d, " "count_bits=%{public}d", value, CLOSING, @@ -264,35 +266,33 @@ bool WorkerPool::AddWorker(const std::shared_ptr &delegate, const std: newThread->CreateThread(); - APP_LOGD("WorkerPool::AddWorker create new thread"); + APP_LOGI("WorkerPool::AddWorker create new thread"); pool_.emplace_back(newThread); - APP_LOGD("POOL SIZE: %{public}zu", pool_.size()); - APP_LOGD("pool_ add end"); + APP_LOGI("WorkerPool::AddWorker pool_ add thread ,POOL SIZE: %{public}zu", pool_.size()); added = true; break; } - APP_LOGD("WorkerPool::AddWorker set thread state error. retry. "); + APP_LOGW("WorkerPool::AddWorker set thread state error. retry. "); } return added; } void WorkerPool::OnWorkerExit(const std::shared_ptr &worker, bool isInterrupted) { - std::unique_lock mLock(poolLock_); - APP_LOGD("WorkerPool::OnWorkerExit start"); - APP_LOGD("size:%{public}zu", pool_.size()); + APP_LOGI("WorkerPool::OnWorkerExit start, pool size: %{public}zu", pool_.size()); for (auto it = pool_.begin(); it != pool_.end(); it++) { if ((*it).get() == worker.get()) { - APP_LOGD("WorkerPool::OnWorkerExit erase current, size=%{public}zu, threads=%{public}d", + APP_LOGI("WorkerPool::OnWorkerExit erase current, size=%{public}zu, threads=%{public}d", pool_.size(), GetWorkingThreadNum(control_.load())); { std::unique_lock lock(exitPoolLock_); exitPool_.emplace_back(worker); + APP_LOGI("WorkerPool::OnWorkerExit exit notify all"); exit_.notify_all(); } pool_.erase(it); @@ -300,7 +300,7 @@ void WorkerPool::OnWorkerExit(const std::shared_ptr &worker, bool break; } } - APP_LOGD("WorkerPool::OnWorkerExit end"); + APP_LOGI("WorkerPool::OnWorkerExit end"); } void WorkerPool::AfterRun(const std::shared_ptr &task) @@ -309,7 +309,7 @@ void WorkerPool::AfterRun(const std::shared_ptr &task) void WorkerPool::BeforeRun(const std::shared_ptr &task) {} -int WorkerPool::GetWorkingThreadNum(int ctl) +unsigned int WorkerPool::GetWorkingThreadNum(unsigned int ctl) { return ctl & CAPACITY; } @@ -324,21 +324,21 @@ int WorkerPool::GetStateFromControl(int ctl) return ctl & ~CAPACITY; } -void WorkerPool::AdvanceStateTo(int target) +void WorkerPool::AdvanceStateTo(unsigned int target) { - APP_LOGD("WorkerPool::AdvanceStateTo begin"); + APP_LOGI("WorkerPool::AdvanceStateTo begin"); for (;;) { - int current = control_.load(); + unsigned int current = control_.load(); if ((current >= target) || CompareAndSet(control_, current, CombineToControl(target, GetWorkingThreadNum(current)))) { - APP_LOGD("WorkerPool::AdvanceStateTo break"); + APP_LOGI("WorkerPool::AdvanceStateTo break"); break; } } - APP_LOGD("WorkerPool::AdvanceStateTo end"); + APP_LOGI("WorkerPool::AdvanceStateTo end"); } -int WorkerPool::CombineToControl(int state, int count) +int WorkerPool::CombineToControl(unsigned int state, unsigned int count) { return state | count; } @@ -352,12 +352,12 @@ bool WorkerPool::CompareAndIncThreadNum(int expect) void WorkerPool::DecrementThread(void) { - APP_LOGD("WorkerPool::DecrementThread begin"); + APP_LOGI("WorkerPool::DecrementThread begin"); int curr = control_.load(); while (!CompareAndDecThreadNum(curr)) { curr = control_.load(); } - APP_LOGD("WorkerPool::DecrementThread end"); + APP_LOGI("WorkerPool::DecrementThread end"); } bool WorkerPool::CompareAndDecThreadNum(int expect) diff --git a/interfaces/innerkits/task_dispatcher/test/unittest/base_task_dispatcher_test/base_task_dispatcher_test.cpp b/interfaces/innerkits/task_dispatcher/test/unittest/base_task_dispatcher_test/base_task_dispatcher_test.cpp index a764060c23..dd2ada38bd 100644 --- a/interfaces/innerkits/task_dispatcher/test/unittest/base_task_dispatcher_test/base_task_dispatcher_test.cpp +++ b/interfaces/innerkits/task_dispatcher/test/unittest/base_task_dispatcher_test/base_task_dispatcher_test.cpp @@ -73,17 +73,10 @@ void BaseTaskDispatcherTest::TearDown() context = nullptr; ptrSerialTaskDispatcher = nullptr; } -std::string Now() -{ - time_t now = std::time(0); - char mbstr[10]; - std::strftime(mbstr, sizeof(mbstr), "%T", std::localtime(&now)); - return mbstr; -} const std::string Prefix(const std::string &name) { - return std::string(">>> ") + Now() + std::string(" ") + name + std::string(": "); + return std::string(">>> prefix :") + std::string(" ") + name + std::string(": "); } /** @@ -171,7 +164,7 @@ HWTEST_F(BaseTaskDispatcherTest, AsyncDispatchBarrier_0100, Function | MediumTes })); // async execute - ASSERT_LT(count.load(), 1); + EXPECT_LT(count.load(), 1); long sleep2 = 100; ptrSerialTaskDispatcher->AsyncDispatchBarrier(std::make_shared([&]() { @@ -182,7 +175,7 @@ HWTEST_F(BaseTaskDispatcherTest, AsyncDispatchBarrier_0100, Function | MediumTes GTEST_LOG_(INFO) << Prefix(name) << "AsyncDispatchBarrier-" << index << " thread " << std::this_thread::get_id() << ", sleep for " << sleep2 << " ms"; })); - ASSERT_LT(count.load(), 2); + EXPECT_LT(count.load(), 2); long wait = sleep1 + sleep2 + 100; GTEST_LOG_(INFO) << Prefix(name) << "wait for " << (wait); auto time = std::chrono::milliseconds(wait); @@ -202,7 +195,7 @@ HWTEST_F(BaseTaskDispatcherTest, CreateDispatchGroup_0100, Function | MediumTest { GTEST_LOG_(INFO) << "CreateDispatchGroup_0100 start"; std::shared_ptr gptr = ptrSerialTaskDispatcher->CreateDispatchGroup(); - ASSERT_TRUE(ptrSerialTaskDispatcher->GroupDispatchWait(gptr, 10)); + EXPECT_TRUE(ptrSerialTaskDispatcher->GroupDispatchWait(gptr, 10)); GTEST_LOG_(INFO) << "CreateDispatchGroup_0100 end"; } @@ -230,7 +223,7 @@ HWTEST_F(BaseTaskDispatcherTest, AsyncGroupDispatch_0100, Function | MediumTest })); // async execute - ASSERT_LT(count.load(), 1); + EXPECT_LT(count.load(), 1); long sleep2 = 100; ptrSerialTaskDispatcher->AsyncGroupDispatch(gptr, std::make_shared([&count, &sleep2, &name]() { @@ -241,7 +234,7 @@ HWTEST_F(BaseTaskDispatcherTest, AsyncGroupDispatch_0100, Function | MediumTest GTEST_LOG_(INFO) << Prefix(name) << "AsyncGroupDispatch-" << index << " thread " << std::this_thread::get_id() << ", sleep for " << sleep2 << " ms"; })); - ASSERT_LT(count.load(), 2); + EXPECT_LT(count.load(), 2); long wait = sleep1 + sleep2 + 100; GTEST_LOG_(INFO) << Prefix(name) << "wait for " << (wait); auto time = std::chrono::milliseconds(wait); @@ -285,7 +278,7 @@ HWTEST_F(BaseTaskDispatcherTest, ApplyDispatch_0100, Function | MediumTest | Lev }); ptrSerialTaskDispatcher->ApplyDispatch(repeats2, 10); // async execute - ASSERT_LT(count.load(), 20); + EXPECT_LT(count.load(), 20); long wait = sleep1 * 10 + sleep2 * 10 + 100 + 100; GTEST_LOG_(INFO) << Prefix(name) << "wait for " << (wait); auto time = std::chrono::milliseconds(wait); @@ -339,7 +332,7 @@ HWTEST_F(BaseTaskDispatcherTest, GroupDispatchWait_0100, Function | MediumTest | { GTEST_LOG_(INFO) << "GroupDispatchWait_0100 start"; std::shared_ptr gptr = ptrSerialTaskDispatcher->CreateDispatchGroup(); - ASSERT_TRUE(ptrSerialTaskDispatcher->GroupDispatchWait(gptr, 0)); + EXPECT_TRUE(ptrSerialTaskDispatcher->GroupDispatchWait(gptr, 0)); GTEST_LOG_(INFO) << "GroupDispatchWait_0100 end"; } diff --git a/interfaces/innerkits/task_dispatcher/test/unittest/parallel_task_dispatcher_base_test/parallel_task_dispatcher_base_test.cpp b/interfaces/innerkits/task_dispatcher/test/unittest/parallel_task_dispatcher_base_test/parallel_task_dispatcher_base_test.cpp index 7822421c35..5347daaca1 100644 --- a/interfaces/innerkits/task_dispatcher/test/unittest/parallel_task_dispatcher_base_test/parallel_task_dispatcher_base_test.cpp +++ b/interfaces/innerkits/task_dispatcher/test/unittest/parallel_task_dispatcher_base_test/parallel_task_dispatcher_base_test.cpp @@ -87,7 +87,7 @@ HWTEST(ParallelTaskDispatcherBaseTest, ParallelTaskDispatcherBase_SyncDispatchTe std::shared_ptr parallelTaskDispatcherBase = CreateParallelTaskDispatcherBase(name, TaskPriority::DEFAULT); ErrCode errCode = parallelTaskDispatcherBase->SyncDispatch(nullptr); - ASSERT_TRUE(errCode == ERR_APPEXECFWK_CHECK_FAILED); + EXPECT_TRUE(errCode == ERR_APPEXECFWK_CHECK_FAILED); std::atomic count(0); EXPECT_EQ(count.load(), 0); std::shared_ptr rptr = std::make_shared([&]() { @@ -120,7 +120,7 @@ HWTEST(ParallelTaskDispatcherBaseTest, ParallelTaskDispatcherBase_AsyncDispatchT std::shared_ptr parallelTaskDispatcherBase = CreateParallelTaskDispatcherBase(name, TaskPriority::DEFAULT); std::shared_ptr revocable = parallelTaskDispatcherBase->AsyncDispatch(nullptr); - ASSERT_TRUE(revocable == nullptr); + EXPECT_TRUE(revocable == nullptr); std::atomic count(0); EXPECT_EQ(count.load(), 0); std::shared_ptr rptr = std::make_shared([&]() { @@ -177,7 +177,7 @@ HWTEST(ParallelTaskDispatcherBaseTest, ParallelTaskDispatcherBase_DelayDispatchT GTEST_LOG_(INFO) << name << " Runnable"; }); std::shared_ptr revocable = parallelTaskDispatcherBase->DelayDispatch(nullptr, 1000); - ASSERT_TRUE(revocable == nullptr); + EXPECT_TRUE(revocable == nullptr); GTEST_LOG_(INFO) << name << " end"; } @@ -235,6 +235,6 @@ HWTEST(ParallelTaskDispatcherBaseTest, ParallelTaskDispatcherBase_AsyncGroupDisp CreateParallelTaskDispatcherBase(name, TaskPriority::DEFAULT); std::shared_ptr revocable = parallelTaskDispatcherBase->AsyncGroupDispatch(nullptr, nullptr); - ASSERT_TRUE(revocable == nullptr); + EXPECT_TRUE(revocable == nullptr); GTEST_LOG_(INFO) << name << " end"; } \ No newline at end of file diff --git a/interfaces/innerkits/task_dispatcher/test/unittest/parallel_task_dispatcher_test/parallel_task_dispatcher_test.cpp b/interfaces/innerkits/task_dispatcher/test/unittest/parallel_task_dispatcher_test/parallel_task_dispatcher_test.cpp index f7a5cec774..0fa744cf87 100644 --- a/interfaces/innerkits/task_dispatcher/test/unittest/parallel_task_dispatcher_test/parallel_task_dispatcher_test.cpp +++ b/interfaces/innerkits/task_dispatcher/test/unittest/parallel_task_dispatcher_test/parallel_task_dispatcher_test.cpp @@ -110,7 +110,7 @@ HWTEST(ParallelTaskDispatcherTest, ParallelTaskDispatcher_SyncDispatchBarrierTes std::shared_ptr parallelTaskDispatcher = CreateParallelTaskDispatcher(name, TaskPriority::DEFAULT); ErrCode result = parallelTaskDispatcher->SyncDispatchBarrier(nullptr); - ASSERT_TRUE(result == ERR_APPEXECFWK_CHECK_FAILED); + EXPECT_TRUE(result == ERR_APPEXECFWK_CHECK_FAILED); GTEST_LOG_(INFO) << name << " end"; } @@ -149,6 +149,6 @@ HWTEST(ParallelTaskDispatcherTest, ParallelTaskDispatcher_AsyncDispatchBarrierTe std::shared_ptr parallelTaskDispatcher = CreateParallelTaskDispatcher(name, TaskPriority::DEFAULT); ErrCode result = parallelTaskDispatcher->AsyncDispatchBarrier(nullptr); - ASSERT_TRUE(result == ERR_APPEXECFWK_CHECK_FAILED); + EXPECT_TRUE(result == ERR_APPEXECFWK_CHECK_FAILED); GTEST_LOG_(INFO) << name << " end"; } diff --git a/interfaces/innerkits/task_dispatcher/test/unittest/serial_task_dispatcher_test/serial_task_dispatcher_test.cpp b/interfaces/innerkits/task_dispatcher/test/unittest/serial_task_dispatcher_test/serial_task_dispatcher_test.cpp index dcbcc7eb86..e9033f2e9f 100644 --- a/interfaces/innerkits/task_dispatcher/test/unittest/serial_task_dispatcher_test/serial_task_dispatcher_test.cpp +++ b/interfaces/innerkits/task_dispatcher/test/unittest/serial_task_dispatcher_test/serial_task_dispatcher_test.cpp @@ -51,14 +51,14 @@ HWTEST(SerialTaskDispatcherTest, SerialTaskDispatcher_SyncDispatchTest_1000, Tes std::shared_ptr dispatcher = std::make_shared(name, priority, executor); std::atomic count(0); - ASSERT_TRUE(count.load() == 0); + EXPECT_TRUE(count.load() == 0); dispatcher->SyncDispatch(std::make_shared([&count, &name]() { int index = count.fetch_add(1); - ASSERT_TRUE(index == 0); + EXPECT_TRUE(index == 0); GTEST_LOG_(INFO) << name + " task " + std::to_string(index) + " end"; })); - ASSERT_TRUE(count.load() == 1); + EXPECT_TRUE(count.load() == 1); GTEST_LOG_(INFO) << name + " end"; } @@ -221,21 +221,21 @@ HWTEST(SerialTaskDispatcherTest, SerialTaskDispatcher_GetWorkingTasksSizeTest_00 auto time = std::chrono::milliseconds(wait); std::this_thread::sleep_for(time); GTEST_LOG_(INFO) << name + " size: " + std::to_string(dispatcher->GetWorkingTasksSize()); - ASSERT_EQ(dispatcher->GetWorkingTasksSize(), 2 - 1); + EXPECT_EQ(dispatcher->GetWorkingTasksSize(), 2 - 1); } { long wait = 2000; auto time = std::chrono::milliseconds(wait); std::this_thread::sleep_for(time); GTEST_LOG_(INFO) << name + " size: " + std::to_string(dispatcher->GetWorkingTasksSize()); - ASSERT_EQ(dispatcher->GetWorkingTasksSize(), 1 - 1); + EXPECT_EQ(dispatcher->GetWorkingTasksSize(), 1 - 1); } { long wait = 2000; auto time = std::chrono::milliseconds(wait); std::this_thread::sleep_for(time); GTEST_LOG_(INFO) << name + " size: " + std::to_string(dispatcher->GetWorkingTasksSize()); - ASSERT_EQ(dispatcher->GetWorkingTasksSize(), 0); + EXPECT_EQ(dispatcher->GetWorkingTasksSize(), 0); } long wait = 5000; auto time = std::chrono::milliseconds(wait); @@ -271,14 +271,14 @@ HWTEST(SerialTaskDispatcherTest, SerialTaskDispatcher_GetWorkingTasksSizeTest_00 auto time = std::chrono::milliseconds(wait); std::this_thread::sleep_for(time); GTEST_LOG_(INFO) << name + " size: " + std::to_string(dispatcher->GetWorkingTasksSize()); - ASSERT_EQ(dispatcher->GetWorkingTasksSize(), times - 1); + EXPECT_EQ(dispatcher->GetWorkingTasksSize(), times - 1); } { - long wait = 300 * times; + long wait = 300 * (long)times; auto time = std::chrono::milliseconds(wait); std::this_thread::sleep_for(time); GTEST_LOG_(INFO) << name + " size: " + std::to_string(dispatcher->GetWorkingTasksSize()); - ASSERT_EQ(dispatcher->GetWorkingTasksSize(), 0); + EXPECT_EQ(dispatcher->GetWorkingTasksSize(), 0); } GTEST_LOG_(INFO) << name + " end"; @@ -302,39 +302,39 @@ HWTEST(SerialTaskDispatcherTest, SerialTaskDispatcher_SyncDispatchTest_001, Test std::shared_ptr dispatcher = std::make_shared("", priority, executor); std::atomic count(0); - ASSERT_TRUE(count.load() == 0); + EXPECT_TRUE(count.load() == 0); int sleep1 = 2000; dispatcher->SyncDispatch(std::make_shared([&count, sleep = sleep1]() { auto time = std::chrono::milliseconds(sleep); std::this_thread::sleep_for(time); int index = count.fetch_add(1); - ASSERT_TRUE(index == 0); + EXPECT_TRUE(index == 0); GTEST_LOG_(INFO) << "SerialTaskDispatcher_SyncDispatchTest_001 task" + std::to_string(index) + " end, elapsed " + std::to_string(sleep); })); - ASSERT_TRUE(count.load() == 1); + EXPECT_TRUE(count.load() == 1); int sleep2 = 100; dispatcher->SyncDispatch(std::make_shared([&count, sleep = sleep2]() { auto time = std::chrono::milliseconds(sleep); std::this_thread::sleep_for(time); int index = count.fetch_add(1); - ASSERT_TRUE(index == 1); + EXPECT_TRUE(index == 1); GTEST_LOG_(INFO) << "SerialTaskDispatcher_SyncDispatchTest_001 task" + std::to_string(index) + " end, elapsed " + std::to_string(sleep); })); - ASSERT_TRUE(count.load() == 2); + EXPECT_TRUE(count.load() == 2); int sleep3 = 1000; dispatcher->SyncDispatch(std::make_shared([&count, sleep = sleep3]() { auto time = std::chrono::milliseconds(sleep); std::this_thread::sleep_for(time); int index = count.fetch_add(1); - ASSERT_TRUE(index == 2); + EXPECT_TRUE(index == 2); GTEST_LOG_(INFO) << "SerialTaskDispatcher_SyncDispatchTest_001 task" + std::to_string(index) + " end, elapsed " + std::to_string(sleep); })); - ASSERT_TRUE(count.load() == 3); + EXPECT_TRUE(count.load() == 3); long wait = 1000; GTEST_LOG_(INFO) << ("wait for " + std::to_string(wait)); @@ -353,7 +353,7 @@ HWTEST(SerialTaskDispatcherTest, SerialTaskDispatcher_SyncDispatchTest_002, Test std::shared_ptr dispatcher = std::make_shared("", priority, executor); ErrCode errCode = dispatcher->SyncDispatch(nullptr); - ASSERT_TRUE(errCode == ERR_APPEXECFWK_CHECK_FAILED); + EXPECT_TRUE(errCode == ERR_APPEXECFWK_CHECK_FAILED); GTEST_LOG_(INFO) << name + " end"; } @@ -376,39 +376,39 @@ HWTEST(SerialTaskDispatcherTest, SerialTaskDispatcher_AsyncDispatchTest_001, Tes std::shared_ptr dispatcher = std::make_shared("", priority, executor); std::atomic count(0); - ASSERT_TRUE(count.load() == 0); + EXPECT_TRUE(count.load() == 0); int sleep1 = 2000; dispatcher->AsyncDispatch(std::make_shared([&count, sleep = sleep1]() { auto time = std::chrono::milliseconds(sleep); std::this_thread::sleep_for(time); int index = count.fetch_add(1); - ASSERT_TRUE(index == 0); + EXPECT_TRUE(index == 0); GTEST_LOG_(INFO) << "SerialTaskDispatcher_AsyncDispatchTest_001 task" + std::to_string(index) + " end, elapsed " + std::to_string(sleep); })); - ASSERT_TRUE(count.load() == 0); + EXPECT_TRUE(count.load() == 0); int sleep2 = 1000; dispatcher->AsyncDispatch(std::make_shared([&count, sleep = sleep2]() { auto time = std::chrono::milliseconds(sleep); std::this_thread::sleep_for(time); int index = count.fetch_add(1); - ASSERT_TRUE(index == 1); + EXPECT_TRUE(index == 1); GTEST_LOG_(INFO) << "SerialTaskDispatcher_AsyncDispatchTest_001 task" + std::to_string(index) + " end, elapsed " + std::to_string(sleep); })); - ASSERT_TRUE(count.load() == 0); + EXPECT_TRUE(count.load() == 0); int sleep3 = 1000; dispatcher->AsyncDispatch(std::make_shared([&count, sleep = sleep3]() { auto time = std::chrono::milliseconds(sleep); std::this_thread::sleep_for(time); int index = count.fetch_add(1); - ASSERT_TRUE(index == 2); + EXPECT_TRUE(index == 2); GTEST_LOG_(INFO) << "SerialTaskDispatcher_AsyncDispatchTest_001 task" + std::to_string(index) + " end, elapsed " + std::to_string(sleep); })); - ASSERT_TRUE(count.load() == 0); + EXPECT_TRUE(count.load() == 0); { long wait = 100; @@ -420,28 +420,28 @@ HWTEST(SerialTaskDispatcherTest, SerialTaskDispatcher_AsyncDispatchTest_001, Tes GTEST_LOG_(INFO) << ("wait for task, wait= " + std::to_string(wait) + " ms"); auto time = std::chrono::milliseconds(wait); std::this_thread::sleep_for(time); - ASSERT_TRUE(count.load() == 0); + EXPECT_TRUE(count.load() == 0); } { long wait = 1000; GTEST_LOG_(INFO) << ("wait for task, wait= " + std::to_string(wait) + " ms"); auto time = std::chrono::milliseconds(wait); std::this_thread::sleep_for(time); - ASSERT_TRUE(count.load() == 1); + EXPECT_TRUE(count.load() == 1); } { long wait = 1000; GTEST_LOG_(INFO) << ("wait for task, wait= " + std::to_string(wait) + " ms"); auto time = std::chrono::milliseconds(wait); std::this_thread::sleep_for(time); - ASSERT_TRUE(count.load() == 2); + EXPECT_TRUE(count.load() == 2); } { long wait = 1000; GTEST_LOG_(INFO) << ("wait for task, wait= " + std::to_string(wait) + " ms"); auto time = std::chrono::milliseconds(wait); std::this_thread::sleep_for(time); - ASSERT_TRUE(count.load() == 3); + EXPECT_TRUE(count.load() == 3); } GTEST_LOG_(INFO) << name + " end"; @@ -456,7 +456,7 @@ HWTEST(SerialTaskDispatcherTest, SerialTaskDispatcher_AsyncDispatchTest_002, Tes std::shared_ptr dispatcher = std::make_shared("", priority, executor); std::shared_ptr revocable = dispatcher->AsyncDispatch(nullptr); - ASSERT_TRUE(revocable == nullptr); + EXPECT_TRUE(revocable == nullptr); GTEST_LOG_(INFO) << name + " end"; } @@ -482,32 +482,32 @@ HWTEST(SerialTaskDispatcherTest, SerialTaskDispatcher_DelayDispatchTest_001, Tes int sleep1 = 2000; dispatcher->DelayDispatch(std::make_shared([&count, sleep = sleep1]() { int index = count.fetch_add(1); - ASSERT_TRUE(index == 2); + EXPECT_TRUE(index == 2); GTEST_LOG_(INFO) << "SerialTaskDispatcher_DelayDispatchTest_001 task" + std::to_string(index) + " end, elapsed " + std::to_string(sleep); }), sleep1); - ASSERT_TRUE(count.load() == 0); + EXPECT_TRUE(count.load() == 0); int sleep2 = 1000; dispatcher->DelayDispatch(std::make_shared([&count, sleep = sleep2]() { int index = count.fetch_add(1); - ASSERT_TRUE(index == 0 || index == 1); + EXPECT_TRUE(index == 0 || index == 1); GTEST_LOG_(INFO) << "SerialTaskDispatcher_DelayDispatchTest_001 task" + std::to_string(index) + " end, elapsed " + std::to_string(sleep); }), sleep2); - ASSERT_TRUE(count.load() == 0); + EXPECT_TRUE(count.load() == 0); int sleep3 = 1000; dispatcher->DelayDispatch(std::make_shared([&count, sleep = sleep3]() { int index = count.fetch_add(1); - ASSERT_TRUE(index == 0 || index == 1); + EXPECT_TRUE(index == 0 || index == 1); GTEST_LOG_(INFO) << "SerialTaskDispatcher_DelayDispatchTest_001 task" + std::to_string(index) + " end, elapsed " + std::to_string(sleep); }), sleep3); - ASSERT_TRUE(count.load() == 0); + EXPECT_TRUE(count.load() == 0); { long wait = 100; @@ -519,7 +519,7 @@ HWTEST(SerialTaskDispatcherTest, SerialTaskDispatcher_DelayDispatchTest_001, Tes GTEST_LOG_(INFO) << ("wait for task, wait= " + std::to_string(wait) + " ms"); auto time = std::chrono::milliseconds(wait); std::this_thread::sleep_for(time); - ASSERT_TRUE(count.load() == 2); + EXPECT_TRUE(count.load() == 2); } { long wait = 500; @@ -527,14 +527,14 @@ HWTEST(SerialTaskDispatcherTest, SerialTaskDispatcher_DelayDispatchTest_001, Tes auto time = std::chrono::milliseconds(wait); std::this_thread::sleep_for(time); GTEST_LOG_(INFO) << ("wait for task, load= " + std::to_string(count.load())); - ASSERT_TRUE(count.load() == 2); + EXPECT_TRUE(count.load() == 2); } { long wait = 1000; GTEST_LOG_(INFO) << ("wait for task, wait= " + std::to_string(wait) + " ms"); auto time = std::chrono::milliseconds(wait); std::this_thread::sleep_for(time); - ASSERT_TRUE(count.load() == 3); + EXPECT_TRUE(count.load() == 3); } GTEST_LOG_(INFO) << name + " end"; @@ -568,7 +568,7 @@ HWTEST(SerialTaskDispatcherTest, SerialTaskDispatcher_DelayDispatchTest_003, Tes int sleep1 = -2000; dispatcher->DelayDispatch(std::make_shared([&count, sleep = sleep1]() { int index = count.fetch_add(1); - ASSERT_TRUE(index == 1 || index == 0); + EXPECT_TRUE(index == 1 || index == 0); GTEST_LOG_(INFO) << "SerialTaskDispatcher_DelayDispatchTest_003 task" + std::to_string(index) + " end, elapsed " + std::to_string(sleep); }), @@ -577,7 +577,7 @@ HWTEST(SerialTaskDispatcherTest, SerialTaskDispatcher_DelayDispatchTest_003, Tes int sleep2 = -1000; dispatcher->DelayDispatch(std::make_shared([&count, sleep = sleep2]() { int index = count.fetch_add(1); - ASSERT_TRUE(index == 0 || index == 1); + EXPECT_TRUE(index == 0 || index == 1); GTEST_LOG_(INFO) << "SerialTaskDispatcher_DelayDispatchTest_003 task" + std::to_string(index) + " end, elapsed " + std::to_string(sleep); }), @@ -588,7 +588,7 @@ HWTEST(SerialTaskDispatcherTest, SerialTaskDispatcher_DelayDispatchTest_003, Tes GTEST_LOG_(INFO) << ("wait for task, wait= " + std::to_string(wait) + " ms"); auto time = std::chrono::milliseconds(wait); std::this_thread::sleep_for(time); - ASSERT_TRUE(count.load() == 2); + EXPECT_TRUE(count.load() == 2); } GTEST_LOG_(INFO) << name + " end"; diff --git a/interfaces/innerkits/task_dispatcher/test/unittest/spec_dispatcher_config_test/BUILD.gn b/interfaces/innerkits/task_dispatcher/test/unittest/spec_dispatcher_config_test/BUILD.gn index 83f95e8170..530fd61127 100644 --- a/interfaces/innerkits/task_dispatcher/test/unittest/spec_dispatcher_config_test/BUILD.gn +++ b/interfaces/innerkits/task_dispatcher/test/unittest/spec_dispatcher_config_test/BUILD.gn @@ -36,7 +36,7 @@ ohos_unittest("SpecDispatcherConfigTest") { "${dispatcher_path}/src/threading/worker_pool.cpp", ] - sources += [ "spec_dispatcher_config_test .cpp" ] + sources += [ "spec_dispatcher_config_test.cpp" ] configs = [ "${dispatcher_path}/test:dispatcher_test_config" ] diff --git a/interfaces/innerkits/task_dispatcher/test/unittest/spec_dispatcher_config_test/spec_dispatcher_config_test .cpp b/interfaces/innerkits/task_dispatcher/test/unittest/spec_dispatcher_config_test/spec_dispatcher_config_test.cpp similarity index 93% rename from interfaces/innerkits/task_dispatcher/test/unittest/spec_dispatcher_config_test/spec_dispatcher_config_test .cpp rename to interfaces/innerkits/task_dispatcher/test/unittest/spec_dispatcher_config_test/spec_dispatcher_config_test.cpp index 8d5e139694..0292695e79 100644 --- a/interfaces/innerkits/task_dispatcher/test/unittest/spec_dispatcher_config_test/spec_dispatcher_config_test .cpp +++ b/interfaces/innerkits/task_dispatcher/test/unittest/spec_dispatcher_config_test/spec_dispatcher_config_test.cpp @@ -65,8 +65,8 @@ HWTEST(SpecDispatcherConfigTest, SpecDispatcherConfig_0100, Function | MediumTes std::string dispatcherName = "SpecDispatcherConfig_0100"; TaskPriority taskPriority = TaskPriority::DEFAULT; std::shared_ptr config = std::make_shared(dispatcherName, taskPriority); - ASSERT_EQ(config->GetName(), dispatcherName); - ASSERT_EQ(config->GetPriority(), TaskPriority::DEFAULT); + EXPECT_EQ(config->GetName(), dispatcherName); + EXPECT_EQ(config->GetPriority(), TaskPriority::DEFAULT); GTEST_LOG_(INFO) << "SpecDispatcherConfig_0100 end"; } /** @@ -81,7 +81,7 @@ HWTEST(SpecDispatcherConfigTest, GetPriority_0100, Function | MediumTest | Level std::string dispatcherName = "GetPriority_0100"; TaskPriority taskPriority = TaskPriority::DEFAULT; std::shared_ptr config = std::make_shared(dispatcherName, taskPriority); - ASSERT_EQ(config->GetPriority(), TaskPriority::DEFAULT); + EXPECT_EQ(config->GetPriority(), TaskPriority::DEFAULT); GTEST_LOG_(INFO) << "GetPriority_0100 end"; } /** @@ -96,6 +96,6 @@ HWTEST(SpecDispatcherConfigTest, GetName_0100, Function | MediumTest | Level1) std::string dispatcherName = "GetName_0100"; TaskPriority taskPriority = TaskPriority::DEFAULT; std::shared_ptr config = std::make_shared(dispatcherName, taskPriority); - ASSERT_EQ(config->GetName(), dispatcherName); + EXPECT_EQ(config->GetName(), dispatcherName); GTEST_LOG_(INFO) << "GetName_0100 end"; } diff --git a/interfaces/innerkits/task_dispatcher/test/unittest/spec_task_dispatcher_test/spec_task_dispatcher_test.cpp b/interfaces/innerkits/task_dispatcher/test/unittest/spec_task_dispatcher_test/spec_task_dispatcher_test.cpp index d01bda6fb0..8c4ad4db71 100644 --- a/interfaces/innerkits/task_dispatcher/test/unittest/spec_task_dispatcher_test/spec_task_dispatcher_test.cpp +++ b/interfaces/innerkits/task_dispatcher/test/unittest/spec_task_dispatcher_test/spec_task_dispatcher_test.cpp @@ -94,7 +94,7 @@ HWTEST(SpecTaskDispatcherTest, SpecTaskDispatcher_0100, Function | MediumTest | GTEST_LOG_(INFO) << "SpecTaskDispatcher_0100 start"; std::shared_ptr ptr = CreateSpecTaskDispatcher(); // same to func CreateSpecTaskDispatcher TaskPriority - ASSERT_EQ(ptr->GetPriority(), TaskPriority::HIGH); + EXPECT_EQ(ptr->GetPriority(), TaskPriority::HIGH); GTEST_LOG_(INFO) << "SpecTaskDispatcher_0100 end"; } @@ -114,36 +114,36 @@ HWTEST(SpecTaskDispatcherTest, SyncDispatch_0100, Function | MediumTest | Level1 // task runs synchronized // use elapsed time to identify a task. std::atomic count(0); - ASSERT_TRUE(count.load() == 0); + EXPECT_TRUE(count.load() == 0); int sleep1 = 2000; ptr->SyncDispatch(std::make_shared([&count, sleep = sleep1]() { auto time = std::chrono::milliseconds(sleep); std::this_thread::sleep_for(time); int index = count.fetch_add(1); - ASSERT_TRUE(index == 0); + EXPECT_TRUE(index == 0); APP_LOGD("task %{public}d end, elapsed %{public}d ms", index, sleep); })); - ASSERT_TRUE(count.load() == 1); + EXPECT_TRUE(count.load() == 1); int sleep2 = 100; ptr->SyncDispatch(std::make_shared([&count, sleep = sleep2]() { auto time = std::chrono::milliseconds(sleep); std::this_thread::sleep_for(time); int index = count.fetch_add(1); - ASSERT_TRUE(index == 1); + EXPECT_TRUE(index == 1); APP_LOGD("task %{public}d end, elapsed %{public}d ms", index, sleep); })); - ASSERT_TRUE(count.load() == 2); + EXPECT_TRUE(count.load() == 2); int sleep3 = 1000; ptr->SyncDispatch(std::make_shared([&count, sleep = sleep3]() { auto time = std::chrono::milliseconds(sleep); std::this_thread::sleep_for(time); int index = count.fetch_add(1); - ASSERT_TRUE(index == 2); + EXPECT_TRUE(index == 2); APP_LOGD("task %{public}d end, elapsed %{public}d ms", index, sleep); })); - ASSERT_TRUE(count.load() == 3); + EXPECT_TRUE(count.load() == 3); long wait = 1000; GTEST_LOG_(INFO) << ("wait for " + std::to_string(wait)); @@ -182,36 +182,36 @@ HWTEST(SpecTaskDispatcherTest, AsyncDispatch_0100, Function | MediumTest | Level // task runs synchronized // use elapsed time to identify a task. std::atomic count(0); - ASSERT_TRUE(count.load() == 0); + EXPECT_TRUE(count.load() == 0); int sleep1 = 2000; ptr->AsyncDispatch(std::make_shared([&count, sleep = sleep1]() { auto time = std::chrono::milliseconds(sleep); std::this_thread::sleep_for(time); int index = count.fetch_add(1); - ASSERT_TRUE(index == 0); + EXPECT_TRUE(index == 0); APP_LOGD("task %{public}d end, elapsed %{public}d ms", index, sleep); })); - ASSERT_TRUE(count.load() == 0); + EXPECT_TRUE(count.load() == 0); int sleep2 = 1000; ptr->AsyncDispatch(std::make_shared([&count, sleep = sleep2]() { auto time = std::chrono::milliseconds(sleep); std::this_thread::sleep_for(time); int index = count.fetch_add(1); - ASSERT_TRUE(index == 1); + EXPECT_TRUE(index == 1); APP_LOGD("task %{public}d end, elapsed %{public}d ms", index, sleep); })); - ASSERT_TRUE(count.load() == 0); + EXPECT_TRUE(count.load() == 0); int sleep3 = 1000; ptr->AsyncDispatch(std::make_shared([&count, sleep = sleep3]() { auto time = std::chrono::milliseconds(sleep); std::this_thread::sleep_for(time); int index = count.fetch_add(1); - ASSERT_TRUE(index == 2); + EXPECT_TRUE(index == 2); APP_LOGD("task %{public}d end, elapsed %{public}d ms", index, sleep); })); - ASSERT_TRUE(count.load() == 0); + EXPECT_TRUE(count.load() == 0); { long wait = 100; @@ -223,28 +223,28 @@ HWTEST(SpecTaskDispatcherTest, AsyncDispatch_0100, Function | MediumTest | Level GTEST_LOG_(INFO) << ("wait for task, wait= " + std::to_string(wait) + " ms"); auto time = std::chrono::milliseconds(wait); std::this_thread::sleep_for(time); - ASSERT_TRUE(count.load() == 0); + EXPECT_TRUE(count.load() == 0); } { long wait = 1000; GTEST_LOG_(INFO) << ("wait for task, wait= " + std::to_string(wait) + " ms"); auto time = std::chrono::milliseconds(wait); std::this_thread::sleep_for(time); - ASSERT_TRUE(count.load() == 1); + EXPECT_TRUE(count.load() == 1); } { long wait = 1000; GTEST_LOG_(INFO) << ("wait for task, wait= " + std::to_string(wait) + " ms"); auto time = std::chrono::milliseconds(wait); std::this_thread::sleep_for(time); - ASSERT_TRUE(count.load() == 2); + EXPECT_TRUE(count.load() == 2); } { long wait = 1000; GTEST_LOG_(INFO) << ("wait for task, wait= " + std::to_string(wait) + " ms"); auto time = std::chrono::milliseconds(wait); std::this_thread::sleep_for(time); - ASSERT_TRUE(count.load() == 3); + EXPECT_TRUE(count.load() == 3); } GTEST_LOG_(INFO) << "AsyncDispatch_0100 end"; @@ -283,31 +283,31 @@ HWTEST(SpecTaskDispatcherTest, DelayDispatch_0100, Function | MediumTest | Level ptr->DelayDispatch(std::make_shared([&count, sleep = sleep1]() { // execute second int index = count.fetch_add(1); - ASSERT_TRUE(index == 2); + EXPECT_TRUE(index == 2); APP_LOGD("task %{public}d end, elapsed %{public}d ms", index, sleep); }), sleep1); - ASSERT_TRUE(count.load() == 0); + EXPECT_TRUE(count.load() == 0); int sleep2 = 1000; ptr->DelayDispatch(std::make_shared([&count, sleep = sleep2]() { // execute first int index = count.fetch_add(1); - ASSERT_TRUE(index == 0 || index == 1); + EXPECT_TRUE(index == 0 || index == 1); APP_LOGD("task %{public}d end, elapsed %{public}d ms", index, sleep); }), sleep2); - ASSERT_TRUE(count.load() == 0); + EXPECT_TRUE(count.load() == 0); int sleep3 = 1000; ptr->DelayDispatch(std::make_shared([&count, sleep = sleep3]() { // execute first int index = count.fetch_add(1); - ASSERT_TRUE(index == 0 || index == 1); + EXPECT_TRUE(index == 0 || index == 1); APP_LOGD("task %{public}d end, elapsed %{public}d ms", index, sleep); }), sleep3); - ASSERT_TRUE(count.load() == 0); + EXPECT_TRUE(count.load() == 0); { long wait = 100; @@ -319,21 +319,21 @@ HWTEST(SpecTaskDispatcherTest, DelayDispatch_0100, Function | MediumTest | Level GTEST_LOG_(INFO) << ("wait for task, wait= " + std::to_string(wait) + " ms"); auto time = std::chrono::milliseconds(wait); std::this_thread::sleep_for(time); - ASSERT_TRUE(count.load() == 2); + EXPECT_TRUE(count.load() == 2); } { long wait = 500; GTEST_LOG_(INFO) << ("wait for task, wait= " + std::to_string(wait) + " ms"); auto time = std::chrono::milliseconds(wait); std::this_thread::sleep_for(time); - ASSERT_TRUE(count.load() == 2); + EXPECT_TRUE(count.load() == 2); } { long wait = 1000; GTEST_LOG_(INFO) << ("wait for task, wait= " + std::to_string(wait) + " ms"); auto time = std::chrono::milliseconds(wait); std::this_thread::sleep_for(time); - ASSERT_TRUE(count.load() == 3); + EXPECT_TRUE(count.load() == 3); } GTEST_LOG_(INFO) << "DelayDispatch_0100 end"; } diff --git a/interfaces/innerkits/task_dispatcher/test/unittest/task_dispatcher_context_test/task_dispatcher_context_test.cpp b/interfaces/innerkits/task_dispatcher/test/unittest/task_dispatcher_context_test/task_dispatcher_context_test.cpp index 8b87a0fa41..bad87ebc86 100644 --- a/interfaces/innerkits/task_dispatcher/test/unittest/task_dispatcher_context_test/task_dispatcher_context_test.cpp +++ b/interfaces/innerkits/task_dispatcher/test/unittest/task_dispatcher_context_test/task_dispatcher_context_test.cpp @@ -57,7 +57,7 @@ HWTEST(TaskDispatcherContextTest, TaskDispatcherContext_0100, Function | MediumT GTEST_LOG_(INFO) << "TaskDispatcherContext_0100 start"; std::shared_ptr taskDispatcherContext = std::make_shared(); std::shared_ptr config = taskDispatcherContext->GetWorkerPoolConfig(); - ASSERT_EQ(config.get()->GetMaxThreadCount(), 32); + EXPECT_EQ(config.get()->GetMaxThreadCount(), 32); GTEST_LOG_(INFO) << "TaskDispatcherContext_0100 end"; } @@ -76,7 +76,7 @@ HWTEST(TaskDispatcherContextTest, TaskDispatcherContext_0200, Function | MediumT std::make_shared(testTaskExecutor); std::map workerThreadsInfo = taskDispatcherContext->GetWorkerThreadsInfo(); bool flag = (workerThreadsInfo.size() == 0); - ASSERT_TRUE(flag); + EXPECT_TRUE(flag); GTEST_LOG_(INFO) << "TaskDispatcherContext_0200 end"; } @@ -91,7 +91,7 @@ HWTEST(TaskDispatcherContextTest, GetWorkerPoolConfig_0100, Function | MediumTes GTEST_LOG_(INFO) << "GetWorkerPoolConfig_0100 start"; std::shared_ptr taskDispatcherContext = std::make_shared(); std::shared_ptr config = taskDispatcherContext->GetWorkerPoolConfig(); - ASSERT_EQ(config.get()->GetMaxThreadCount(), 32); + EXPECT_EQ(config.get()->GetMaxThreadCount(), 32); GTEST_LOG_(INFO) << "GetWorkerPoolConfig_0100 end"; } /** @@ -107,7 +107,7 @@ HWTEST(TaskDispatcherContextTest, GetWorkerThreadsInfo_0100, Function | MediumTe std::shared_ptr taskDispatcherContext = std::make_shared(nullptr); std::map workerThreadsInfo = taskDispatcherContext->GetWorkerThreadsInfo(); bool flag = (workerThreadsInfo.size() == 0); - ASSERT_TRUE(flag); + EXPECT_TRUE(flag); GTEST_LOG_(INFO) << "GetWorkerThreadsInfo_0100 end"; } /** @@ -125,7 +125,7 @@ HWTEST(TaskDispatcherContextTest, GetWorkerThreadsInfo_0200, Function | MediumTe std::make_shared(testTaskExecutor); std::map workerThreadsInfo = taskDispatcherContext->GetWorkerThreadsInfo(); bool flag = (workerThreadsInfo.size() == 0); - ASSERT_TRUE(flag); + EXPECT_TRUE(flag); GTEST_LOG_(INFO) << "TaskDispatcherContext_0200 end"; } /** @@ -143,7 +143,7 @@ HWTEST(TaskDispatcherContextTest, CreateSerialDispatcher_0100, Function | Medium TaskPriority taskPriority = TaskPriority::DEFAULT; std::shared_ptr ptrSerialTaskDispatcher = taskDispatcherContext->CreateSerialDispatcher(dispatcherName, taskPriority); - ASSERT_EQ(ptrSerialTaskDispatcher->GetDispatcherName(), dispatcherName); + EXPECT_EQ(ptrSerialTaskDispatcher->GetDispatcherName(), dispatcherName); GTEST_LOG_(INFO) << "CreateSerialDispatcher_0100 end"; } /** @@ -168,10 +168,10 @@ HWTEST(TaskDispatcherContextTest, GetSerialDispatchers_0100, Function | MediumTe std::map, std::string> serialDispatchers = taskDispatcherContext->GetSerialDispatchers(); bool flag = (serialDispatchers.size() == 2); - ASSERT_TRUE(flag); + EXPECT_TRUE(flag); std::map, std::string>::iterator iter; for (iter = serialDispatchers.begin(); iter != serialDispatchers.end(); iter++) { - ASSERT_EQ(iter->second, dispatcherName); + EXPECT_EQ(iter->second, dispatcherName); } GTEST_LOG_(INFO) << "GetSerialDispatchers_0100 end"; } @@ -189,7 +189,7 @@ HWTEST(TaskDispatcherContextTest, CreateParallelDispatcher_0100, Function | Medi TaskPriority taskPriority = TaskPriority::HIGH; std::shared_ptr ptrSerialTaskDispatcher = taskDispatcherContext->CreateParallelDispatcher(dispatcherName, taskPriority); - ASSERT_EQ(ptrSerialTaskDispatcher->GetPriority(), taskPriority); + EXPECT_EQ(ptrSerialTaskDispatcher->GetPriority(), taskPriority); GTEST_LOG_(INFO) << "CreateParallelDispatcher_0100 end"; } @@ -252,7 +252,7 @@ HWTEST(TaskDispatcherContextTest, GetWaitingTasksCount_0100, Function | MediumTe const std::shared_ptr testTaskExecutor = nullptr; std::shared_ptr taskDispatcherContext = std::make_shared(testTaskExecutor); - ASSERT_EQ(taskDispatcherContext->GetWaitingTasksCount(), 0); + EXPECT_EQ(taskDispatcherContext->GetWaitingTasksCount(), 0); GTEST_LOG_(INFO) << "GetWaitingTasksCount_0100 end"; } @@ -269,7 +269,7 @@ HWTEST(TaskDispatcherContextTest, GetWaitingTasksCount_0200, Function | MediumTe const std::shared_ptr testTaskExecutor = std::make_shared(config); std::shared_ptr taskDispatcherContext = std::make_shared(testTaskExecutor); - ASSERT_EQ(taskDispatcherContext->GetWaitingTasksCount(), 0); + EXPECT_EQ(taskDispatcherContext->GetWaitingTasksCount(), 0); GTEST_LOG_(INFO) << "GetWaitingTasksCount_0200 end"; } /** @@ -285,6 +285,6 @@ HWTEST(TaskDispatcherContextTest, GetTaskCounter_0100, Function | MediumTest | L const std::shared_ptr testTaskExecutor = std::make_shared(config); std::shared_ptr taskDispatcherContext = std::make_shared(testTaskExecutor); - ASSERT_EQ(taskDispatcherContext->GetTaskCounter(), 0); + EXPECT_EQ(taskDispatcherContext->GetTaskCounter(), 0); GTEST_LOG_(INFO) << "GetTaskCounter_0100 end"; } \ No newline at end of file diff --git a/interfaces/innerkits/test/mock/include/test.cpp b/interfaces/innerkits/test/mock/include/test.cpp deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/interfaces/innerkits/test/moduletest/task_dispatcher/global_task_dispatcher_module_test/global_task_dispatcher_module_test.cpp b/interfaces/innerkits/test/moduletest/task_dispatcher/global_task_dispatcher_module_test/global_task_dispatcher_module_test.cpp index 110f9356de..6abe4204c1 100644 --- a/interfaces/innerkits/test/moduletest/task_dispatcher/global_task_dispatcher_module_test/global_task_dispatcher_module_test.cpp +++ b/interfaces/innerkits/test/moduletest/task_dispatcher/global_task_dispatcher_module_test/global_task_dispatcher_module_test.cpp @@ -68,7 +68,6 @@ std::shared_ptr GlobalTaskDispatcherModuleTest::GetMtGlobalTaskD HWTEST_F(GlobalTaskDispatcherModuleTest, GetMtGlobalTaskDispatcherTest_001, TestSize.Level1) { auto name = std::string("GetMtGlobalTaskDispatcherTest_001"); - // TaskDispatcherContext context; GTEST_LOG_(INFO) << name + " start"; TaskPriority defaultPriority = TaskPriority::DEFAULT; std::shared_ptr defaultPtr1 = GetMtGlobalTaskDispatcher(defaultPriority); diff --git a/interfaces/innerkits/test/moduletest/task_dispatcher/parallel_task_dispatcher_module_test/parallel_task_dispatcher_module_test.cpp b/interfaces/innerkits/test/moduletest/task_dispatcher/parallel_task_dispatcher_module_test/parallel_task_dispatcher_module_test.cpp index 159c241aec..2724e7393b 100644 --- a/interfaces/innerkits/test/moduletest/task_dispatcher/parallel_task_dispatcher_module_test/parallel_task_dispatcher_module_test.cpp +++ b/interfaces/innerkits/test/moduletest/task_dispatcher/parallel_task_dispatcher_module_test/parallel_task_dispatcher_module_test.cpp @@ -300,15 +300,11 @@ HWTEST_F(ParallelTaskDispatcherModuleTest, ParallelTaskDispatcher_DelayDispatchT GTEST_LOG_(INFO) << name << " Runnable2"; }), sleep2); - // printf("111111111111111111111111111111111111111111111111111111111111111111"); EXPECT_TRUE(count.load() < 2); long wait = 1000; auto time = std::chrono::milliseconds(wait); std::this_thread::sleep_for(time); - // printf("222222222222222222222222222222222222222222222222222222222222222222"); EXPECT_TRUE(count.load() == 2); - // printf("33333333333333333333333333333333333333333333333333333333333333333"); - // printf("context use count:%d", context.use_count()); GTEST_LOG_(INFO) << name << " end"; } diff --git a/interfaces/innerkits/test/moduletest/task_dispatcher/serial_task_dispatcher_module_test/serial_task_dispatcher_module_test.cpp b/interfaces/innerkits/test/moduletest/task_dispatcher/serial_task_dispatcher_module_test/serial_task_dispatcher_module_test.cpp index efebb9c2a9..b267e283e1 100644 --- a/interfaces/innerkits/test/moduletest/task_dispatcher/serial_task_dispatcher_module_test/serial_task_dispatcher_module_test.cpp +++ b/interfaces/innerkits/test/moduletest/task_dispatcher/serial_task_dispatcher_module_test/serial_task_dispatcher_module_test.cpp @@ -187,16 +187,14 @@ HWTEST_F(SerialTaskDispatcherModuleTest, SerialTaskDispatcher_AsyncDispatchTest_ const int total = 300; std::atomic count(0); long wait = 100; - int period = 10; for (int i = 0; i < total; i++) { - ptr->AsyncDispatch(std::make_shared([&count, &period, &name]() { - int sleep = std::rand() % period; - auto time = std::chrono::milliseconds(sleep); + ptr->AsyncDispatch(std::make_shared([&count, &name]() { + auto time = std::chrono::milliseconds(1); std::this_thread::sleep_for(time); int index = count.fetch_add(1); GTEST_LOG_(INFO) << "SerialTaskDispatcher_AsyncDispatchTest_002 task" + std::to_string(index) + "end"; })); - wait += period; + wait += 1; } EXPECT_TRUE(count.load() < total); auto time = std::chrono::milliseconds(wait + 1000); diff --git a/kits/BUILD.gn b/kits/BUILD.gn index 3818831753..5cbdd086c5 100755 --- a/kits/BUILD.gn +++ b/kits/BUILD.gn @@ -105,7 +105,6 @@ ohos_shared_library("appkit_native") { sources = [ "$SUBSYSTEM_DIR/kits/appkit/native/app/src/ability_manager.cpp", "$SUBSYSTEM_DIR/kits/appkit/native/app/src/ability_record_mgr.cpp", - "$SUBSYSTEM_DIR/kits/appkit/native/app/src/ability_start_setting.cpp", "$SUBSYSTEM_DIR/kits/appkit/native/app/src/app_loader.cpp", "$SUBSYSTEM_DIR/kits/appkit/native/app/src/application_context.cpp", "$SUBSYSTEM_DIR/kits/appkit/native/app/src/application_env.cpp", @@ -138,7 +137,6 @@ ohos_shared_library("appkit_native") { public_deps = [ "//base/global/resmgr_standard/frameworks/resmgr:global_resmgr" ] - external_deps = [ "hiviewdfx_hilog_native:libhilog", "ipc:ipc_core", diff --git a/kits/appkit/napi/bundlemgr/BUILD.gn b/kits/appkit/napi/bundlemgr/BUILD.gn index e78938a77d..20f2273cc1 100644 --- a/kits/appkit/napi/bundlemgr/BUILD.gn +++ b/kits/appkit/napi/bundlemgr/BUILD.gn @@ -17,6 +17,7 @@ ohos_shared_library("bundle") { include_dirs = [ "//foundation/ace/napi/interfaces/kits", "//third_party/node/src", + "//third_party/libuv/include", "//foundation/aafwk/standard/services/common/include", "//utils/system/safwk/native/include", "./", @@ -26,6 +27,7 @@ ohos_shared_library("bundle") { "bundle_mgr.cpp", "installer_callback.cpp", "native_module.cpp", + "permission_callback.cpp", ] deps = [ diff --git a/kits/appkit/napi/bundlemgr/bundle_mgr.cpp b/kits/appkit/napi/bundlemgr/bundle_mgr.cpp index 2e5350e9ef..97c625351f 100644 --- a/kits/appkit/napi/bundlemgr/bundle_mgr.cpp +++ b/kits/appkit/napi/bundlemgr/bundle_mgr.cpp @@ -21,6 +21,9 @@ #include "if_system_ability_manager.h" #include "iservice_registry.h" #include "installer_callback.h" +#include "permission_callback.h" +#include "ipc_skeleton.h" +#include "bundle_constants.h" using namespace OHOS; using namespace OHOS::AAFwk; @@ -36,12 +39,6 @@ constexpr size_t ARGS_SIZE_FOUR = 4; constexpr int32_t DEFAULT_INT32 = 0; constexpr int32_t PARAM0 = 0; constexpr int32_t PARAM1 = 1; -constexpr int32_t PARAM2 = 2; -constexpr int32_t NAPI_RETURN_FAILED = -1; -constexpr int32_t NAPI_RETURN_ZERO = 0; -constexpr int32_t NAPI_RETURN_ONE = 1; -constexpr int32_t NAPI_RETURN_TWO = 2; -constexpr int32_t NAPI_RETURN_THREE = 3; constexpr int32_t CODE_SUCCESS = 0; constexpr int32_t CODE_FAILED = -1; enum class InstallErrorCode { @@ -62,6 +59,24 @@ enum class InstallErrorCode { STATUS_BMS_SERVICE_ERROR = 0x41 }; +const std::string PERMISSION_CHANGE = "permissionChange"; +const std::string ANY_PERMISSION_CHANGE = "anyPermissionChange"; + +std::mutex permissionsCallbackMutex; +std::mutex anyPermissionsCallbackMutex; + +struct PermissionsKey { + napi_ref callback = 0; + std::vector uids; + bool operator<(const PermissionsKey &other) const + { + return this->callback < other.callback; + } +}; + +std::map> permissionsCallback; +std::map> anyPermissionsCallback; + } // namespace napi_value g_classBundleInstaller; @@ -75,6 +90,15 @@ static OHOS::sptr GetBundleMgr() return OHOS::iface_cast(remoteObject); } +static bool CheckIsSystemApp() +{ + int32_t uid = IPCSkeleton::GetCallingUid(); + if (uid >= OHOS::AppExecFwk::Constants::ROOT_UID && uid <= OHOS::AppExecFwk::Constants::MAX_SYS_UID) { + return true; + } + return false; +} + static void ConvertApplicationInfo(napi_env env, napi_value objAppInfo, const ApplicationInfo &appInfo) { napi_value nName; @@ -119,9 +143,12 @@ static void ConvertApplicationInfo(napi_env env, napi_value objAppInfo, const Ap NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, appInfo.process.c_str(), NAPI_AUTO_LENGTH, &nProcess)); NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAppInfo, "process", nProcess)); - napi_value nEntryDir; - NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, appInfo.entryDir.c_str(), NAPI_AUTO_LENGTH, &nEntryDir)); - NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAppInfo, "entryDir", nEntryDir)); + if (CheckIsSystemApp()) { + napi_value nEntryDir; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, appInfo.entryDir.c_str(), NAPI_AUTO_LENGTH, &nEntryDir)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAppInfo, "entryDir", nEntryDir)); + } napi_value nPermissions; NAPI_CALL_RETURN_VOID(env, napi_create_array(env, &nPermissions)); @@ -187,14 +214,15 @@ static void ConvertCustomizeData(napi_env env, napi_value objCustomizeData, cons HILOG_INFO("ConvertCustomizeData value=%{public}s.", customizeData.value.c_str()); napi_value nExtra; NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, customizeData.extra.c_str(), NAPI_AUTO_LENGTH, &nExtra)); - NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objCustomizeData, "value", nExtra)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objCustomizeData, "extra", nExtra)); HILOG_INFO("ConvertCustomizeData extra=%{public}s.", customizeData.extra.c_str()); } static void ConvertParameters(napi_env env, napi_value objParameters, const Parameters ¶meters) { napi_value nDescription; - NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, parameters.description.c_str(), NAPI_AUTO_LENGTH, &nDescription)); + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, parameters.description.c_str(), NAPI_AUTO_LENGTH, &nDescription)); NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objParameters, "description", nDescription)); HILOG_INFO("ConvertParameters parameters.description=%{public}s.", parameters.description.c_str()); napi_value nName; @@ -210,7 +238,8 @@ static void ConvertParameters(napi_env env, napi_value objParameters, const Para static void ConvertResults(napi_env env, napi_value objResults, const Results &results) { napi_value nDescription; - NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, results.description.c_str(), NAPI_AUTO_LENGTH, &nDescription)); + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, results.description.c_str(), NAPI_AUTO_LENGTH, &nDescription)); NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objResults, "description", nDescription)); HILOG_INFO("ConvertResults results.description=%{public}s.", results.description.c_str()); napi_value nName; @@ -223,7 +252,6 @@ static void ConvertResults(napi_env env, napi_value objResults, const Results &r HILOG_INFO("ConvertResults results.type=%{public}s.", results.type.c_str()); } - static void ConvertMetaData(napi_env env, napi_value objMetaData, const MetaData &metaData) { napi_value nCustomizeDatas; @@ -279,6 +307,16 @@ static void ConvertAbilityInfo(napi_env env, napi_value objAbilityInfo, const Ab env, napi_create_string_utf8(env, abilityInfo.iconPath.c_str(), NAPI_AUTO_LENGTH, &nIconPath)); NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAbilityInfo, "icon", nIconPath)); + napi_value nsrcPath; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, abilityInfo.srcPath.c_str(), NAPI_AUTO_LENGTH, &nsrcPath)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAbilityInfo, "srcPath", nsrcPath)); + + napi_value nLaunguage; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, abilityInfo.srcLanguage.c_str(), NAPI_AUTO_LENGTH, &nLaunguage)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAbilityInfo, "srcLanguage", nLaunguage)); + napi_value nVisible; NAPI_CALL_RETURN_VOID(env, napi_get_boolean(env, abilityInfo.visible, &nVisible)); NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAbilityInfo, "isVisible", nVisible)); @@ -634,10 +672,12 @@ static void ConvertFormInfo(napi_env env, napi_value objformInfo, const FormInfo static void ConvertShortcutIntent(napi_env env, napi_value objShortcutInfo, const ShortcutIntent &shortcutIntent) { napi_value nTargetBundle; - NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, shortcutIntent.targetBundle.c_str(), NAPI_AUTO_LENGTH, &nTargetBundle)); + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, shortcutIntent.targetBundle.c_str(), NAPI_AUTO_LENGTH, &nTargetBundle)); NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objShortcutInfo, "targetBundle", nTargetBundle)); napi_value nTargetClass; - NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, shortcutIntent.targetClass.c_str(), NAPI_AUTO_LENGTH, &nTargetClass)); + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, shortcutIntent.targetClass.c_str(), NAPI_AUTO_LENGTH, &nTargetClass)); NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objShortcutInfo, "targetClass", nTargetClass)); } @@ -659,13 +699,11 @@ static void ConvertShortcutInfos(napi_env env, napi_value objShortcutInfo, const NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objShortcutInfo, "hostAbility", nHostAbility)); napi_value nIcon; - NAPI_CALL_RETURN_VOID( - env, napi_create_string_utf8(env, shortcutInfo.icon.c_str(), NAPI_AUTO_LENGTH, &nIcon)); + NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, shortcutInfo.icon.c_str(), NAPI_AUTO_LENGTH, &nIcon)); NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objShortcutInfo, "icon", nIcon)); napi_value nLabel; - NAPI_CALL_RETURN_VOID( - env, napi_create_string_utf8(env, shortcutInfo.label.c_str(), NAPI_AUTO_LENGTH, &nLabel)); + NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, shortcutInfo.label.c_str(), NAPI_AUTO_LENGTH, &nLabel)); NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objShortcutInfo, "label", nLabel)); napi_value nDisableMessage; @@ -683,7 +721,7 @@ static void ConvertShortcutInfos(napi_env env, napi_value objShortcutInfo, const napi_value nIsEnables; NAPI_CALL_RETURN_VOID(env, napi_get_boolean(env, shortcutInfo.isEnables, &nIsEnables)); - NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objShortcutInfo, "isEnables", nIsEnables)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objShortcutInfo, "isEnabled", nIsEnables)); napi_value nIntents; NAPI_CALL_RETURN_VOID(env, napi_create_array(env, &nIntents)); @@ -693,20 +731,92 @@ static void ConvertShortcutInfos(napi_env env, napi_value objShortcutInfo, const ConvertShortcutIntent(env, nIntent, shortcutInfo.intents[idx]); NAPI_CALL_RETURN_VOID(env, napi_set_element(env, nIntents, idx, nIntent)); } - NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objShortcutInfo, "intents", nIntents)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objShortcutInfo, "wants", nIntents)); +} + +static void ConvertModuleUsageRecords( + napi_env env, napi_value objModuleUsageRecord, const ModuleUsageRecord &moduleUsageRecord) +{ + napi_value nbundleName; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, moduleUsageRecord.bundleName.c_str(), NAPI_AUTO_LENGTH, &nbundleName)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objModuleUsageRecord, "bundleName", nbundleName)); + HILOG_INFO("ConvertModuleUsageRecords bundleName=%{public}s.", moduleUsageRecord.bundleName.c_str()); + + napi_value nappLabelId; + NAPI_CALL_RETURN_VOID(env, napi_create_uint32(env, moduleUsageRecord.appLabelId, &nappLabelId)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objModuleUsageRecord, "appLabelId", nappLabelId)); + HILOG_INFO("ConvertModuleUsageRecords appLabelId=%{public}ud.", moduleUsageRecord.appLabelId); + + napi_value nname; + NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, moduleUsageRecord.name.c_str(), NAPI_AUTO_LENGTH, &nname)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objModuleUsageRecord, "name", nname)); + HILOG_INFO("ConvertModuleUsageRecords name=%{public}s.", moduleUsageRecord.name.c_str()); + + napi_value nlabelId; + NAPI_CALL_RETURN_VOID(env, napi_create_uint32(env, moduleUsageRecord.labelId, &nlabelId)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objModuleUsageRecord, "labelId", nlabelId)); + HILOG_INFO("ConvertModuleUsageRecords labelId=%{public}ud.", moduleUsageRecord.labelId); + + napi_value ndescriptionId; + NAPI_CALL_RETURN_VOID(env, napi_create_uint32(env, moduleUsageRecord.descriptionId, &ndescriptionId)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objModuleUsageRecord, "descriptionId", ndescriptionId)); + HILOG_INFO("ConvertModuleUsageRecords descriptionId=%{public}ud.", moduleUsageRecord.descriptionId); + + napi_value nabilityName; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, moduleUsageRecord.abilityName.c_str(), NAPI_AUTO_LENGTH, &nabilityName)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objModuleUsageRecord, "abilityName", nabilityName)); + HILOG_INFO("ConvertModuleUsageRecords abilityName=%{public}s.", moduleUsageRecord.abilityName.c_str()); + + napi_value nabilityLabelId; + NAPI_CALL_RETURN_VOID(env, napi_create_uint32(env, moduleUsageRecord.abilityLabelId, &nabilityLabelId)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objModuleUsageRecord, "abilityLabelId", nabilityLabelId)); + HILOG_INFO("ConvertModuleUsageRecords abilityLabelId=%{public}ud.", moduleUsageRecord.abilityLabelId); + + napi_value nabilityDescriptionId; + NAPI_CALL_RETURN_VOID(env, napi_create_uint32(env, moduleUsageRecord.abilityDescriptionId, &nabilityDescriptionId)); + NAPI_CALL_RETURN_VOID( + env, napi_set_named_property(env, objModuleUsageRecord, "abilityDescriptionId", nabilityDescriptionId)); + HILOG_INFO("ConvertModuleUsageRecords abilityDescriptionId=%{public}ud.", moduleUsageRecord.abilityDescriptionId); + + napi_value nabilityIconId; + NAPI_CALL_RETURN_VOID(env, napi_create_uint32(env, moduleUsageRecord.abilityIconId, &nabilityIconId)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objModuleUsageRecord, "abilityIconId", nabilityIconId)); + HILOG_INFO("ConvertModuleUsageRecords abilityIconId=%{public}ud.", moduleUsageRecord.abilityIconId); + + napi_value nlaunchedCount; + NAPI_CALL_RETURN_VOID(env, napi_create_uint32(env, moduleUsageRecord.launchedCount, &nlaunchedCount)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objModuleUsageRecord, "launchedCount", nlaunchedCount)); + HILOG_INFO("ConvertModuleUsageRecords launchedCount=%{public}ud.", moduleUsageRecord.launchedCount); + + napi_value nlastLaunchTime; + NAPI_CALL_RETURN_VOID(env, napi_create_int64(env, moduleUsageRecord.lastLaunchTime, &nlastLaunchTime)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objModuleUsageRecord, "lastLaunchTime", nlastLaunchTime)); + + napi_value nremoved; + NAPI_CALL_RETURN_VOID(env, napi_get_boolean(env, moduleUsageRecord.removed, &nremoved)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objModuleUsageRecord, "isRemoved", nremoved)); + + napi_value ninstallationFreeSupported; + NAPI_CALL_RETURN_VOID( + env, napi_get_boolean(env, moduleUsageRecord.installationFreeSupported, &ninstallationFreeSupported)); + NAPI_CALL_RETURN_VOID(env, + napi_set_named_property(env, objModuleUsageRecord, "installationFreeSupported", ninstallationFreeSupported)); } + static std::string GetStringFromNAPI(napi_env env, napi_value value) { std::string result; size_t size = 0; - if (napi_get_value_string_utf8(env, value, nullptr, NAPI_RETURN_ZERO, &size) != napi_ok) { + if (napi_get_value_string_utf8(env, value, nullptr, 0, &size) != napi_ok) { HILOG_ERROR("can not get string size"); return ""; } - result.reserve(size + NAPI_RETURN_ONE); + result.reserve(size + 1); result.resize(size); - if (napi_get_value_string_utf8(env, value, result.data(), (size + NAPI_RETURN_ONE), &size) != napi_ok) { + if (napi_get_value_string_utf8(env, value, result.data(), (size + 1), &size) != napi_ok) { HILOG_ERROR("can not get string value"); return ""; } @@ -726,7 +836,7 @@ static napi_value ParseInt(napi_env env, int ¶m, napi_value args) param = value; // create result code napi_value result; - status = napi_create_int32(env, NAPI_RETURN_ONE, &result); + status = napi_create_int32(env, 1, &result); NAPI_ASSERT(env, status == napi_ok, "napi_create_int32 error!"); return result; } @@ -788,8 +898,8 @@ napi_value GetApplicationInfos(napi_env env, napi_callback_info info) HILOG_INFO("ARGCSIZE is =%{public}zu.", argc); int flag; int userId; - ParseInt(env, flag, argv[PARAM0]); - ParseInt(env, userId, argv[PARAM1]); + ParseInt(env, flag, argv[0]); + ParseInt(env, userId, argv[1]); ApplicationFlag applicationFlag = ApplicationFlag::GET_APPLICATION_INFO_WITH_PERMS; if (flag == static_cast(ApplicationFlag::GET_BASIC_APPLICATION_INFO)) { applicationFlag = ApplicationFlag::GET_BASIC_APPLICATION_INFO; @@ -804,7 +914,7 @@ napi_value GetApplicationInfos(napi_env env, napi_callback_info info) napi_valuetype valuetype = napi_undefined; napi_typeof(env, argv[ARGS_SIZE_TWO], &valuetype); NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); - NAPI_CALL(env, napi_create_reference(env, argv[ARGS_SIZE_TWO], NAPI_RETURN_ONE, &asyncCallbackInfo->callback)); + NAPI_CALL(env, napi_create_reference(env, argv[ARGS_SIZE_TWO], 1, &asyncCallbackInfo->callback)); napi_create_async_work( env, @@ -837,8 +947,16 @@ napi_value GetApplicationInfos(napi_env env, napi_callback_info info) (void *)asyncCallbackInfo, &asyncCallbackInfo->asyncWork); NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork)); + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } napi_value result; - NAPI_CALL(env, napi_create_int32(env, NAPI_RETURN_ONE, &result)); + NAPI_CALL(env, napi_create_int32(env, 1, &result)); return result; } else { HILOG_INFO("GetApplicationInfos promise."); @@ -871,6 +989,15 @@ napi_value GetApplicationInfos(napi_env env, napi_callback_info info) (void *)asyncCallbackInfo, &asyncCallbackInfo->asyncWork); napi_queue_async_work(env, asyncCallbackInfo->asyncWork); + + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } return promise; } } @@ -934,7 +1061,7 @@ static napi_value ParseWant(napi_env env, Want &want, napi_value args) // create result code napi_value result; - status = napi_create_int32(env, NAPI_RETURN_ONE, &result); + status = napi_create_int32(env, 1, &result); NAPI_ASSERT(env, status == napi_ok, "napi_create_int32 error!"); return result; } @@ -971,7 +1098,7 @@ static napi_value ParseQueryParameter(napi_env env, QueryParameter &queryParamet HILOG_INFO("ParseQueryParameter userId=%{public}s.", queryParameter.userId.c_str()); // create result code napi_value result; - status = napi_create_int32(env, NAPI_RETURN_ONE, &result); + status = napi_create_int32(env, 1, &result); NAPI_ASSERT(env, status == napi_ok, "napi_create_int32 error!"); return result; } @@ -988,12 +1115,12 @@ napi_value QueryAbilityInfo(napi_env env, napi_callback_info info) NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); HILOG_INFO("argc = [%{public}zu]", argc); Want want; - ParseWant(env, want, argv[PARAM0]); + ParseWant(env, want, argv[0]); HILOG_INFO("After ParseWant action=%{public}s.", want.GetAction().c_str()); HILOG_INFO("After ParseWant bundleName=%{public}s.", want.GetElement().GetBundleName().c_str()); HILOG_INFO("After ParseWant abilityName=%{public}s.", want.GetElement().GetAbilityName().c_str()); QueryParameter queryParameter; - ParseQueryParameter(env, queryParameter, argv[PARAM1]); + ParseQueryParameter(env, queryParameter, argv[1]); AsyncAbilityInfoCallbackInfo *asyncCallbackInfo = new AsyncAbilityInfoCallbackInfo{.env = env, .asyncWork = nullptr, .deferred = nullptr, .want = want}; @@ -1002,7 +1129,7 @@ napi_value QueryAbilityInfo(napi_env env, napi_callback_info info) napi_valuetype valuetype = napi_undefined; napi_typeof(env, argv[ARGS_SIZE_TWO], &valuetype); NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); - NAPI_CALL(env, napi_create_reference(env, argv[ARGS_SIZE_TWO], NAPI_RETURN_ONE, &asyncCallbackInfo->callback)); + NAPI_CALL(env, napi_create_reference(env, argv[ARGS_SIZE_TWO], 1, &asyncCallbackInfo->callback)); napi_value resourceName; napi_create_string_latin1(env, "QueryAbilityInfo", NAPI_AUTO_LENGTH, &resourceName); @@ -1038,8 +1165,16 @@ napi_value QueryAbilityInfo(napi_env env, napi_callback_info info) &asyncCallbackInfo->asyncWork); NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork)); + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } napi_value result; - NAPI_CALL(env, napi_create_int32(env, NAPI_RETURN_ONE, &result)); + NAPI_CALL(env, napi_create_int32(env, 1, &result)); return result; } else { HILOG_INFO("QueryAbilityInfo promise."); @@ -1071,6 +1206,16 @@ napi_value QueryAbilityInfo(napi_env env, napi_callback_info info) (void *)asyncCallbackInfo, &asyncCallbackInfo->asyncWork); napi_queue_async_work(env, asyncCallbackInfo->asyncWork); + + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } + return promise; } } @@ -1096,7 +1241,7 @@ static napi_value ParseString(napi_env env, std::string ¶m, napi_value args) HILOG_INFO("param=%{public}s.", param.c_str()); // create result code napi_value result; - status = napi_create_int32(env, NAPI_RETURN_ONE, &result); + status = napi_create_int32(env, 1, &result); NAPI_ASSERT(env, status == napi_ok, "napi_create_int32 error!"); return result; } @@ -1113,9 +1258,9 @@ napi_value GetApplicationInfo(napi_env env, napi_callback_info info) int flag; int userId; std::string bundleName; - ParseString(env, bundleName, argv[PARAM0]); - ParseInt(env, flag, argv[PARAM1]); - ParseInt(env, userId, argv[PARAM2]); + ParseString(env, bundleName, argv[0]); + ParseInt(env, flag, argv[1]); + ParseInt(env, userId, argv[2]); ApplicationFlag applicationFlag = ApplicationFlag::GET_APPLICATION_INFO_WITH_PERMS; if (flag == static_cast(ApplicationFlag::GET_BASIC_APPLICATION_INFO)) { applicationFlag = ApplicationFlag::GET_BASIC_APPLICATION_INFO; @@ -1132,7 +1277,7 @@ napi_value GetApplicationInfo(napi_env env, napi_callback_info info) napi_valuetype valuetype = napi_undefined; napi_typeof(env, argv[ARGS_SIZE_THREE], &valuetype); NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); - NAPI_CALL(env, napi_create_reference(env, argv[ARGS_SIZE_THREE], NAPI_RETURN_ONE, &asyncCallbackInfo->callback)); + NAPI_CALL(env, napi_create_reference(env, argv[ARGS_SIZE_THREE], 1, &asyncCallbackInfo->callback)); napi_value resourceName; napi_create_string_latin1(env, "NAPI_GetApplicationInfoCallBack", NAPI_AUTO_LENGTH, &resourceName); @@ -1175,8 +1320,16 @@ napi_value GetApplicationInfo(napi_env env, napi_callback_info info) &asyncCallbackInfo->asyncWork); NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork)); + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } napi_value result; - NAPI_CALL(env, napi_create_int32(env, NAPI_RETURN_ONE, &result)); + NAPI_CALL(env, napi_create_int32(env, 1, &result)); return result; } else { HILOG_INFO("GetApplicationInfo promise."); @@ -1216,6 +1369,15 @@ napi_value GetApplicationInfo(napi_env env, napi_callback_info info) (void *)asyncCallbackInfo, &asyncCallbackInfo->asyncWork); napi_queue_async_work(env, asyncCallbackInfo->asyncWork); + + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } return promise; } } @@ -1265,7 +1427,7 @@ napi_value GetBundleInfos(napi_env env, napi_callback_info info) void *data = nullptr; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, &data)); int flag; - ParseInt(env, flag, argv[PARAM0]); + ParseInt(env, flag, argv[0]); BundleFlag bundleFlag = BundleFlag::GET_BUNDLE_WITH_ABILITIES; if (flag == static_cast(BundleFlag::GET_BUNDLE_DEFAULT)) { bundleFlag = BundleFlag::GET_BUNDLE_DEFAULT; @@ -1279,7 +1441,7 @@ napi_value GetBundleInfos(napi_env env, napi_callback_info info) napi_valuetype valuetype = napi_undefined; napi_typeof(env, argv[ARGS_SIZE_ONE], &valuetype); NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); - NAPI_CALL(env, napi_create_reference(env, argv[ARGS_SIZE_ONE], NAPI_RETURN_ONE, &asyncCallbackInfo->callback)); + NAPI_CALL(env, napi_create_reference(env, argv[ARGS_SIZE_ONE], 1, &asyncCallbackInfo->callback)); napi_create_async_work( env, @@ -1312,8 +1474,17 @@ napi_value GetBundleInfos(napi_env env, napi_callback_info info) (void *)asyncCallbackInfo, &asyncCallbackInfo->asyncWork); NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork)); + + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } napi_value result; - NAPI_CALL(env, napi_create_int32(env, NAPI_RETURN_ONE, &result)); + NAPI_CALL(env, napi_create_int32(env, 1, &result)); return result; } else { HILOG_INFO("BundleMgr::GetBundleInfos promise."); @@ -1345,9 +1516,19 @@ napi_value GetBundleInfos(napi_env env, napi_callback_info info) (void *)asyncCallbackInfo, &asyncCallbackInfo->asyncWork); napi_queue_async_work(env, asyncCallbackInfo->asyncWork); + + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } return promise; } } + static bool InnerGetBundleInfo( napi_env env, const std::string &bundleName, const BundleFlag bundleFlag, BundleInfo &bundleInfo) { @@ -1374,8 +1555,8 @@ napi_value GetBundleInfo(napi_env env, napi_callback_info info) HILOG_INFO("argc = [%{public}zu]", argc); std::string bundleName; int flag; - ParseString(env, bundleName, argv[PARAM0]); - ParseInt(env, flag, argv[PARAM1]); + ParseString(env, bundleName, argv[0]); + ParseInt(env, flag, argv[1]); BundleFlag bundleFlag = BundleFlag::GET_BUNDLE_WITH_ABILITIES; if (flag == static_cast(BundleFlag::GET_BUNDLE_DEFAULT)) { bundleFlag = BundleFlag::GET_BUNDLE_DEFAULT; @@ -1388,7 +1569,7 @@ napi_value GetBundleInfo(napi_env env, napi_callback_info info) napi_valuetype valuetype = napi_undefined; napi_typeof(env, argv[ARGS_SIZE_TWO], &valuetype); NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); - NAPI_CALL(env, napi_create_reference(env, argv[ARGS_SIZE_TWO], NAPI_RETURN_ONE, &asyncCallbackInfo->callback)); + NAPI_CALL(env, napi_create_reference(env, argv[ARGS_SIZE_TWO], 1, &asyncCallbackInfo->callback)); napi_value resourceName; napi_create_string_latin1(env, "NAPI_InnerGetBundleInfo", NAPI_AUTO_LENGTH, &resourceName); @@ -1424,8 +1605,16 @@ napi_value GetBundleInfo(napi_env env, napi_callback_info info) &asyncCallbackInfo->asyncWork); NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork)); + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } napi_value result; - NAPI_CALL(env, napi_create_int32(env, NAPI_RETURN_ONE, &result)); + NAPI_CALL(env, napi_create_int32(env, 1, &result)); return result; } else { HILOG_INFO("GetBundleinfo promise."); @@ -1458,6 +1647,15 @@ napi_value GetBundleInfo(napi_env env, napi_callback_info info) (void *)asyncCallbackInfo, &asyncCallbackInfo->asyncWork); napi_queue_async_work(env, asyncCallbackInfo->asyncWork); + + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } return promise; } } @@ -1488,8 +1686,8 @@ napi_value GetBundleArchiveInfo(napi_env env, napi_callback_info info) HILOG_INFO("argc = [%{public}zu]", argc); std::string hapFilePath; int flag; - ParseString(env, hapFilePath, argv[PARAM0]); - ParseInt(env, flag, argv[PARAM1]); + ParseString(env, hapFilePath, argv[0]); + ParseInt(env, flag, argv[1]); BundleFlag bundleFlag = BundleFlag::GET_BUNDLE_WITH_ABILITIES; if (flag == static_cast(BundleFlag::GET_BUNDLE_DEFAULT)) { bundleFlag = BundleFlag::GET_BUNDLE_DEFAULT; @@ -1502,7 +1700,7 @@ napi_value GetBundleArchiveInfo(napi_env env, napi_callback_info info) napi_valuetype valuetype = napi_undefined; napi_typeof(env, argv[ARGS_SIZE_TWO], &valuetype); NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); - NAPI_CALL(env, napi_create_reference(env, argv[ARGS_SIZE_TWO], NAPI_RETURN_ONE, &asyncCallbackInfo->callback)); + NAPI_CALL(env, napi_create_reference(env, argv[ARGS_SIZE_TWO], 1, &asyncCallbackInfo->callback)); napi_value resourceName; napi_create_string_latin1(env, "NAPI_GetBundleArchiveInfo", NAPI_AUTO_LENGTH, &resourceName); @@ -1537,8 +1735,16 @@ napi_value GetBundleArchiveInfo(napi_env env, napi_callback_info info) (void *)asyncCallbackInfo, &asyncCallbackInfo->asyncWork); NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork)); + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } napi_value result; - NAPI_CALL(env, napi_create_int32(env, NAPI_RETURN_ONE, &result)); + NAPI_CALL(env, napi_create_int32(env, 1, &result)); return result; } else { HILOG_INFO("GetBundleArchiveInfo promise."); @@ -1571,6 +1777,15 @@ napi_value GetBundleArchiveInfo(napi_env env, napi_callback_info info) (void *)asyncCallbackInfo, &asyncCallbackInfo->asyncWork); napi_queue_async_work(env, asyncCallbackInfo->asyncWork); + + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } return promise; } } @@ -1659,7 +1874,7 @@ napi_value GetPermissionDef(napi_env env, napi_callback_info info) NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); HILOG_INFO("argc = [%{public}zu]", argc); std::string permissionName; - ParseString(env, permissionName, argv[PARAM0]); + ParseString(env, permissionName, argv[0]); AsyncPermissionDefCallbackInfo *asyncCallbackInfo = new AsyncPermissionDefCallbackInfo{ .env = env, .asyncWork = nullptr, .deferred = nullptr, .permissionName = permissionName}; @@ -1668,7 +1883,7 @@ napi_value GetPermissionDef(napi_env env, napi_callback_info info) napi_valuetype valuetype = napi_undefined; napi_typeof(env, argv[ARGS_SIZE_ONE], &valuetype); NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); - NAPI_CALL(env, napi_create_reference(env, argv[ARGS_SIZE_ONE], NAPI_RETURN_ONE, &asyncCallbackInfo->callback)); + NAPI_CALL(env, napi_create_reference(env, argv[ARGS_SIZE_ONE], 1, &asyncCallbackInfo->callback)); napi_value resourceName; napi_create_string_latin1(env, "GetPermissionDef", NAPI_AUTO_LENGTH, &resourceName); @@ -1703,8 +1918,16 @@ napi_value GetPermissionDef(napi_env env, napi_callback_info info) (void *)asyncCallbackInfo, &asyncCallbackInfo->asyncWork); NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork)); + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } napi_value result; - NAPI_CALL(env, napi_create_int32(env, NAPI_RETURN_ONE, &result)); + NAPI_CALL(env, napi_create_int32(env, 1, &result)); return result; } else { napi_deferred deferred; @@ -1735,6 +1958,15 @@ napi_value GetPermissionDef(napi_env env, napi_callback_info info) (void *)asyncCallbackInfo, &asyncCallbackInfo->asyncWork); napi_queue_async_work(env, asyncCallbackInfo->asyncWork); + + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } return promise; } } @@ -1779,7 +2011,7 @@ napi_value GetBundleInstaller(napi_env env, napi_callback_info info) size_t argc = ARGS_SIZE_ONE; napi_value argv[ARGS_SIZE_ONE] = {nullptr}; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); - HILOG_INFO("argc = [%{public}zu]", argc); + HILOG_INFO("argc = [%{public}d]", argc); AsyncGetBundleInstallerCallbackInfo *asyncCallbackInfo = new AsyncGetBundleInstallerCallbackInfo{.env = env, .asyncWork = nullptr, .deferred = nullptr}; @@ -1787,9 +2019,9 @@ napi_value GetBundleInstaller(napi_env env, napi_callback_info info) if (argc > (ARGS_SIZE_ONE - CALLBACK_SIZE)) { HILOG_INFO("GetBundleInstaller asyncCallback."); napi_valuetype valuetype = napi_undefined; - NAPI_CALL(env, napi_typeof(env, argv[PARAM0], &valuetype)); + NAPI_CALL(env, napi_typeof(env, argv[0], &valuetype)); NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); - napi_create_reference(env, argv[PARAM0], NAPI_RETURN_ONE, &asyncCallbackInfo->callback); + napi_create_reference(env, argv[0], 1, &asyncCallbackInfo->callback); napi_value resourceName; napi_create_string_latin1(env, "GetBundleInstaller", NAPI_AUTO_LENGTH, &resourceName); @@ -1818,8 +2050,16 @@ napi_value GetBundleInstaller(napi_env env, napi_callback_info info) (void *)asyncCallbackInfo, &asyncCallbackInfo->asyncWork); NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork)); + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } napi_value result; - NAPI_CALL(env, napi_create_int32(env, NAPI_RETURN_ONE, &result)); + NAPI_CALL(env, napi_create_int32(env, 1, &result)); return result; } else { napi_deferred deferred; @@ -1846,6 +2086,15 @@ napi_value GetBundleInstaller(napi_env env, napi_callback_info info) (void *)asyncCallbackInfo, &asyncCallbackInfo->asyncWork); napi_queue_async_work(env, asyncCallbackInfo->asyncWork); + + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } return promise; } } @@ -1874,6 +2123,16 @@ static napi_value ParseInstallParam(napi_env env, InstallParam &installParam, na installParam.userId = userId; HILOG_INFO("ParseInstallParam userId=%{public}d.", installParam.userId); + property = nullptr; + status = napi_get_named_property(env, installProp, "noCheckSignature", &property); + NAPI_ASSERT(env, status == napi_ok, "property noCheckSignature incorrect!"); + napi_typeof(env, property, &valueType); + NAPI_ASSERT(env, valueType == napi_boolean, "property type mismatch!"); + bool noCheckSignature = false; + NAPI_CALL(env, napi_get_value_bool(env, property, &noCheckSignature)); + installParam.noCheckSignature = noCheckSignature; + HILOG_INFO("ParseInstallParam noCheckSignature=%{public}d.", installParam.noCheckSignature); + property = nullptr; status = napi_get_named_property(env, installProp, "isKeepData", &property); NAPI_ASSERT(env, status == napi_ok, "property isKeepData incorrect!"); @@ -1885,7 +2144,7 @@ static napi_value ParseInstallParam(napi_env env, InstallParam &installParam, na HILOG_INFO("ParseInstallParam isKeepData=%{public}d.", installParam.isKeepData); // create result code napi_value result; - status = napi_create_int32(env, NAPI_RETURN_ONE, &result); + status = napi_create_int32(env, 1, &result); NAPI_ASSERT(env, status == napi_ok, "napi_create_int32 error!"); return result; } @@ -1899,7 +2158,7 @@ static napi_value ParseStringArray(napi_env env, std::vector &hapFi napi_valuetype valueAryType = napi_undefined; NAPI_CALL(env, napi_is_array(env, args, &isArray)); NAPI_CALL(env, napi_get_array_length(env, args, &arrayLength)); - HILOG_INFO("ParseStringArray args is array, length=%{public}d", arrayLength); + HILOG_INFO("ParseStringArray args is array, length=%{public}ud", arrayLength); for (uint32_t j = 0; j < arrayLength; j++) { NAPI_CALL(env, napi_get_element(env, args, j, &valueAry)); @@ -1913,7 +2172,7 @@ static napi_value ParseStringArray(napi_env env, std::vector &hapFi // create result code napi_value result; napi_status status; - status = napi_create_int32(env, NAPI_RETURN_ONE, &result); + status = napi_create_int32(env, 1, &result); NAPI_ASSERT(env, status == napi_ok, "napi_create_int32 error!"); return result; } @@ -1978,17 +2237,21 @@ static void ConvertInstallResult(InstallResult &installResult) installResult.resultCode = static_cast(InstallErrorCode::STATUS_INSTALL_FAILURE_STORAGE); installResult.resultMsg = "STATUS_INSTALL_FAILURE_STORAGE"; break; - case static_cast(IStatusReceiver::ERR_UNINSTALL_SYSTEM_APP_ERROR): - case static_cast(IStatusReceiver::ERR_UNINSTALL_KILLING_APP_ERROR): - installResult.resultCode = static_cast(InstallErrorCode::STATUS_UNINSTALL_FAILURE_CONFLICT); - installResult.resultMsg = "STATUS_UNINSTALL_FAILURE_CONFLICT"; - break; case static_cast(IStatusReceiver::ERR_UNINSTALL_INVALID_NAME): case static_cast(IStatusReceiver::ERR_UNINSTALL_PARAM_ERROR): case static_cast(IStatusReceiver::ERR_UNINSTALL_PERMISSION_DENIED): - installResult.resultCode = static_cast(InstallErrorCode::STATUS_UNINSTALL_FAILURE_ABORTED); - installResult.resultMsg = "STATUS_UNINSTALL_FAILURE_ABORTED"; - break; + if (CheckIsSystemApp()) { + installResult.resultCode = static_cast(InstallErrorCode::STATUS_UNINSTALL_FAILURE_ABORTED); + installResult.resultMsg = "STATUS_UNINSTALL_FAILURE_ABORTED"; + break; + } + case static_cast(IStatusReceiver::ERR_UNINSTALL_SYSTEM_APP_ERROR): + case static_cast(IStatusReceiver::ERR_UNINSTALL_KILLING_APP_ERROR): + if (CheckIsSystemApp()) { + installResult.resultCode = static_cast(InstallErrorCode::STATUS_UNINSTALL_FAILURE_CONFLICT); + installResult.resultMsg = "STATUS_UNINSTALL_FAILURE_CONFLICT"; + break; + } case static_cast(IStatusReceiver::ERR_UNINSTALL_BUNDLE_MGR_SERVICE_ERROR): case static_cast(IStatusReceiver::ERR_UNINSTALL_MISSING_INSTALLED_BUNDLE): case static_cast(IStatusReceiver::ERR_UNINSTALL_MISSING_INSTALLED_MODULE): @@ -2013,9 +2276,9 @@ napi_value Install(napi_env env, napi_callback_info info) NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); HILOG_INFO("argc = [%{public}zu]", argc); std::vector bundleFilePaths; - ParseStringArray(env, bundleFilePaths, argv[PARAM0]); + ParseStringArray(env, bundleFilePaths, argv[0]); InstallParam installParam; - ParseInstallParam(env, installParam, argv[PARAM1]); + ParseInstallParam(env, installParam, argv[1]); AsyncInstallCallbackInfo *asyncCallbackInfo = new AsyncInstallCallbackInfo{ .env = env, .asyncWork = nullptr, @@ -2029,7 +2292,7 @@ napi_value Install(napi_env env, napi_callback_info info) napi_valuetype valuetype = napi_undefined; NAPI_CALL(env, napi_typeof(env, argv[ARGS_SIZE_TWO], &valuetype)); NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); - napi_create_reference(env, argv[ARGS_SIZE_TWO], NAPI_RETURN_ONE, &asyncCallbackInfo->callback); + napi_create_reference(env, argv[ARGS_SIZE_TWO], 1, &asyncCallbackInfo->callback); napi_value resourceName; napi_create_string_latin1(env, "Install", NAPI_AUTO_LENGTH, &resourceName); @@ -2074,8 +2337,16 @@ napi_value Install(napi_env env, napi_callback_info info) (void *)asyncCallbackInfo, &asyncCallbackInfo->asyncWork); NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork)); + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } napi_value result; - NAPI_CALL(env, napi_create_int32(env, NAPI_RETURN_ONE, &result)); + NAPI_CALL(env, napi_create_int32(env, 1, &result)); return result; } else { napi_deferred deferred; @@ -2116,6 +2387,15 @@ napi_value Install(napi_env env, napi_callback_info info) (void *)asyncCallbackInfo, &asyncCallbackInfo->asyncWork); napi_queue_async_work(env, asyncCallbackInfo->asyncWork); + + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } return promise; } } @@ -2156,9 +2436,9 @@ napi_value Uninstall(napi_env env, napi_callback_info info) NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); HILOG_INFO("argc = [%{public}zu]", argc); std::string bundleName; - ParseString(env, bundleName, argv[PARAM0]); + ParseString(env, bundleName, argv[0]); InstallParam installParam; - ParseInstallParam(env, installParam, argv[PARAM1]); + ParseInstallParam(env, installParam, argv[1]); AsyncInstallCallbackInfo *asyncCallbackInfo = new AsyncInstallCallbackInfo{ .env = env, .asyncWork = nullptr, @@ -2172,7 +2452,7 @@ napi_value Uninstall(napi_env env, napi_callback_info info) napi_valuetype valuetype = napi_undefined; NAPI_CALL(env, napi_typeof(env, argv[ARGS_SIZE_TWO], &valuetype)); NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); - napi_create_reference(env, argv[ARGS_SIZE_TWO], NAPI_RETURN_ONE, &asyncCallbackInfo->callback); + napi_create_reference(env, argv[ARGS_SIZE_TWO], 1, &asyncCallbackInfo->callback); napi_value resourceName; napi_create_string_latin1(env, "Uninstall", NAPI_AUTO_LENGTH, &resourceName); @@ -2216,9 +2496,16 @@ napi_value Uninstall(napi_env env, napi_callback_info info) &asyncCallbackInfo->asyncWork); NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork)); + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } napi_value result; - NAPI_CALL(env, napi_create_int32(env, NAPI_RETURN_ONE, &result)); - + NAPI_CALL(env, napi_create_int32(env, 1, &result)); return result; } else { napi_deferred deferred; @@ -2257,6 +2544,15 @@ napi_value Uninstall(napi_env env, napi_callback_info info) (void *)asyncCallbackInfo, &asyncCallbackInfo->asyncWork); napi_queue_async_work(env, asyncCallbackInfo->asyncWork); + + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } return promise; } } @@ -2315,9 +2611,9 @@ napi_value GetAllFormsInfo(napi_env env, napi_callback_info info) napi_value resourceName; NAPI_CALL(env, napi_create_string_latin1(env, "GetAllFormsInfo", NAPI_AUTO_LENGTH, &resourceName)); napi_valuetype valuetype = napi_undefined; - napi_typeof(env, argv[PARAM0], &valuetype); + napi_typeof(env, argv[0], &valuetype); NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); - NAPI_CALL(env, napi_create_reference(env, argv[PARAM0], NAPI_RETURN_ONE, &asyncCallbackInfo->callback)); + NAPI_CALL(env, napi_create_reference(env, argv[0], 1, &asyncCallbackInfo->callback)); napi_create_async_work( env, @@ -2349,8 +2645,17 @@ napi_value GetAllFormsInfo(napi_env env, napi_callback_info info) (void *)asyncCallbackInfo, &asyncCallbackInfo->asyncWork); NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork)); + + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } napi_value result; - NAPI_CALL(env, napi_create_int32(env, NAPI_RETURN_ONE, &result)); + NAPI_CALL(env, napi_create_int32(env, 1, &result)); return result; } else { HILOG_INFO("GetFormInfos promise."); @@ -2382,6 +2687,15 @@ napi_value GetAllFormsInfo(napi_env env, napi_callback_info info) (void *)asyncCallbackInfo, &asyncCallbackInfo->asyncWork); napi_queue_async_work(env, asyncCallbackInfo->asyncWork); + + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } return promise; } } @@ -2409,8 +2723,8 @@ napi_value GetFormsInfoByModule(napi_env env, napi_callback_info info) HILOG_INFO("ARGCSIZE is =%{public}zu.", argc); std::string bundleName; std::string moduleName; - ParseString(env, bundleName, argv[PARAM0]); - ParseString(env, moduleName, argv[PARAM1]); + ParseString(env, bundleName, argv[0]); + ParseString(env, moduleName, argv[1]); AsyncFormInfosByModuleCallbackInfo *asyncCallbackInfo = new AsyncFormInfosByModuleCallbackInfo{ .env = env, .asyncWork = nullptr, .deferred = nullptr, .bundleName = bundleName, .moduleName = moduleName}; @@ -2421,7 +2735,7 @@ napi_value GetFormsInfoByModule(napi_env env, napi_callback_info info) napi_valuetype valuetype = napi_undefined; napi_typeof(env, argv[ARGS_SIZE_TWO], &valuetype); NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); - NAPI_CALL(env, napi_create_reference(env, argv[ARGS_SIZE_TWO], NAPI_RETURN_ONE, &asyncCallbackInfo->callback)); + NAPI_CALL(env, napi_create_reference(env, argv[ARGS_SIZE_TWO], 1, &asyncCallbackInfo->callback)); napi_create_async_work( env, @@ -2454,8 +2768,16 @@ napi_value GetFormsInfoByModule(napi_env env, napi_callback_info info) (void *)asyncCallbackInfo, &asyncCallbackInfo->asyncWork); NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork)); + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } napi_value result; - NAPI_CALL(env, napi_create_int32(env, NAPI_RETURN_ONE, &result)); + NAPI_CALL(env, napi_create_int32(env, 1, &result)); return result; } else { HILOG_INFO("GetFormsInfoByModule promise."); @@ -2488,6 +2810,15 @@ napi_value GetFormsInfoByModule(napi_env env, napi_callback_info info) (void *)asyncCallbackInfo, &asyncCallbackInfo->asyncWork); napi_queue_async_work(env, asyncCallbackInfo->asyncWork); + + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } return promise; } } @@ -2514,7 +2845,7 @@ napi_value GetFormsInfoByApp(napi_env env, napi_callback_info info) NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, &data)); HILOG_INFO("ARGCSIZE is =%{public}zu.", argc); std::string bundleName; - ParseString(env, bundleName, argv[PARAM0]); + ParseString(env, bundleName, argv[0]); AsyncFormInfosByAppCallbackInfo *asyncCallbackInfo = new AsyncFormInfosByAppCallbackInfo{ .env = env, .asyncWork = nullptr, .deferred = nullptr, .bundleName = bundleName}; @@ -2525,7 +2856,7 @@ napi_value GetFormsInfoByApp(napi_env env, napi_callback_info info) napi_valuetype valuetype = napi_undefined; napi_typeof(env, argv[ARGS_SIZE_ONE], &valuetype); NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); - NAPI_CALL(env, napi_create_reference(env, argv[ARGS_SIZE_ONE], NAPI_RETURN_ONE, &asyncCallbackInfo->callback)); + NAPI_CALL(env, napi_create_reference(env, argv[ARGS_SIZE_ONE], 1, &asyncCallbackInfo->callback)); napi_create_async_work( env, @@ -2558,8 +2889,16 @@ napi_value GetFormsInfoByApp(napi_env env, napi_callback_info info) (void *)asyncCallbackInfo, &asyncCallbackInfo->asyncWork); NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork)); + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } napi_value result; - NAPI_CALL(env, napi_create_int32(env, NAPI_RETURN_ONE, &result)); + NAPI_CALL(env, napi_create_int32(env, 1, &result)); return result; } else { HILOG_INFO("GetFormsInfoByApp promise."); @@ -2591,11 +2930,21 @@ napi_value GetFormsInfoByApp(napi_env env, napi_callback_info info) (void *)asyncCallbackInfo, &asyncCallbackInfo->asyncWork); napi_queue_async_work(env, asyncCallbackInfo->asyncWork); + + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } return promise; } } -static void ProcessShortcutInfos(napi_env env, napi_value result, const std::vector &shortcutInfos) +static void ProcessShortcutInfos( + napi_env env, napi_value result, const std::vector &shortcutInfos) { if (shortcutInfos.size() > 0) { HILOG_INFO("-----ShortcutInfos is not null-----"); @@ -2614,14 +2963,15 @@ static void ProcessShortcutInfos(napi_env env, napi_value result, const std::vec } } -static bool InnerGetShortcutInfos(napi_env env, const std::string &bundleName, std::vector &shortcutInfos) +static bool InnerGetShortcutInfos( + napi_env env, const std::string &bundleName, std::vector &shortcutInfos) { auto iBundleMgr = GetBundleMgr(); if (!iBundleMgr) { HILOG_ERROR("can not get iBundleMgr"); return false; } - return iBundleMgr-> GetShortcutInfos(bundleName, shortcutInfos); + return iBundleMgr->GetShortcutInfos(bundleName, shortcutInfos); } /** * Promise and async callback @@ -2635,7 +2985,7 @@ napi_value GetShortcutInfos(napi_env env, napi_callback_info info) NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, &data)); HILOG_INFO("ARGCSIZE is =%{public}zu.", argc); std::string bundleName; - ParseString(env, bundleName, argv[PARAM0]); + ParseString(env, bundleName, argv[0]); AsyncShortcutInfosCallbackInfo *asyncCallbackInfo = new AsyncShortcutInfosCallbackInfo{ .env = env, .asyncWork = nullptr, .deferred = nullptr, .bundleName = bundleName}; if (argc > (ARGS_SIZE_TWO - CALLBACK_SIZE)) { @@ -2645,7 +2995,7 @@ napi_value GetShortcutInfos(napi_env env, napi_callback_info info) napi_valuetype valuetype = napi_undefined; napi_typeof(env, argv[ARGS_SIZE_ONE], &valuetype); NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); - NAPI_CALL(env, napi_create_reference(env, argv[ARGS_SIZE_ONE], NAPI_RETURN_ONE, &asyncCallbackInfo->callback)); + NAPI_CALL(env, napi_create_reference(env, argv[ARGS_SIZE_ONE], 1, &asyncCallbackInfo->callback)); napi_create_async_work( env, @@ -2678,8 +3028,16 @@ napi_value GetShortcutInfos(napi_env env, napi_callback_info info) (void *)asyncCallbackInfo, &asyncCallbackInfo->asyncWork); NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork)); + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } napi_value result; - NAPI_CALL(env, napi_create_int32(env, NAPI_RETURN_ONE, &result)); + NAPI_CALL(env, napi_create_int32(env, 1, &result)); return result; } else { HILOG_INFO("GetShortcutInfos promise."); @@ -2711,6 +3069,611 @@ napi_value GetShortcutInfos(napi_env env, napi_callback_info info) (void *)asyncCallbackInfo, &asyncCallbackInfo->asyncWork); napi_queue_async_work(env, asyncCallbackInfo->asyncWork); + + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } + return promise; + } +} + +static void ProcessModuleUsageRecords( + napi_env env, napi_value result, const std::vector &moduleUsageRecords) +{ + if (moduleUsageRecords.size() > 0) { + HILOG_INFO("-----moduleUsageRecords is not null-----"); + size_t index = 0; + for (const auto &item : moduleUsageRecords) { + HILOG_INFO("bundleName{%s} ", item.bundleName.c_str()); + HILOG_INFO("abilityName{%s} ", item.abilityName.c_str()); + napi_value objModuleUsageRecord; + NAPI_CALL_RETURN_VOID(env, napi_create_object(env, &objModuleUsageRecord)); + ConvertModuleUsageRecords(env, objModuleUsageRecord, item); + NAPI_CALL_RETURN_VOID(env, napi_set_element(env, result, index, objModuleUsageRecord)); + index++; + } + } else { + HILOG_INFO("-----moduleUsageRecords is null-----"); + } +} + +static bool InnerGetModuleUsageRecords( + napi_env env, const int32_t number, std::vector &moduleUsageRecords) +{ + auto iBundleMgr = GetBundleMgr(); + if (!iBundleMgr) { + HILOG_ERROR("can not get iBundleMgr"); + return false; + } + return iBundleMgr->GetModuleUsageRecords(number, moduleUsageRecords); +} +/** + * Promise and async callback + */ +napi_value GetModuleUsageRecords(napi_env env, napi_callback_info info) +{ + size_t argc = ARGS_SIZE_THREE; + napi_value argv[ARGS_SIZE_THREE] = {nullptr}; + napi_value thisArg; + void *data = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, &data)); + HILOG_INFO("ARGCSIZE is =%{public}zu.", argc); + int number; + ParseInt(env, number, argv[0]); + AsyncModuleUsageRecordsCallbackInfo *asyncCallbackInfo = new AsyncModuleUsageRecordsCallbackInfo{ + .env = env, .asyncWork = nullptr, .deferred = nullptr, .number = number}; + if (argc > (ARGS_SIZE_TWO - CALLBACK_SIZE)) { + HILOG_INFO("GetModuleUsageRecords asyncCallback."); + napi_value resourceName; + NAPI_CALL(env, napi_create_string_latin1(env, "GetModuleUsageRecords", NAPI_AUTO_LENGTH, &resourceName)); + napi_valuetype valuetype = napi_undefined; + napi_typeof(env, argv[ARGS_SIZE_ONE], &valuetype); + NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); + NAPI_CALL(env, napi_create_reference(env, argv[ARGS_SIZE_ONE], 1, &asyncCallbackInfo->callback)); + + napi_create_async_work( + env, + nullptr, + resourceName, + [](napi_env env, void *data) { + AsyncModuleUsageRecordsCallbackInfo *asyncCallbackInfo = (AsyncModuleUsageRecordsCallbackInfo *)data; + asyncCallbackInfo->ret = + InnerGetModuleUsageRecords(env, asyncCallbackInfo->number, asyncCallbackInfo->moduleUsageRecords); + }, + [](napi_env env, napi_status status, void *data) { + AsyncModuleUsageRecordsCallbackInfo *asyncCallbackInfo = (AsyncModuleUsageRecordsCallbackInfo *)data; + napi_value result[ARGS_SIZE_TWO] = {0}; + napi_value callback = 0; + napi_value undefined = 0; + napi_value callResult = 0; + napi_get_undefined(env, &undefined); + napi_create_array(env, &result[PARAM1]); + ProcessModuleUsageRecords(env, result[PARAM1], asyncCallbackInfo->moduleUsageRecords); + result[PARAM0] = GetCallbackErrorValue(env, asyncCallbackInfo->ret ? CODE_SUCCESS : CODE_FAILED); + napi_get_reference_value(env, asyncCallbackInfo->callback, &callback); + napi_call_function(env, undefined, callback, ARGS_SIZE_TWO, &result[PARAM0], &callResult); + + if (asyncCallbackInfo->callback != nullptr) { + napi_delete_reference(env, asyncCallbackInfo->callback); + } + napi_delete_async_work(env, asyncCallbackInfo->asyncWork); + delete asyncCallbackInfo; + }, + (void *)asyncCallbackInfo, + &asyncCallbackInfo->asyncWork); + NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork)); + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } + napi_value result; + NAPI_CALL(env, napi_create_int32(env, 1, &result)); + return result; + } else { + HILOG_INFO("GetModuleUsageRecords promise."); + napi_deferred deferred; + napi_value promise; + NAPI_CALL(env, napi_create_promise(env, &deferred, &promise)); + asyncCallbackInfo->deferred = deferred; + + napi_value resourceName; + napi_create_string_latin1(env, "GetModuleUsageRecords", NAPI_AUTO_LENGTH, &resourceName); + napi_create_async_work( + env, + nullptr, + resourceName, + [](napi_env env, void *data) { + AsyncModuleUsageRecordsCallbackInfo *asyncCallbackInfo = (AsyncModuleUsageRecordsCallbackInfo *)data; + InnerGetModuleUsageRecords(env, asyncCallbackInfo->number, asyncCallbackInfo->moduleUsageRecords); + }, + [](napi_env env, napi_status status, void *data) { + HILOG_INFO("=================load================="); + AsyncModuleUsageRecordsCallbackInfo *asyncCallbackInfo = (AsyncModuleUsageRecordsCallbackInfo *)data; + napi_value result; + napi_create_array(env, &result); + ProcessModuleUsageRecords(env, result, asyncCallbackInfo->moduleUsageRecords); + napi_resolve_deferred(asyncCallbackInfo->env, asyncCallbackInfo->deferred, result); + napi_delete_async_work(env, asyncCallbackInfo->asyncWork); + delete asyncCallbackInfo; + }, + (void *)asyncCallbackInfo, + &asyncCallbackInfo->asyncWork); + napi_queue_async_work(env, asyncCallbackInfo->asyncWork); + + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } + return promise; + } +} + +static bool InnerRegisterAllPermissionsChanged(napi_env env, napi_ref callbackRef) +{ + HILOG_INFO("InnerRegisterAllPermissionsChanged begin"); + auto iBundleMgr = GetBundleMgr(); + if (!iBundleMgr) { + HILOG_ERROR("can not get iBundleMgr"); + return false; + } + OHOS::sptr callback = new PermissionCallback(env, callbackRef); + if (!callback) { + HILOG_ERROR("callback nullptr"); + return false; + } + auto result = iBundleMgr->RegisterAllPermissionsChanged(callback); + if (!result) { + HILOG_ERROR("RegisterAllPermissionsChanged call error"); + return false; + } + std::lock_guard lock(anyPermissionsCallbackMutex); + auto ret = anyPermissionsCallback.emplace(callbackRef, callback); + if (!ret.second) { + HILOG_ERROR("RegisterAllPermissionsChanged emplace failed"); + return false; + } + HILOG_INFO("InnerRegisterAllPermissionsChanged end"); + return true; +} + +static napi_value ParseInt32Array(napi_env env, std::vector &uids, napi_value args) +{ + HILOG_INFO("Parseint32Array called"); + bool isArray = false; + uint32_t arrayLength = 0; + napi_value valueAry = 0; + napi_valuetype valueAryType = napi_undefined; + NAPI_CALL(env, napi_is_array(env, args, &isArray)); + NAPI_CALL(env, napi_get_array_length(env, args, &arrayLength)); + HILOG_INFO("Parseint32Array args is array, length=%{public}ud", arrayLength); + + for (uint32_t j = 0; j < arrayLength; j++) { + NAPI_CALL(env, napi_get_element(env, args, j, &valueAry)); + NAPI_CALL(env, napi_typeof(env, valueAry, &valueAryType)); + int uid; + ParseInt(env, uid, valueAry); + uids.emplace_back(uid); + } + // create result code + napi_value result; + napi_status status; + status = napi_create_int32(env, 1, &result); + NAPI_ASSERT(env, status == napi_ok, "napi_create_int32 error!"); + return result; +} + +static bool InnerRegisterPermissionsChanged(napi_env env, const std::vector &uids, napi_ref callbackRef) +{ + HILOG_INFO("InnerRegisterPermissionsChanged begin"); + auto iBundleMgr = GetBundleMgr(); + if (!iBundleMgr) { + HILOG_ERROR("can not get iBundleMgr"); + return false; + } + OHOS::sptr callback = new PermissionCallback(env, callbackRef); + if (!callback) { + HILOG_ERROR("callback nullptr"); + return false; + } + auto result = iBundleMgr->RegisterPermissionsChanged(uids, callback); + if (!result) { + HILOG_ERROR("RegisterAllPermissionsChanged call error"); + return false; + } + + PermissionsKey permissonsKey{.callback = callbackRef, .uids = uids}; + + std::lock_guard lock(permissionsCallbackMutex); + auto ret = permissionsCallback.emplace(permissonsKey, callback); + if (!ret.second) { + HILOG_ERROR("InnerRegisterPermissionsChanged emplace failed"); + return false; + } + HILOG_INFO("InnerRegisterPermissionsChanged end"); + return true; +} + +napi_value RegisterAllPermissionsChanged(napi_env env, napi_callback_info info) +{ + size_t argc = ARGS_SIZE_THREE; + napi_value argv[ARGS_SIZE_THREE] = {nullptr}; + napi_value thisArg; + void *data = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, &data)); + HILOG_INFO("ARGCSIZE is = %{public}zu.", argc); + std::string permissionEvent; + ParseString(env, permissionEvent, argv[0]); + if (permissionEvent == PERMISSION_CHANGE && argc == ARGS_SIZE_THREE) { + std::vector uids; + ParseInt32Array(env, uids, argv[ARGS_SIZE_ONE]); + AsyncRegisterPermissions *asyncCallbackInfo = + new AsyncRegisterPermissions{.env = env, .asyncWork = nullptr, .uids = uids}; + HILOG_INFO("RegisterAllPermissionsChanged permissionChange asyncCallback."); + napi_valuetype valuetype = napi_undefined; + napi_typeof(env, argv[ARGS_SIZE_TWO], &valuetype); + NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); + NAPI_CALL(env, napi_create_reference(env, argv[ARGS_SIZE_TWO], 1, &asyncCallbackInfo->callback)); + + napi_value resourceName; + napi_create_string_latin1(env, "NAPI_RegisterPermissionsChanged", NAPI_AUTO_LENGTH, &resourceName); + napi_create_async_work( + env, + nullptr, + resourceName, + [](napi_env env, void *data) { + AsyncRegisterPermissions *asyncCallbackInfo = (AsyncRegisterPermissions *)data; + InnerRegisterPermissionsChanged(env, asyncCallbackInfo->uids, asyncCallbackInfo->callback); + }, + [](napi_env env, napi_status status, void *data) { + AsyncRegisterPermissions *asyncCallbackInfo = (AsyncRegisterPermissions *)data; + napi_delete_async_work(env, asyncCallbackInfo->asyncWork); + delete asyncCallbackInfo; + }, + (void *)asyncCallbackInfo, + &asyncCallbackInfo->asyncWork); + NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork)); + + napi_value result; + NAPI_CALL(env, napi_create_int32(env, 1, &result)); + return result; + } else if (permissionEvent == ANY_PERMISSION_CHANGE && argc == ARGS_SIZE_TWO) { + AsyncRegisterAllPermissions *asyncCallbackInfo = + new AsyncRegisterAllPermissions{.env = env, .asyncWork = nullptr}; + HILOG_INFO("RegisterAllPermissionsChanged anyPermissionChange asyncCallback."); + napi_valuetype valuetype = napi_undefined; + napi_typeof(env, argv[ARGS_SIZE_ONE], &valuetype); + NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); + NAPI_CALL(env, napi_create_reference(env, argv[ARGS_SIZE_ONE], 1, &asyncCallbackInfo->callback)); + napi_value resourceName; + napi_create_string_latin1(env, "NAPI_RegisterAllPermissionsChanged", NAPI_AUTO_LENGTH, &resourceName); + napi_create_async_work( + env, + nullptr, + resourceName, + [](napi_env env, void *data) { + AsyncRegisterAllPermissions *asyncCallbackInfo = (AsyncRegisterAllPermissions *)data; + InnerRegisterAllPermissionsChanged(env, asyncCallbackInfo->callback); + }, + [](napi_env env, napi_status status, void *data) { + AsyncRegisterAllPermissions *asyncCallbackInfo = (AsyncRegisterAllPermissions *)data; + napi_delete_async_work(env, asyncCallbackInfo->asyncWork); + delete asyncCallbackInfo; + }, + (void *)asyncCallbackInfo, + &asyncCallbackInfo->asyncWork); + NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork)); + + napi_value result; + NAPI_CALL(env, napi_create_int32(env, 1, &result)); + return result; + } + + napi_value result; + NAPI_CALL(env, napi_create_int32(env, 0, &result)); + return result; +} + +static bool InnerUnregisterAnyPermissionsChanged(napi_env env, napi_ref callbackRef) +{ + HILOG_INFO("InnerUnregisterAnyPermissionsChanged"); + std::lock_guard lock(anyPermissionsCallbackMutex); + for (const auto &item : anyPermissionsCallback) { + napi_value callback = 0; + napi_value ref = 0; + napi_get_reference_value(env, item.first, &callback); + napi_get_reference_value(env, callbackRef, &ref); + bool result = false; + auto napiRet = napi_strict_equals(env, callback, ref, &result); + HILOG_INFO("status is = %{public}d.", napiRet); + if (result) { + HILOG_INFO("find value in anyPermissionsCallback"); + auto iBundleMgr = GetBundleMgr(); + if (!iBundleMgr) { + HILOG_ERROR("can not get iBundleMgr"); + return false; + } + auto result = iBundleMgr->UnregisterPermissionsChanged(item.second); + if (!result) { + HILOG_ERROR("UnregisterPermissionsChanged call error"); + return false; + } + anyPermissionsCallback.erase(item.first); + return true; + } + } + HILOG_INFO("InnerUnregisterAnyPermissionsChanged end"); + return false; +} + +static bool InnerUnregisterPermissionsChanged(napi_env env, const std::vector &uids, napi_ref callbackRef) +{ + HILOG_INFO("InnerUnregisterPermissionsChanged"); + std::lock_guard lock(permissionsCallbackMutex); + for (const auto &item : permissionsCallback) { + napi_value callback = 0; + napi_value ref = 0; + napi_get_reference_value(env, item.first.callback, &callback); + napi_get_reference_value(env, callbackRef, &ref); + bool result = false; + auto napiRet = napi_strict_equals(env, callback, ref, &result); + HILOG_INFO("status is = %{public}d.", napiRet); + if (result && uids == item.first.uids) { + HILOG_INFO("find value in permissionsCallback"); + auto iBundleMgr = GetBundleMgr(); + if (!iBundleMgr) { + HILOG_ERROR("can not get iBundleMgr"); + return false; + } + auto result = iBundleMgr->UnregisterPermissionsChanged(item.second); + if (!result) { + HILOG_ERROR("InnerUnregisterPermissionsChanged call error"); + return false; + } + HILOG_INFO("call UnregisterPermissionsChanged success = %{public}d", permissionsCallback.size()); + permissionsCallback.erase(item.first); + return true; + } + HILOG_INFO("can not find value in permissionsCallback"); + } + HILOG_INFO("InnerUnregisterPermissionsChanged end"); + return false; +} + +napi_value UnregisterPermissionsChanged(napi_env env, napi_callback_info info) +{ + size_t argc = ARGS_SIZE_THREE; + napi_value argv[ARGS_SIZE_THREE] = {nullptr}; + napi_value thisArg; + void *data = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, &data)); + HILOG_INFO("ARGCSIZE is =%{public}zu.", argc); + std::string permissionEvent; + ParseString(env, permissionEvent, argv[0]); + + if (permissionEvent == ANY_PERMISSION_CHANGE && argc == ARGS_SIZE_TWO) { + AsyncUnregisterPermissions *asyncCallbackInfo = new AsyncUnregisterPermissions{ + .env = env, + .asyncWork = nullptr, + }; + HILOG_INFO("UnregisterAnyPermissionsChanged asyncCallback."); + napi_valuetype valuetype = napi_undefined; + napi_typeof(env, argv[ARGS_SIZE_ONE], &valuetype); + NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); + NAPI_CALL(env, napi_create_reference(env, argv[ARGS_SIZE_ONE], 1, &asyncCallbackInfo->callback)); + napi_value resourceName; + napi_create_string_latin1(env, "NAPI_UnreegisterAnyPermissionsChanged", NAPI_AUTO_LENGTH, &resourceName); + napi_create_async_work( + env, + nullptr, + resourceName, + [](napi_env env, void *data) { + AsyncUnregisterPermissions *asyncCallbackInfo = (AsyncUnregisterPermissions *)data; + asyncCallbackInfo->ret = InnerUnregisterAnyPermissionsChanged(env, asyncCallbackInfo->callback); + }, + [](napi_env env, napi_status status, void *data) { + AsyncUnregisterPermissions *asyncCallbackInfo = (AsyncUnregisterPermissions *)data; + napi_value result[ARGS_SIZE_ONE] = {0}; + napi_value callback = 0; + napi_value undefined = 0; + napi_value callResult = 0; + result[PARAM0] = GetCallbackErrorValue(env, asyncCallbackInfo->ret ? CODE_SUCCESS : CODE_FAILED); + napi_get_reference_value(env, asyncCallbackInfo->callback, &callback); + napi_call_function(env, undefined, callback, ARGS_SIZE_ONE, &result[PARAM0], &callResult); + if (asyncCallbackInfo->callback != nullptr) { + napi_delete_reference(env, asyncCallbackInfo->callback); + } + napi_delete_async_work(env, asyncCallbackInfo->asyncWork); + delete asyncCallbackInfo; + }, + (void *)asyncCallbackInfo, + &asyncCallbackInfo->asyncWork); + NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork)); + + napi_value result; + NAPI_CALL(env, napi_create_int32(env, 1, &result)); + return result; + } else if (permissionEvent == PERMISSION_CHANGE && argc == ARGS_SIZE_THREE) { + std::vector uids; + ParseInt32Array(env, uids, argv[ARGS_SIZE_ONE]); + AsyncUnregisterPermissions *asyncCallbackInfo = + new AsyncUnregisterPermissions{.env = env, .asyncWork = nullptr, .uids = uids}; + HILOG_INFO("UnregisterPermissionsChanged asyncCallback."); + napi_valuetype valuetype = napi_undefined; + napi_typeof(env, argv[ARGS_SIZE_TWO], &valuetype); + NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); + NAPI_CALL(env, napi_create_reference(env, argv[ARGS_SIZE_TWO], 1, &asyncCallbackInfo->callback)); + napi_value resourceName; + napi_create_string_latin1(env, "NAPI_UnreegisterPermissionsChanged", NAPI_AUTO_LENGTH, &resourceName); + napi_create_async_work( + env, + nullptr, + resourceName, + [](napi_env env, void *data) { + AsyncUnregisterPermissions *asyncCallbackInfo = (AsyncUnregisterPermissions *)data; + asyncCallbackInfo->ret = + InnerUnregisterPermissionsChanged(env, asyncCallbackInfo->uids, asyncCallbackInfo->callback); + }, + [](napi_env env, napi_status status, void *data) { + AsyncUnregisterPermissions *asyncCallbackInfo = (AsyncUnregisterPermissions *)data; + napi_value result[ARGS_SIZE_ONE] = {0}; + napi_value callback = 0; + napi_value undefined = 0; + napi_value callResult = 0; + result[PARAM0] = GetCallbackErrorValue(env, asyncCallbackInfo->ret ? CODE_SUCCESS : CODE_FAILED); + napi_get_reference_value(env, asyncCallbackInfo->callback, &callback); + napi_call_function(env, undefined, callback, ARGS_SIZE_ONE, &result[PARAM0], &callResult); + if (asyncCallbackInfo->callback != nullptr) { + napi_delete_reference(env, asyncCallbackInfo->callback); + } + napi_delete_async_work(env, asyncCallbackInfo->asyncWork); + delete asyncCallbackInfo; + }, + (void *)asyncCallbackInfo, + &asyncCallbackInfo->asyncWork); + NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork)); + + napi_value result; + NAPI_CALL(env, napi_create_int32(env, 1, &result)); + return result; + } + napi_value result; + NAPI_CALL(env, napi_create_int32(env, 0, &result)); + return result; +} + +static int InnerCheckPermission(napi_env env, const std::string &bundleName, const std::string &permission) +{ + auto iBundleMgr = GetBundleMgr(); + if (!iBundleMgr) { + HILOG_ERROR("can not get iBundleMgr"); + return false; + }; + int ret = iBundleMgr->CheckPermission(bundleName, permission); + + return ret; +} + +/** + * Promise and async callback + */ +napi_value CheckPermission(napi_env env, napi_callback_info info) +{ + size_t argc = ARGS_SIZE_THREE; + napi_value argv[ARGS_SIZE_THREE] = {0}; + napi_value thisArg = nullptr; + void *data = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, &data)); + std::string bundleName; + ParseString(env, bundleName, argv[0]); + std::string permission; + ParseString(env, permission, argv[1]); + + AsyncPermissionCallbackInfo *asyncCallbackInfo = new AsyncPermissionCallbackInfo{ + .env = env, .asyncWork = nullptr, .deferred = nullptr, .bundleName = bundleName, .permission = permission}; + if (argc > (ARGS_SIZE_THREE - CALLBACK_SIZE)) { + HILOG_INFO("CheckPermission asyncCallback."); + napi_value resourceName; + napi_create_string_latin1(env, "CheckPermission", NAPI_AUTO_LENGTH, &resourceName); + + napi_valuetype valuetype = napi_undefined; + napi_typeof(env, argv[ARGS_SIZE_TWO], &valuetype); + NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); + NAPI_CALL(env, napi_create_reference(env, argv[ARGS_SIZE_TWO], 1, &asyncCallbackInfo->callback)); + + napi_create_async_work( + env, + nullptr, + resourceName, + [](napi_env env, void *data) { + AsyncPermissionCallbackInfo *asyncCallbackInfo = (AsyncPermissionCallbackInfo *)data; + asyncCallbackInfo->ret = + InnerCheckPermission(env, asyncCallbackInfo->bundleName, asyncCallbackInfo->permission); + }, + [](napi_env env, napi_status status, void *data) { + AsyncPermissionCallbackInfo *asyncCallbackInfo = (AsyncPermissionCallbackInfo *)data; + napi_value result[ARGS_SIZE_TWO] = {0}; + napi_value callback = 0; + napi_value undefined = 0; + napi_value callResult = 0; + napi_get_undefined(env, &undefined); + napi_create_int32(env, asyncCallbackInfo->ret, &result[PARAM1]); + result[PARAM0] = GetCallbackErrorValue(env, asyncCallbackInfo->ret == 0 ? CODE_SUCCESS : CODE_FAILED); + napi_get_reference_value(env, asyncCallbackInfo->callback, &callback); + napi_call_function(env, undefined, callback, ARGS_SIZE_TWO, &result[PARAM0], &callResult); + + if (asyncCallbackInfo->callback != nullptr) { + napi_delete_reference(env, asyncCallbackInfo->callback); + } + napi_delete_async_work(env, asyncCallbackInfo->asyncWork); + delete asyncCallbackInfo; + }, + (void *)asyncCallbackInfo, + &asyncCallbackInfo->asyncWork); + + NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork)); + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } + napi_value result; + NAPI_CALL(env, napi_create_int32(env, 1, &result)); + return result; + } else { + HILOG_INFO("BundleMgr::CheckPermission promise."); + napi_deferred deferred; + napi_value promise; + NAPI_CALL(env, napi_create_promise(env, &deferred, &promise)); + asyncCallbackInfo->deferred = deferred; + + napi_value resourceName; + napi_create_string_latin1(env, "CheckPermission", NAPI_AUTO_LENGTH, &resourceName); + napi_create_async_work( + env, + nullptr, + resourceName, + [](napi_env env, void *data) { + AsyncPermissionCallbackInfo *asyncCallbackInfo = (AsyncPermissionCallbackInfo *)data; + asyncCallbackInfo->ret = + InnerCheckPermission(env, asyncCallbackInfo->bundleName, asyncCallbackInfo->permission); + }, + [](napi_env env, napi_status status, void *data) { + HILOG_INFO("=================load================="); + AsyncPermissionCallbackInfo *asyncCallbackInfo = (AsyncPermissionCallbackInfo *)data; + napi_value result; + napi_create_int32(asyncCallbackInfo->env, asyncCallbackInfo->ret, &result); + napi_resolve_deferred(asyncCallbackInfo->env, asyncCallbackInfo->deferred, result); + napi_delete_async_work(env, asyncCallbackInfo->asyncWork); + delete asyncCallbackInfo; + }, + (void *)asyncCallbackInfo, + &asyncCallbackInfo->asyncWork); + napi_queue_async_work(env, asyncCallbackInfo->asyncWork); + + napi_value ret = nullptr; + NAPI_CALL(env, napi_get_null(env, &ret)); + if (ret == nullptr) { + if (asyncCallbackInfo != nullptr) { + delete asyncCallbackInfo; + asyncCallbackInfo = nullptr; + } + } return promise; } } @@ -2734,10 +3697,10 @@ void CreateAbilityTypeObject(napi_env env, napi_value value) void CreateAbilitySubTypeObject(napi_env env, napi_value value) { napi_value nUnspecified; - NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, NAPI_RETURN_ZERO, &nUnspecified)); + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, 0, &nUnspecified)); NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "UNSPECIFIED", nUnspecified)); napi_value nCa; - NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, NAPI_RETURN_ONE, &nCa)); + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, 1, &nCa)); NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "CA", nCa)); } @@ -2776,15 +3739,15 @@ void CreateLaunchModeObject(napi_env env, napi_value value) void CreateModuleUpdateFlagObject(napi_env env, napi_value value) { napi_value nFlagModuleUpgradeCheck; - NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, NAPI_RETURN_ZERO, &nFlagModuleUpgradeCheck)); + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, 0, &nFlagModuleUpgradeCheck)); NAPI_CALL_RETURN_VOID( env, napi_set_named_property(env, value, "FLAG_MODULE_UPGRADE_CHECK", nFlagModuleUpgradeCheck)); napi_value nFlagModuleUpgradeInstall; - NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, NAPI_RETURN_ONE, &nFlagModuleUpgradeInstall)); + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, 1, &nFlagModuleUpgradeInstall)); NAPI_CALL_RETURN_VOID( env, napi_set_named_property(env, value, "FLAG_MODULE_UPGRADE_INSTALL", nFlagModuleUpgradeInstall)); napi_value nFlagModuleUpgradeinstallWithConfigWindows; - NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, NAPI_RETURN_TWO, &nFlagModuleUpgradeinstallWithConfigWindows)); + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, 2, &nFlagModuleUpgradeinstallWithConfigWindows)); NAPI_CALL_RETURN_VOID(env, napi_set_named_property( env, value, "FLAG_MODULE_UPGRADE_INSTALL_WITH_CONFIG_WINDOWS", nFlagModuleUpgradeinstallWithConfigWindows)); @@ -2793,51 +3756,51 @@ void CreateModuleUpdateFlagObject(napi_env env, napi_value value) void CreateFormTypeObject(napi_env env, napi_value value) { napi_value nJava; - NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, NAPI_RETURN_ZERO, &nJava)); + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, 0, &nJava)); NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "JAVA", nJava)); napi_value nJs; - NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, NAPI_RETURN_ONE, &nJs)); + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, 1, &nJs)); NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "JS", nJs)); } void CreateColorModeObject(napi_env env, napi_value value) { napi_value nAutoMode; - NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, NAPI_RETURN_FAILED, &nAutoMode)); + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, -1, &nAutoMode)); NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "AUTO_MODE", nAutoMode)); napi_value nDarkMode; - NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, NAPI_RETURN_ZERO, &nDarkMode)); + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, 0, &nDarkMode)); NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "DARK_MODE", nDarkMode)); napi_value nLightMode; - NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, NAPI_RETURN_ONE, &nLightMode)); + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, 1, &nLightMode)); NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "LIGHT_MODE", nLightMode)); } void CreateGrantStatusObject(napi_env env, napi_value value) { napi_value nPermissionDenied; - NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, NAPI_RETURN_FAILED, &nPermissionDenied)); + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, -1, &nPermissionDenied)); NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "PERMISSION_DENIED", nPermissionDenied)); napi_value nPermissionGranted; - NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, NAPI_RETURN_ZERO, &nPermissionGranted)); + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, 0, &nPermissionGranted)); NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "PERMISSION_GRANTED", nPermissionGranted)); } void CreateModuleRemoveFlagObject(napi_env env, napi_value value) { napi_value nFlagModuleNotUsedByForm; - NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, NAPI_RETURN_ZERO, &nFlagModuleNotUsedByForm)); + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, 0, &nFlagModuleNotUsedByForm)); NAPI_CALL_RETURN_VOID( env, napi_set_named_property(env, value, "FLAG_MODULE_NOT_USED_BY_FORM", nFlagModuleNotUsedByForm)); napi_value nFlagModuleUsedByForm; - NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, NAPI_RETURN_ONE, &nFlagModuleUsedByForm)); + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, 1, &nFlagModuleUsedByForm)); NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "FLAG_MODULE_USED_BY_FORM", nFlagModuleUsedByForm)); napi_value nFlagModuleNotUsedByShortcut; - NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, NAPI_RETURN_TWO, &nFlagModuleNotUsedByShortcut)); + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, 2, &nFlagModuleNotUsedByShortcut)); NAPI_CALL_RETURN_VOID( env, napi_set_named_property(env, value, "FLAG_MODULE_NOT_USED_BY_SHORTCUT", nFlagModuleNotUsedByShortcut)); napi_value nFlagModuleUsedByShortcut; - NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, NAPI_RETURN_THREE, &nFlagModuleUsedByShortcut)); + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, 3, &nFlagModuleUsedByShortcut)); NAPI_CALL_RETURN_VOID( env, napi_set_named_property(env, value, "FLAG_MODULE_USED_BY_SHORTCUT", nFlagModuleUsedByShortcut)); } @@ -2845,13 +3808,13 @@ void CreateModuleRemoveFlagObject(napi_env env, napi_value value) void CreateSignatureCompareResultObject(napi_env env, napi_value value) { napi_value nSignatureMatched; - NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, NAPI_RETURN_ZERO, &nSignatureMatched)); + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, 0, &nSignatureMatched)); NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "SIGNATURE_MATCHED", nSignatureMatched)); napi_value nSignatureNotMatched; - NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, NAPI_RETURN_ONE, &nSignatureNotMatched)); + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, 1, &nSignatureNotMatched)); NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "SIGNATURE_NOT_MATCHED", nSignatureNotMatched)); napi_value nSignatureUnknownBundle; - NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, NAPI_RETURN_TWO, &nSignatureUnknownBundle)); + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, 2, &nSignatureUnknownBundle)); NAPI_CALL_RETURN_VOID( env, napi_set_named_property(env, value, "SIGNATURE_UNKNOWN_BUNDLE", nSignatureUnknownBundle)); } @@ -2859,15 +3822,15 @@ void CreateSignatureCompareResultObject(napi_env env, napi_value value) void CreateShortcutExistenceObject(napi_env env, napi_value value) { napi_value nShortcutExistenceExists; - NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, NAPI_RETURN_ZERO, &nShortcutExistenceExists)); + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, 0, &nShortcutExistenceExists)); NAPI_CALL_RETURN_VOID( env, napi_set_named_property(env, value, "SHORTCUT_EXISTENCE_EXISTS", nShortcutExistenceExists)); napi_value nShortcutExistenceNotExists; - NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, NAPI_RETURN_ONE, &nShortcutExistenceNotExists)); + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, 1, &nShortcutExistenceNotExists)); NAPI_CALL_RETURN_VOID( env, napi_set_named_property(env, value, "SHORTCUT_EXISTENCE_NOT_EXISTS", nShortcutExistenceNotExists)); napi_value nShortcutExistenceUnknow; - NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, NAPI_RETURN_TWO, &nShortcutExistenceUnknow)); + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, 2, &nShortcutExistenceUnknow)); NAPI_CALL_RETURN_VOID( env, napi_set_named_property(env, value, "SHORTCUT_EXISTENCE_UNKNOW", nShortcutExistenceUnknow)); } @@ -2875,7 +3838,7 @@ void CreateShortcutExistenceObject(napi_env env, napi_value value) void CreateQueryShortCutFlagObject(napi_env env, napi_value value) { napi_value nQueryShortCutHome; - NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, NAPI_RETURN_ZERO, &nQueryShortCutHome)); + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, 0, &nQueryShortCutHome)); NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, value, "QUERY_SHORTCUT_HOME", nQueryShortCutHome)); } diff --git a/kits/appkit/napi/bundlemgr/bundle_mgr.h b/kits/appkit/napi/bundlemgr/bundle_mgr.h index e3625bcd71..e3a80b53da 100644 --- a/kits/appkit/napi/bundlemgr/bundle_mgr.h +++ b/kits/appkit/napi/bundlemgr/bundle_mgr.h @@ -73,6 +73,16 @@ struct AsyncPermissionDefCallbackInfo { bool ret = false; }; +struct AsyncPermissionCallbackInfo { + napi_env env; + napi_async_work asyncWork; + napi_deferred deferred; + napi_ref callback = 0; + std::string bundleName; + std::string permission; + int ret = -1; +}; + struct AsyncBundleInfosCallbackInfo { napi_env env; napi_async_work asyncWork; @@ -157,6 +167,37 @@ struct AsyncShortcutInfosCallbackInfo { bool ret = false; }; +struct AsyncModuleUsageRecordsCallbackInfo { + napi_env env; + napi_async_work asyncWork; + napi_deferred deferred; + napi_ref callback = 0; + int32_t number; + std::vector moduleUsageRecords; + bool ret = false; +}; + +struct AsyncRegisterAllPermissions { + napi_env env; + napi_async_work asyncWork; + napi_ref callback = 0; +}; + +struct AsyncRegisterPermissions { + napi_env env; + napi_async_work asyncWork; + napi_ref callback = 0; + std::vector uids; +}; + +struct AsyncUnregisterPermissions { + napi_env env; + napi_async_work asyncWork; + napi_ref callback = 0; + std::vector uids; + bool ret = false; +}; + extern napi_value g_classBundleInstaller; napi_value GetApplicationInfos(napi_env env, napi_callback_info); @@ -174,6 +215,10 @@ napi_value GetAllFormsInfo(napi_env env, napi_callback_info info); napi_value GetFormsInfoByApp(napi_env env, napi_callback_info info); napi_value GetFormsInfoByModule(napi_env env, napi_callback_info info); napi_value GetShortcutInfos(napi_env env, napi_callback_info info); +napi_value GetModuleUsageRecords(napi_env env, napi_callback_info info); +napi_value RegisterAllPermissionsChanged(napi_env env, napi_callback_info info); +napi_value UnregisterPermissionsChanged(napi_env env, napi_callback_info info); +napi_value CheckPermission(napi_env env, napi_callback_info info); void CreateAbilityTypeObject(napi_env env, napi_value value); void CreateAbilitySubTypeObject(napi_env env, napi_value value); void CreateDisplayOrientationObject(napi_env env, napi_value value); diff --git a/kits/appkit/napi/bundlemgr/native_module.cpp b/kits/appkit/napi/bundlemgr/native_module.cpp index 47abb8f2e7..0fbea0b8bf 100644 --- a/kits/appkit/napi/bundlemgr/native_module.cpp +++ b/kits/appkit/napi/bundlemgr/native_module.cpp @@ -94,6 +94,10 @@ static napi_value Init(napi_env env, napi_value exports) DECLARE_NAPI_FUNCTION("getFormsInfo", GetFormsInfoByApp), DECLARE_NAPI_FUNCTION("getAllFormsInfo", GetAllFormsInfo), DECLARE_NAPI_FUNCTION("getShortcutInfos", GetShortcutInfos), + DECLARE_NAPI_FUNCTION("getModuleUsageRecords", GetModuleUsageRecords), + DECLARE_NAPI_FUNCTION("on", RegisterAllPermissionsChanged), + DECLARE_NAPI_FUNCTION("off", UnregisterPermissionsChanged), + DECLARE_NAPI_FUNCTION("checkPermission", CheckPermission), DECLARE_NAPI_PROPERTY("AbilityType", nAbilityType), DECLARE_NAPI_PROPERTY("AbilitySubType", nAbilitySubType), DECLARE_NAPI_PROPERTY("DisplayOrientation", nDisplayOrientation), diff --git a/kits/appkit/napi/bundlemgr/permission_callback.cpp b/kits/appkit/napi/bundlemgr/permission_callback.cpp new file mode 100644 index 0000000000..b4aa91d5d3 --- /dev/null +++ b/kits/appkit/napi/bundlemgr/permission_callback.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2021 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 "permission_callback.h" +#include "hilog_wrapper.h" + +PermissionCallback::PermissionCallback(napi_env env, napi_ref callback) : env_(env), callback_(callback) +{} + +PermissionCallback::~PermissionCallback() +{ + if (callback_ != nullptr) { + napi_delete_reference(env_, callback_); + } +} + +void PermissionCallback::OnChanged(const int32_t uid) +{ + uv_loop_s *loop = nullptr; +#if NAPI_VERSION >= 2 + napi_get_uv_event_loop(env_, &loop); +#endif // NAPI_VERSION >= 2 + + uv_work_t *work = new uv_work_t; + CallbackInfo *callbackInfo = new (std::nothrow) CallbackInfo{ + .env = env_, + .callback = callback_, + .uid = uid, + }; + + work->data = (void *)callbackInfo; + + uv_queue_work( + loop, + work, + [](uv_work_t *work) {}, + [](uv_work_t *work, int status) { + HILOG_INFO("CallOnPermissonChanged, uv_queue_work"); + // JS Thread + CallbackInfo *event = (CallbackInfo *)work->data; + napi_value result[2] = {0}; + + napi_value callResult = nullptr; + napi_value eCode = nullptr; + NAPI_CALL_RETURN_VOID(event->env, napi_create_int32(event->env, 0, &eCode)); + napi_create_object(event->env, &callResult); + napi_set_named_property(event->env, callResult, "code", eCode); + result[0] = callResult; + // create uid + NAPI_CALL_RETURN_VOID(event->env, napi_create_int32(event->env, event->uid, &result[1])); + + napi_value callback = 0; + napi_value undefined = 0; + napi_get_undefined(event->env, &undefined); + napi_value callbackResult = 0; + napi_get_reference_value(event->env, event->callback, &callback); + napi_call_function(event->env, undefined, callback, 2, &result[0], &callbackResult); + delete event; + delete work; + }); + + HILOG_INFO("OnChanged, end"); +} \ No newline at end of file diff --git a/kits/appkit/napi/bundlemgr/permission_callback.h b/kits/appkit/napi/bundlemgr/permission_callback.h new file mode 100644 index 0000000000..bcda69feb6 --- /dev/null +++ b/kits/appkit/napi/bundlemgr/permission_callback.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2021 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 PERMISSION_CALLBACK_H +#define PERMISSION_CALLBACK_H + +#include +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +#include "nocopyable.h" +#include "on_permission_changed_callback_host.h" + +struct CallbackInfo { + napi_env env; + napi_ref callback = 0; + int32_t uid; +}; + +class PermissionCallback : public OHOS::AppExecFwk::OnPermissionChangedCallbackHost { +public: + PermissionCallback(napi_env env, napi_ref callback); + virtual ~PermissionCallback(); + virtual void OnChanged(const int32_t uid) override; + + +private: + napi_env env_; + napi_ref callback_; + DISALLOW_COPY_AND_MOVE(PermissionCallback); +}; + +#endif // PERMISSION_CALLBACK_H \ No newline at end of file diff --git a/kits/appkit/native/app/include/ability_start_setting.h b/kits/appkit/native/app/include/ability_start_setting.h deleted file mode 100644 index f6b466636b..0000000000 --- a/kits/appkit/native/app/include/ability_start_setting.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2021 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 ABILITY_START_SETTING_H -#define ABILITY_START_SETTING_H - -#include -#include -#include -#include -#include "parcel.h" - -namespace OHOS { -namespace AppExecFwk { - -class AbilityStartSetting final : public Parcelable, public std::enable_shared_from_this { -public: - static const std::string BOUNDS_KEY; - static const std::string WINDOW_DISPLAY_ID_KEY; - static const std::string WINDOW_MODE_KEY; - - /** - * @brief Construct copy function. - * @param other indicates instance of abilitystartsetting object - * @return none. - */ - AbilityStartSetting(const AbilityStartSetting &other); - /** - * @brief Overload assignment operation. - * @param other indicates instance of abilitystartsetting object. - * @return Returns current instance of abilitystartsetting object. - */ - AbilityStartSetting &operator=(const AbilityStartSetting &other); - - virtual ~AbilityStartSetting() = default; - - /** - * @brief Obtains the names of all the attributes that have been added to this AbilityStartSetting object. - * - * @return Returns the set of attribute names included in this AbilityStartSetting object. - */ - std::set GetPropertiesKey(); - - /** - * @brief Obtains the names of all the attributes that have been added to this AbilityStartSetting object. - * - * @return Returns the set of attribute names included in this AbilityStartSetting object. - */ - static std::shared_ptr GetEmptySetting(); - - /** - * @brief Checks whether this AbilityStartSetting object is empty. - * - * @return Returns true if this AbilityStartSetting object is empty and animatorOption is null; returns false - * otherwise. - */ - bool IsEmpty(); - /** - * @brief Sets the names of all the attributes of the AbilityStartSetting object. - * - * @param key Indicates the name of the key. - * @param value The window display mode of the values. - */ - void AddProperty(const std::string &key, const std::string &value); - - /** - * @brief Gets the name of the attributes of the AbilityStartSetting object. - * - * @param key Indicates the name of the key. - * @return Returns value Indicates the value of the attributes of the AbilityStartSetting object - */ - std::string GetProperty(const std::string &key); - - /* - * @brief Write the data of AbilityStartSetting to the file stream - * @param parcel indicates write the data of AbilityStartSetting to the file stream through parcel - * @return bool - */ - bool Marshalling(Parcel &parcel) const; - - /** - * @brief Reading file stream through parcel to generate AbilityStartSetting instance - * @param parcel indicates reading file stream through parcel to generate AbilityStartSetting instance - * @return AbilityStartSetting shared_ptr - */ - static AbilityStartSetting *Unmarshalling(Parcel &parcel); - -protected: - AbilityStartSetting() = default; - friend std::shared_ptr AbilityStartSettingCreator(); - -private: - std::map abilityStarKey_; -}; -} // namespace AppExecFwk -} // namespace OHOS -#endif // ABILITY_START_SETTING_H diff --git a/kits/appkit/native/app/include/context.h b/kits/appkit/native/app/include/context.h index f08b28c2ec..4c1726936b 100755 --- a/kits/appkit/native/app/include/context.h +++ b/kits/appkit/native/app/include/context.h @@ -23,7 +23,6 @@ #include "ability_info.h" #include "process_info.h" #include "resource_manager.h" -#include "ability_start_setting.h" #include "dummy_hap_module_info.h" #include "hap_module_info.h" #include "task/task_priority.h" @@ -33,7 +32,7 @@ namespace OHOS { namespace AppExecFwk { using Want = OHOS::AAFwk::Want; - +using AbilityStartSetting = AAFwk::AbilityStartSetting; // Request permissions for user #define OHOS_REQUEST_PERMISSION_BUNDLENAME "com.ohos.systemui" #define OHOS_REQUEST_PERMISSION_ABILITY_NAME "com.ohos.systemui.systemdialog.MainAbility" diff --git a/kits/appkit/native/app/src/ability_start_setting.cpp b/kits/appkit/native/app/src/ability_start_setting.cpp deleted file mode 100644 index 9961e33785..0000000000 --- a/kits/appkit/native/app/src/ability_start_setting.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (c) 2021 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 "ability_start_setting.h" -#include -#include "app_log_wrapper.h" -#include "string_ex.h" - -using namespace OHOS; - -namespace OHOS { -namespace AppExecFwk { - -const std::string AbilityStartSetting::BOUNDS_KEY = "bounds"; -const std::string AbilityStartSetting::WINDOW_DISPLAY_ID_KEY = "windowId"; -const std::string AbilityStartSetting::WINDOW_MODE_KEY = "windowMode"; - -/** - * @brief Construct copy function. - * @param other indicates instance of abilitystartsetting object - * @return none. - */ -AbilityStartSetting::AbilityStartSetting(const AbilityStartSetting &other) -{ - abilityStarKey_.clear(); - abilityStarKey_ = other.abilityStarKey_; -} -/** - * @brief Overload assignment operation. - * @param other indicates instance of abilitystartsetting object. - * @return Returns current instance of abilitystartsetting object. - */ -AbilityStartSetting &AbilityStartSetting::operator=(const AbilityStartSetting &other) -{ - if (this != &other) { - abilityStarKey_.clear(); - abilityStarKey_ = other.abilityStarKey_; - } - return *this; -} -/** - * @brief Inner function to create AbilityStartSetting - * - * @return Returns the shared_ptr of AbilityStartSetting object. - */ -std::shared_ptr AbilityStartSettingCreator() -{ - std::shared_ptr abilityStartSetting{new (std::nothrow) AbilityStartSetting()}; - return abilityStartSetting; -} - -/** - * @brief Obtains an empty AbilityStartSetting object. - * - * @return Returns the btains an empty AbilityStartSetting object. - */ -std::shared_ptr AbilityStartSetting::GetEmptySetting() -{ - return AbilityStartSettingCreator(); -} - -/** - * @brief Obtains the names of all the attributes that have been added to this AbilityStartSetting object. - * - * @return Returns the set of attribute names included in this AbilityStartSetting object. - */ -std::set AbilityStartSetting::GetPropertiesKey() -{ - std::set abilityStartSet; - abilityStartSet.clear(); - - for (auto it : abilityStarKey_) { - abilityStartSet.emplace(it.first); - } - return abilityStartSet; -} - -/** - * @brief Checks whether this AbilityStartSetting object is empty. - * - * @return Returns true if this AbilityStartSetting object is empty and animatorOption is null; returns false otherwise. - */ -bool AbilityStartSetting::IsEmpty() -{ - return (abilityStarKey_.size() == 0); -} - -/** - * @brief Sets the names of all the attributes of the AbilityStartSetting object. - * - * @param key Indicates the name of the key. - * @param value The window display mode of the values. - */ -void AbilityStartSetting::AddProperty(const std::string &key, const std::string &value) -{ - abilityStarKey_[key] = value; -} - -/** - * @brief Gets the name of the attributes of the AbilityStartSetting object. - * - * @param key Indicates the name of the key. - * @return Returns value Indicates the value of the attributes of the AbilityStartSetting object - */ -std::string AbilityStartSetting::GetProperty(const std::string &key) -{ - auto it = abilityStarKey_.find(key); - if (it == abilityStarKey_.end()) { - return std::string(); - } - return abilityStarKey_[key]; -} - -/** - * @brief Write the data of AbilityStartSetting to the file stream - * @param parcel indicates write the data of AbilityStartSetting to the file stream through parcel - * @return bool - */ -bool AbilityStartSetting::Marshalling(Parcel &parcel) const -{ - size_t size = abilityStarKey_.size(); - - // 1. Number of key value pairs written - parcel.WriteUint32((uint32_t)size); - - std::map::const_iterator it; - - // 2. Write the key and value strings - for (auto pair : abilityStarKey_) { - // 1.key - parcel.WriteString16(Str8ToStr16(pair.first)); - // 2.data content - parcel.WriteString16(Str8ToStr16(pair.second)); - } - - return true; -} - -/** - * @brief Reading file stream through parcel to generate AbilityStartSetting instance - * @param parcel indicates reading file stream through parcel to generate AbilityStartSetting instance - * @return AbilityStartSetting shared_ptr - */ -AbilityStartSetting *AbilityStartSetting::Unmarshalling(Parcel &parcel) -{ - AbilityStartSetting *abilityStartSetting = new (std::nothrow) AbilityStartSetting(); - if (abilityStartSetting == nullptr) { - return nullptr; - } - // 1. Number of key value pairs read - uint32_t size = 0; - parcel.ReadUint32(size); - std::u16string keyReadString16; - std::u16string dataReadString16; - for (size_t i = 0; (i < size) && abilityStartSetting; i++) { - // 1.key - keyReadString16 = parcel.ReadString16(); - // 2.data content - dataReadString16 = parcel.ReadString16(); - abilityStartSetting->abilityStarKey_[Str16ToStr8(keyReadString16)] = Str16ToStr8(dataReadString16); - keyReadString16.clear(); - dataReadString16.clear(); - } - - return abilityStartSetting; -} - -} // namespace AppExecFwk -} // namespace OHOS \ No newline at end of file diff --git a/kits/appkit/native/app/src/application_context.cpp b/kits/appkit/native/app/src/application_context.cpp index bc7797af42..5ae36a1525 100755 --- a/kits/appkit/native/app/src/application_context.cpp +++ b/kits/appkit/native/app/src/application_context.cpp @@ -199,12 +199,15 @@ int ApplicationContext::GetMissionId() std::shared_ptr ApplicationContext::CreateParallelTaskDispatcher( const std::string &name, const TaskPriority &priority) { + APP_LOGI("ApplicationContext::CreateParallelTaskDispatcher begin"); if (taskDispatcherContext_ == nullptr) { APP_LOGE("ApplicationContext::CreateParallelTaskDispatcher taskDispatcherContext_ is nullptr"); return nullptr; } - return taskDispatcherContext_->CreateParallelDispatcher(name, priority); + std::shared_ptr task = taskDispatcherContext_->CreateParallelDispatcher(name, priority); + APP_LOGI("ApplicationContext::CreateParallelTaskDispatcher end"); + return task; } /** @@ -218,12 +221,15 @@ std::shared_ptr ApplicationContext::CreateParallelTaskDispatcher std::shared_ptr ApplicationContext::CreateSerialTaskDispatcher( const std::string &name, const TaskPriority &priority) { + APP_LOGI("ApplicationContext::CreateSerialTaskDispatcher begin"); if (taskDispatcherContext_ == nullptr) { APP_LOGE("ApplicationContext::CreateSerialTaskDispatcher taskDispatcherContext_ is nullptr"); return nullptr; } - return taskDispatcherContext_->CreateSerialDispatcher(name, priority); + std::shared_ptr task = taskDispatcherContext_->CreateSerialDispatcher(name, priority); + APP_LOGI("ApplicationContext::CreateSerialTaskDispatcher end"); + return task; } /** @@ -235,12 +241,15 @@ std::shared_ptr ApplicationContext::CreateSerialTaskDispatcher( */ std::shared_ptr ApplicationContext::GetGlobalTaskDispatcher(const TaskPriority &priority) { + APP_LOGI("ApplicationContext::GetGlobalTaskDispatcher begin"); if (taskDispatcherContext_ == nullptr) { APP_LOGE("ApplicationContext::GetGlobalTaskDispatcher taskDispatcherContext_ is nullptr"); return nullptr; } - return taskDispatcherContext_->GetGlobalTaskDispatcher(priority); + std::shared_ptr task = taskDispatcherContext_->GetGlobalTaskDispatcher(priority); + APP_LOGI("ApplicationContext::GetGlobalTaskDispatcher end"); + return task; } } // namespace AppExecFwk diff --git a/kits/appkit/native/app/src/context_deal.cpp b/kits/appkit/native/app/src/context_deal.cpp index b84ff9650b..12830529e8 100755 --- a/kits/appkit/native/app/src/context_deal.cpp +++ b/kits/appkit/native/app/src/context_deal.cpp @@ -53,10 +53,12 @@ std::shared_ptr ContextDeal::GetProcessInfo() const */ void ContextDeal::SetProcessInfo(const std::shared_ptr &info) { + APP_LOGI("ContextDeal::SetProcessInfo begin"); if (info == nullptr) { APP_LOGE("ContextDeal::SetProcessInfo failed, info is empty"); return; } + APP_LOGI("ContextDeal::SetProcessInfo end"); processInfo_ = info; } @@ -78,11 +80,13 @@ std::shared_ptr ContextDeal::GetApplicationInfo() const */ void ContextDeal::SetApplicationInfo(const std::shared_ptr &info) { + APP_LOGI("ContextDeal::SetApplicationInfo begin"); if (info == nullptr) { APP_LOGE("ContextDeal::SetApplicationInfo failed, info is empty"); return; } applicationInfo_ = info; + APP_LOGI("ContextDeal::SetApplicationInfo end"); } /** @@ -102,11 +106,13 @@ std::shared_ptr ContextDeal::GetApplicationContext() const */ void ContextDeal::SetApplicationContext(const std::shared_ptr &context) { + APP_LOGI("ContextDeal::SetApplicationContext begin"); if (context == nullptr) { APP_LOGE("ContextDeal::SetApplicationContext failed, context is empty"); return; } appContext_ = context; + APP_LOGI("ContextDeal::SetApplicationContext end"); } /** @@ -148,11 +154,13 @@ const std::shared_ptr ContextDeal::GetAbilityInfo() */ void ContextDeal::SetAbilityInfo(const std::shared_ptr &info) { + APP_LOGI("ContextDeal::SetAbilityInfo begin"); if (info == nullptr) { APP_LOGE("ContextDeal::SetAbilityInfo failed, info is empty"); return; } abilityInfo_ = info; + APP_LOGI("ContextDeal::SetAbilityInfo end"); } /** @@ -172,11 +180,13 @@ std::shared_ptr ContextDeal::GetContext() */ void ContextDeal::SetContext(const std::shared_ptr &context) { + APP_LOGI("ContextDeal::SetContext begin"); if (context == nullptr) { APP_LOGE("ContextDeal::SetContext failed, context is empty"); return; } abilityContext_ = context; + APP_LOGI("ContextDeal::SetContext end"); } /** @@ -187,15 +197,18 @@ void ContextDeal::SetContext(const std::shared_ptr &context) */ sptr ContextDeal::GetBundleManager() const { + APP_LOGI("ContextDeal::GetBundleManager begin"); auto bundleObj = OHOS::DelayedSingleton::GetInstance()->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID); if (bundleObj == nullptr) { APP_LOGE("failed to get bundle manager service"); return nullptr; } - - APP_LOGI("get bundle manager proxy success."); - return iface_cast(bundleObj); + APP_LOGI("ContextDeal::GetBundleManager before iface_cast"); + sptr bms = iface_cast(bundleObj); + APP_LOGI("ContextDeal::GetBundleManager after iface_cast"); + APP_LOGI("ContextDeal::GetBundleManager end"); + return bms; } /** @@ -215,11 +228,13 @@ std::shared_ptr ContextDeal::GetResourceManag */ void ContextDeal::SetProfile(const std::shared_ptr &profile) { + APP_LOGI("ContextDeal::SetProfile begin"); if (profile == nullptr) { APP_LOGE("ContextDeal::SetProfile failed, profile is nullptr"); return; } profile_ = profile; + APP_LOGI("ContextDeal::SetProfile end"); } /** @@ -241,8 +256,11 @@ std::shared_ptr ContextDeal::GetProfile() const */ bool ContextDeal::DeleteFile(const std::string &fileName) { + APP_LOGI("ContextDeal::DeleteFile begin"); std::string path = GetDataDir() + CONTEXT_DEAL_FILE_SEPARATOR + fileName; - return OHOS::RemoveFile(path); + bool ret = OHOS::RemoveFile(path); + APP_LOGI("ContextDeal::DeleteFile end"); + return ret; } /** @@ -320,6 +338,7 @@ std::string ContextDeal::GetDataDir() */ std::string ContextDeal::GetDir(const std::string &name, int mode) { + APP_LOGI("ContextDeal::GetDir begin"); if (applicationInfo_ == nullptr) { APP_LOGE("ContextDeal::GetDir failed, applicationInfo_ == nullptr"); return ""; @@ -330,6 +349,7 @@ std::string ContextDeal::GetDir(const std::string &name, int mode) OHOS::ForceCreateDirectory(dir); OHOS::ChangeModeDirectory(dir, mode); } + APP_LOGI("ContextDeal::GetDir end"); return dir; } @@ -380,12 +400,14 @@ std::string ContextDeal::GetFilesDir() */ std::string ContextDeal::GetNoBackupFilesDir() { + APP_LOGI("ContextDeal::GetNoBackupFilesDir begin"); std::string dir = applicationInfo_->dataDir + CONTEXT_DEAL_NO_BACKUP_Files; if (!OHOS::FileExists(dir)) { APP_LOGI("ContextDeal::GetDir GetNoBackupFilesDir is not exits"); OHOS::ForceCreateDirectory(dir); OHOS::ChangeModeDirectory(dir, MODE); } + APP_LOGI("ContextDeal::GetNoBackupFilesDir end"); return dir; } @@ -476,14 +498,17 @@ void ContextDeal::UnauthUriPermission(const std::string &permission, const Uri & */ sptr ContextDeal::GetAbilityManager() { + APP_LOGI("ContextDeal::GetAbilityManager begin"); auto remoteObject = OHOS::DelayedSingleton::GetInstance()->GetSystemAbility(ABILITY_MGR_SERVICE_ID); if (remoteObject == nullptr) { APP_LOGE("failed to get ability manager service"); return nullptr; } - - APP_LOGI("get bundle ability proxy success."); - return iface_cast(remoteObject); + APP_LOGI("ContextDeal::SetPattern before iface_cast"); + sptr ams = iface_cast(remoteObject); + APP_LOGI("ContextDeal::SetPattern after iface_cast"); + APP_LOGI("ContextDeal::GetAbilityManager end"); + return ams; } /** @@ -496,13 +521,15 @@ sptr ContextDeal::GetAbilityManager() */ std::string ContextDeal::GetAppType() { + APP_LOGI("ContextDeal::GetAppType begin"); sptr ptr = GetBundleManager(); if (ptr == nullptr) { APP_LOGE("GetAppType failed to get bundle manager service"); return ""; } - - return ptr->GetAppType(applicationInfo_->bundleName); + std::string retString = ptr->GetAppType(applicationInfo_->bundleName); + APP_LOGI("ContextDeal::GetAppType end"); + return retString; } /** @@ -577,18 +604,21 @@ std::string ContextDeal::GetDistributedDir() */ void ContextDeal::SetPattern(int patternId) { + APP_LOGI("ContextDeal::SetPattern begin"); if (resourceManager_ != nullptr) { if (!pattern_.empty()) { pattern_.clear(); } - + APP_LOGI("ContextDeal::SetPattern before resourceManager_->GetPatternById"); OHOS::Global::Resource::RState errval = resourceManager_->GetPatternById(patternId, pattern_); + APP_LOGI("ContextDeal::SetPattern after resourceManager_->GetPatternById"); if (errval != OHOS::Global::Resource::RState::SUCCESS) { APP_LOGE("ContextDeal::SetPattern GetPatternById(patternId:%d) retval is %u", patternId, errval); } } else { APP_LOGE("ContextDeal::SetPattern resourceManager_ is nullptr"); } + APP_LOGI("ContextDeal::SetPattern end"); } /** @@ -738,19 +768,23 @@ void ContextDeal::SerUriString(const std::string &uri) */ std::string ContextDeal::GetString(int resId) { + APP_LOGI("ContextDeal::GetString begin"); if (resourceManager_ == nullptr) { APP_LOGE("ContextDeal::GetString resourceManager_ is nullptr"); return ""; } std::string ret; + APP_LOGI("ContextDeal::GetString before resourceManager_->GetStringById"); OHOS::Global::Resource::RState errval = resourceManager_->GetStringById(resId, ret); + APP_LOGI("ContextDeal::GetString after resourceManager_->GetStringById"); if (errval == OHOS::Global::Resource::RState::SUCCESS) { return ret; } else { APP_LOGE("ContextDeal::GetString GetStringById(resId:%d) retval is %u", resId, errval); return ""; } + APP_LOGI("ContextDeal::GetString end"); } /** @@ -762,19 +796,23 @@ std::string ContextDeal::GetString(int resId) */ std::vector ContextDeal::GetStringArray(int resId) { + APP_LOGI("ContextDeal::GetStringArray begin"); if (resourceManager_ == nullptr) { APP_LOGE("ContextDeal::GetStringArray resourceManager_ is nullptr"); return std::vector(); } std::vector retv; + APP_LOGI("ContextDeal::GetString before resourceManager_->GetStringArrayById"); OHOS::Global::Resource::RState errval = resourceManager_->GetStringArrayById(resId, retv); + APP_LOGI("ContextDeal::GetString after resourceManager_->GetStringArrayById"); if (errval == OHOS::Global::Resource::RState::SUCCESS) { return retv; } else { APP_LOGE("ContextDeal::GetStringArray GetStringArrayById(resId:%d) retval is %u", resId, errval); return std::vector(); } + APP_LOGI("ContextDeal::GetStringArray end"); } /** @@ -786,19 +824,23 @@ std::vector ContextDeal::GetStringArray(int resId) */ std::vector ContextDeal::GetIntArray(int resId) { + APP_LOGI("ContextDeal::GetIntArray begin"); if (resourceManager_ == nullptr) { APP_LOGE("ContextDeal::GetIntArray resourceManager_ is nullptr"); return std::vector(); } std::vector retv; + APP_LOGI("ContextDeal::GetString before resourceManager_->GetIntArrayById"); OHOS::Global::Resource::RState errval = resourceManager_->GetIntArrayById(resId, retv); + APP_LOGI("ContextDeal::GetString after resourceManager_->GetIntArrayById"); if (errval == OHOS::Global::Resource::RState::SUCCESS) { return retv; } else { APP_LOGE("ContextDeal::GetIntArray GetIntArrayById(resId:%d) retval is %u", resId, errval); return std::vector(); } + APP_LOGI("ContextDeal::GetIntArray end"); } /** @@ -808,10 +850,11 @@ std::vector ContextDeal::GetIntArray(int resId) */ std::map ContextDeal::GetTheme() { + APP_LOGI("ContextDeal::GetTheme begin"); if (theme_.empty()) { SetTheme(GetThemeId()); } - + APP_LOGI("ContextDeal::GetTheme end"); return theme_; } @@ -822,6 +865,7 @@ std::map ContextDeal::GetTheme() */ void ContextDeal::SetTheme(int themeId) { + APP_LOGI("ContextDeal::SetTheme begin"); if (resourceManager_ == nullptr) { APP_LOGE("ContextDeal::SetTheme resourceManager_ is nullptr"); return; @@ -836,15 +880,16 @@ void ContextDeal::SetTheme(int themeId) if (!theme_.empty()) { theme_.clear(); } - + APP_LOGI("ContextDeal::GetString before resourceManager_->GetThemeById"); OHOS::Global::Resource::RState errval = resourceManager_->GetThemeById(themeId, theme_); + APP_LOGI("ContextDeal::GetString after resourceManager_->GetThemeById"); if (errval != OHOS::Global::Resource::RState::SUCCESS) { APP_LOGE("ContextDeal::SetTheme GetThemeById(themeId:%d) retval is %u", themeId, errval); return; } // hapModInfo->themeId = themeId; - + APP_LOGI("ContextDeal::SetTheme end"); return; } @@ -855,7 +900,9 @@ void ContextDeal::SetTheme(int themeId) */ std::map ContextDeal::GetPattern() { + APP_LOGI("ContextDeal::GetPattern begin"); if (!pattern_.empty()) { + APP_LOGI("ContextDeal::GetPattern end"); return pattern_; } else { APP_LOGE("ContextDeal::GetPattern pattern_ is empty"); @@ -872,19 +919,23 @@ std::map ContextDeal::GetPattern() */ int ContextDeal::GetColor(int resId) { + APP_LOGI("ContextDeal::GetColor begin"); if (resourceManager_ == nullptr) { APP_LOGE("ContextDeal::GetColor resourceManager_ is nullptr"); return INVALID_RESOURCE_VALUE; } uint32_t ret = INVALID_RESOURCE_VALUE; + APP_LOGI("ContextDeal::GetString before resourceManager_->GetColorById"); OHOS::Global::Resource::RState errval = resourceManager_->GetColorById(resId, ret); + APP_LOGI("ContextDeal::GetString after resourceManager_->GetColorById"); if (errval == OHOS::Global::Resource::RState::SUCCESS) { return ret; } else { APP_LOGE("ContextDeal::GetColor GetColorById(resId:%d) retval is %u", resId, errval); return INVALID_RESOURCE_VALUE; } + APP_LOGI("ContextDeal::GetColor end"); } /** @@ -931,7 +982,9 @@ bool ContextDeal::TerminateAbilityResult(int startId) */ int ContextDeal::GetDisplayOrientation() { + APP_LOGI("ContextDeal::GetDisplayOrientation begin"); if (abilityInfo_ != nullptr) { + APP_LOGI("ContextDeal::GetDisplayOrientation end"); return static_cast(abilityInfo_->orientation); } else { APP_LOGE("ContextDeal::GetDisplayOrientation abilityInfo_ is nullptr"); @@ -947,6 +1000,7 @@ int ContextDeal::GetDisplayOrientation() */ std::string ContextDeal::GetPreferencesDir() { + APP_LOGI("ContextDeal::GetPreferencesDir begin"); if (!preferenceDir_.empty()) { return preferenceDir_; } @@ -992,7 +1046,7 @@ std::string ContextDeal::GetPreferencesDir() } preferenceDir_ = dataDir; - + APP_LOGI("ContextDeal::GetPreferencesDir end"); return preferenceDir_; } @@ -1003,6 +1057,7 @@ std::string ContextDeal::GetPreferencesDir() */ void ContextDeal::SetColorMode(int mode) { + APP_LOGI("ContextDeal::SetColorMode begin"); auto hapModInfo = GetHapModuleInfo(); if (hapModInfo == nullptr) { APP_LOGE("ContextDeal::SetColorMode hapModInfo is nullptr"); @@ -1016,6 +1071,7 @@ void ContextDeal::SetColorMode(int mode) } else { // default use AUTO hapModInfo->colorMode = ModuleColorMode::AUTO; } + APP_LOGI("ContextDeal::SetColorMode end"); } /** @@ -1025,12 +1081,13 @@ void ContextDeal::SetColorMode(int mode) */ int ContextDeal::GetColorMode() { + APP_LOGI("ContextDeal::GetColorMode begin"); auto hapModInfo = GetHapModuleInfo(); if (hapModInfo == nullptr) { APP_LOGE("ContextDeal::GetColorMode hapModInfo is nullptr"); return -1; } - + APP_LOGI("ContextDeal::GetColorMode end"); return static_cast(hapModInfo->colorMode); } @@ -1060,6 +1117,7 @@ int ContextDeal::GetMissionId() */ void ContextDeal::TerminateAndRemoveMission() { + APP_LOGI("ContextDeal::TerminateAndRemoveMission begin"); auto abilityManagerClient = AAFwk::AbilityManagerClient::GetInstance(); if (abilityManagerClient == nullptr) { APP_LOGE("ContextDeal::TerminateAndRemoveMission abilityManagerClient is nullptr"); @@ -1067,10 +1125,13 @@ void ContextDeal::TerminateAndRemoveMission() } std::vector removeIdList = {GetMissionId()}; + APP_LOGI("ContextDeal::TerminateAndRemoveMission before abilityManagerClient->RemoveMissions"); ErrCode errval = abilityManagerClient->RemoveMissions(removeIdList); + APP_LOGI("ContextDeal::TerminateAndRemoveMission after abilityManagerClient->RemoveMissions"); if (errval != ERR_OK) { APP_LOGW("ContextDeal::TerminateAndRemoveMission RemoveMissions retval is ERROR(%d)", errval); } + APP_LOGI("ContextDeal::TerminateAndRemoveMission end"); } /** @@ -1108,6 +1169,7 @@ std::shared_ptr ContextDeal::GetUITaskDispatcher() */ std::shared_ptr ContextDeal::GetMainTaskDispatcher() { + APP_LOGI("ContextDeal::GetMainTaskDispatcher begin"); if (mainTaskDispatcher_ != nullptr) { return mainTaskDispatcher_; } @@ -1125,7 +1187,7 @@ std::shared_ptr ContextDeal::GetMainTaskDispatcher() } mainTaskDispatcher_ = std::make_shared(config, mainEventRunner_); - + APP_LOGI("ContextDeal::GetMainTaskDispatcher end"); return mainTaskDispatcher_; } @@ -1140,12 +1202,15 @@ std::shared_ptr ContextDeal::GetMainTaskDispatcher() std::shared_ptr ContextDeal::CreateParallelTaskDispatcher( const std::string &name, const TaskPriority &priority) { + APP_LOGI("ContextDeal::CreateParallelTaskDispatcher begin"); if (appContext_ == nullptr) { APP_LOGE("ContextDeal::CreateParallelTaskDispatcher appContext_ is nullptr"); return nullptr; } - return appContext_->CreateParallelTaskDispatcher(name, priority); + std::shared_ptr task = appContext_->CreateParallelTaskDispatcher(name, priority); + APP_LOGI("ContextDeal::CreateParallelTaskDispatcher end"); + return task; } /** @@ -1159,12 +1224,15 @@ std::shared_ptr ContextDeal::CreateParallelTaskDispatcher( std::shared_ptr ContextDeal::CreateSerialTaskDispatcher( const std::string &name, const TaskPriority &priority) { + APP_LOGI("ContextDeal::CreateSerialTaskDispatcher begin"); if (appContext_ == nullptr) { APP_LOGE("ContextDeal::CreateSerialTaskDispatcher appContext_ is nullptr"); return nullptr; } - return appContext_->CreateSerialTaskDispatcher(name, priority); + std::shared_ptr task = appContext_->CreateSerialTaskDispatcher(name, priority); + APP_LOGI("ContextDeal::CreateSerialTaskDispatcher end"); + return task; } /** @@ -1176,12 +1244,15 @@ std::shared_ptr ContextDeal::CreateSerialTaskDispatcher( */ std::shared_ptr ContextDeal::GetGlobalTaskDispatcher(const TaskPriority &priority) { + APP_LOGI("ContextDeal::GetGlobalTaskDispatcher begin"); if (appContext_ == nullptr) { APP_LOGE("ContextDeal::GetGlobalTaskDispatcher appContext_ is nullptr"); return nullptr; } - return appContext_->GetGlobalTaskDispatcher(priority); + std::shared_ptr task = appContext_->GetGlobalTaskDispatcher(priority); + APP_LOGI("ContextDeal::GetGlobalTaskDispatcher end"); + return task; } /** @@ -1201,6 +1272,8 @@ void ContextDeal::SetRunner(const std::shared_ptr &runner) */ bool ContextDeal::HapModuleInfoRequestInit() { + APP_LOGI("ContextDeal::HapModuleInfoRequestInit begin"); + sptr ptr = GetBundleManager(); if (ptr == nullptr) { APP_LOGE("GetHapModuleInfo failed to get bundle manager service"); @@ -1213,11 +1286,13 @@ bool ContextDeal::HapModuleInfoRequestInit() } hapModuleInfoLocal_ = std::make_shared(); + APP_LOGI("ContextDeal::HapModuleInfoRequestInit before IBundleMgr->GetBundleManager"); if (!ptr->GetHapModuleInfo(*abilityInfo_.get(), *hapModuleInfoLocal_)) { APP_LOGE("IBundleMgr::GetHapModuleInfo failed, will retval false value"); return false; } - + APP_LOGI("ContextDeal::HapModuleInfoRequestInit after IBundleMgr->GetBundleManager"); + APP_LOGI("ContextDeal::HapModuleInfoRequestInit end"); return true; } diff --git a/kits/appkit/native/app/src/main_thread.cpp b/kits/appkit/native/app/src/main_thread.cpp index 2b66932ead..a2c94f9fd1 100644 --- a/kits/appkit/native/app/src/main_thread.cpp +++ b/kits/appkit/native/app/src/main_thread.cpp @@ -149,7 +149,7 @@ std::shared_ptr MainThread::GetApplicationImpl() */ bool MainThread::ConnectToAppMgr() { - APP_LOGI("MainThread::connectToAppMgr start"); + APP_LOGI("MainThread::ConnectToAppMgr start"); auto object = OHOS::DelayedSingleton::GetInstance()->GetSystemAbility(APP_MGR_SERVICE_ID); if (object == nullptr) { APP_LOGE("failed to get bundle manager service"); @@ -161,17 +161,21 @@ bool MainThread::ConnectToAppMgr() return false; } + APP_LOGI("%{public}s, Start calling AddDeathRecipient.", __func__); if (!object->AddDeathRecipient(deathRecipient_)) { APP_LOGE("failed to AddDeathRecipient"); return false; } + APP_LOGI("%{public}s, End calling AddDeathRecipient.", __func__); appMgr_ = iface_cast(object); if (appMgr_ == nullptr) { APP_LOGE("failed to iface_cast object to appMgr_"); return false; } + APP_LOGI("MainThread::connectToAppMgr before AttachApplication"); appMgr_->AttachApplication(this); + APP_LOGI("MainThread::connectToAppMgr after AttachApplication"); APP_LOGI("MainThread::connectToAppMgr end"); return true; } @@ -199,7 +203,7 @@ void MainThread::Attach() */ void MainThread::RemoveAppMgrDeathRecipient() { - APP_LOGD("MainThread::RemoveAppMgrDeathRecipient called"); + APP_LOGI("MainThread::RemoveAppMgrDeathRecipient called begin"); if (appMgr_ == nullptr) { APP_LOGE("MainThread::RemoveAppMgrDeathRecipient failed"); return; @@ -207,10 +211,13 @@ void MainThread::RemoveAppMgrDeathRecipient() sptr object = appMgr_->AsObject(); if (object != nullptr) { + APP_LOGI("%{public}s called. Start calling RemoveDeathRecipient.", __func__); object->RemoveDeathRecipient(deathRecipient_); + APP_LOGI("%{public}s called. End calling RemoveDeathRecipient.", __func__); } else { APP_LOGE("appMgr_->AsObject() failed"); } + APP_LOGI("%{public}s called end.", __func__); } /** @@ -231,11 +238,12 @@ std::shared_ptr MainThread::GetMainHandler() const */ void MainThread::ScheduleForegroundApplication() { - APP_LOGI("MainThread::scheduleForegroundApplication called"); + APP_LOGI("MainThread::scheduleForegroundApplication called begin"); auto task = [appThread = this]() { appThread->HandleForegroundApplication(); }; if (!mainHandler_->PostTask(task)) { APP_LOGE("PostTask task failed"); } + APP_LOGI("MainThread::scheduleForegroundApplication called end."); } /** @@ -245,12 +253,13 @@ void MainThread::ScheduleForegroundApplication() */ void MainThread::ScheduleBackgroundApplication() { - APP_LOGI("MainThread::scheduleBackgroundApplication called"); + APP_LOGI("MainThread::scheduleBackgroundApplication called begin"); auto task = [appThread = this]() { appThread->HandleBackgroundApplication(); }; if (!mainHandler_->PostTask(task)) { APP_LOGE("MainThread::ScheduleBackgroundApplication PostTask task failed"); } + APP_LOGI("MainThread::scheduleBackgroundApplication called end."); } /** @@ -260,12 +269,13 @@ void MainThread::ScheduleBackgroundApplication() */ void MainThread::ScheduleTerminateApplication() { - APP_LOGI("MainThread::scheduleTerminateApplication called"); + APP_LOGI("MainThread::scheduleTerminateApplication called begin"); auto task = [appThread = this]() { appThread->HandleTerminateApplication(); }; if (!mainHandler_->PostTask(task)) { APP_LOGE("MainThread::ScheduleTerminateApplication PostTask task failed"); } + APP_LOGI("MainThread::scheduleTerminateApplication called."); } /** @@ -282,6 +292,7 @@ void MainThread::ScheduleShrinkMemory(const int level) if (!mainHandler_->PostTask(task)) { APP_LOGE("MainThread::ScheduleShrinkMemory PostTask task failed"); } + APP_LOGI("MainThread::scheduleShrinkMemory level: %{public}d end.", level); } /** @@ -291,12 +302,13 @@ void MainThread::ScheduleShrinkMemory(const int level) */ void MainThread::ScheduleProcessSecurityExit() { - APP_LOGI("MainThread::ScheduleProcessSecurityExit called"); + APP_LOGI("MainThread::ScheduleProcessSecurityExit called start"); auto task = [appThread = this]() { appThread->HandleProcessSecurityExit(); }; if (!mainHandler_->PostTask(task)) { APP_LOGE("MainThread::ScheduleProcessSecurityExit PostTask task failed"); } + APP_LOGI("MainThread::ScheduleProcessSecurityExit called end"); } /** @@ -318,12 +330,13 @@ void MainThread::ScheduleLowMemory() */ void MainThread::ScheduleLaunchApplication(const AppLaunchData &data) { - APP_LOGI("MainThread::scheduleLaunchApplication called"); + APP_LOGI("MainThread::scheduleLaunchApplication start"); auto task = [appThread = this, data]() { appThread->HandleLaunchApplication(data); }; if (!mainHandler_->PostTask(task)) { APP_LOGE("MainThread::ScheduleLaunchApplication PostTask task failed"); } + APP_LOGI("MainThread::scheduleLaunchApplication end."); } /** @@ -336,7 +349,7 @@ void MainThread::ScheduleLaunchApplication(const AppLaunchData &data) */ void MainThread::ScheduleLaunchAbility(const AbilityInfo &info, const sptr &token) { - APP_LOGI("MainThread::scheduleLaunchAbility called"); + APP_LOGI("MainThread::scheduleLaunchAbility called start."); APP_LOGI( "MainThread::scheduleLaunchAbility AbilityInfo name:%{public}s type:%{public}d", info.name.c_str(), info.type); @@ -352,6 +365,7 @@ void MainThread::ScheduleLaunchAbility(const AbilityInfo &info, const sptrPostTask(task)) { APP_LOGE("MainThread::ScheduleLaunchAbility PostTask task failed"); } + APP_LOGI("MainThread::scheduleLaunchAbility called end."); } /** @@ -363,11 +377,12 @@ void MainThread::ScheduleLaunchAbility(const AbilityInfo &info, const sptr &token) { - APP_LOGI("MainThread::scheduleCleanAbility called"); + APP_LOGI("MainThread::scheduleCleanAbility called start."); auto task = [appThread = this, token]() { appThread->HandleCleanAbility(token); }; if (!mainHandler_->PostTask(task)) { APP_LOGE("MainThread::ScheduleCleanAbility PostTask task failed"); } + APP_LOGI("MainThread::scheduleCleanAbility called end."); } /** @@ -391,11 +406,12 @@ void MainThread::ScheduleProfileChanged(const Profile &profile) */ void MainThread::ScheduleConfigurationUpdated(const Configuration &config) { - APP_LOGI("MainThread::ScheduleConfigurationUpdated called"); + APP_LOGI("MainThread::ScheduleConfigurationUpdated called start."); auto task = [appThread = this, config]() { appThread->HandleConfigurationUpdated(config); }; if (!mainHandler_->PostTask(task)) { APP_LOGE("MainThread::ScheduleConfigurationUpdated PostTask task failed"); } + APP_LOGI("MainThread::ScheduleConfigurationUpdated called end."); } /** @@ -408,6 +424,8 @@ void MainThread::ScheduleConfigurationUpdated(const Configuration &config) */ bool MainThread::CheckLaunchApplicationParam(const AppLaunchData &appLaunchData) const { + APP_LOGI("MainThread::CheckLaunchApplicationParam called start."); + ApplicationInfo appInfo = appLaunchData.GetApplicationInfo(); ProcessInfo processInfo = appLaunchData.GetProcessInfo(); @@ -421,6 +439,7 @@ bool MainThread::CheckLaunchApplicationParam(const AppLaunchData &appLaunchData) return false; } + APP_LOGI("MainThread::CheckLaunchApplicationParam called end."); return true; } @@ -434,6 +453,7 @@ bool MainThread::CheckLaunchApplicationParam(const AppLaunchData &appLaunchData) */ bool MainThread::CheckAbilityItem(const std::shared_ptr &record) const { + APP_LOGI("MainThread::CheckAbilityItem called start."); if (record == nullptr) { APP_LOGE("MainThread::checkAbilityItem record is null"); return false; @@ -452,6 +472,7 @@ bool MainThread::CheckAbilityItem(const std::shared_ptr &rec return false; } + APP_LOGI("MainThread::CheckAbilityItem called end."); return true; } @@ -462,12 +483,14 @@ bool MainThread::CheckAbilityItem(const std::shared_ptr &rec */ void MainThread::HandleTerminateApplicationLocal() { - APP_LOGI("MainThread::HandleTerminateApplicationLocal called..."); + APP_LOGI("MainThread::HandleTerminateApplicationLocal called start."); if (application_ == nullptr) { APP_LOGE("MainThread::HandleTerminateApplicationLocal error!"); return; } + APP_LOGI("MainThread::HandleTerminateApplicationLocal before PerformTerminateStrong."); applicationImpl_->PerformTerminateStrong(); + APP_LOGI("MainThread::HandleTerminateApplicationLocal after PerformTerminateStrong."); std::shared_ptr runner = mainHandler_->GetEventRunner(); if (runner == nullptr) { APP_LOGE("MainThread::HandleTerminateApplicationLocal get manHandler error"); @@ -481,14 +504,19 @@ void MainThread::HandleTerminateApplicationLocal() SetRunnerStarted(false); #ifdef ABILITY_LIBRARY_LOADER + APP_LOGI("MainThread::HandleTerminateApplicationLocal called. Start calling CloseAbilityLibrary."); CloseAbilityLibrary(); + APP_LOGI("MainThread::HandleTerminateApplicationLocal called. End calling CloseAbilityLibrary."); #endif // ABILITY_LIBRARY_LOADER #ifdef APPLICATION_LIBRARY_LOADER if (handleAppLib_ != nullptr) { + APP_LOGI("MainThread::HandleTerminateApplicationLocal called. Start calling dlclose."); dlclose(handleAppLib_); + APP_LOGI("MainThread::HandleTerminateApplicationLocal called. End calling dlclose."); handleAppLib_ = nullptr; } #endif // APPLICATION_LIBRARY_LOADER + APP_LOGI("MainThread::HandleTerminateApplicationLocal called end."); } /** @@ -498,7 +526,7 @@ void MainThread::HandleTerminateApplicationLocal() */ void MainThread::HandleProcessSecurityExit() { - APP_LOGI("MainThread::HandleProcessSecurityExit called"); + APP_LOGI("MainThread::HandleProcessSecurityExit called start."); if (abilityRecordMgr_ == nullptr) { APP_LOGE("MainThread::HandleProcessSecurityExit abilityRecordMgr_ is null"); return; @@ -511,6 +539,7 @@ void MainThread::HandleProcessSecurityExit() } HandleTerminateApplicationLocal(); + APP_LOGI("MainThread::HandleProcessSecurityExit called end."); } /** @@ -522,7 +551,7 @@ void MainThread::HandleProcessSecurityExit() */ void MainThread::HandleLaunchApplication(const AppLaunchData &appLaunchData) { - APP_LOGI("MainThread::handleLaunchApplication called"); + APP_LOGI("MainThread::handleLaunchApplication called start."); if (application_ != nullptr) { APP_LOGE("MainThread::handleLaunchApplication already create application"); return; @@ -534,15 +563,19 @@ void MainThread::HandleLaunchApplication(const AppLaunchData &appLaunchData) } #ifdef ABILITY_LIBRARY_LOADER + APP_LOGI("MainThread::handleLaunchApplication Start calling LoadAbilityLibrary."); LoadAbilityLibrary(appLaunchData.GetApplicationInfo().moduleSourceDirs); + APP_LOGI("MainThread::handleLaunchApplication End calling LoadAbilityLibrary."); #endif // ABILITY_LIBRARY_LOADER #ifdef APPLICATION_LIBRARY_LOADER std::string appPath = applicationLibraryPath; + APP_LOGI("MainThread::handleLaunchApplication Start calling dlopen. appPath=%{public}s", appPath.c_str()); handleAppLib_ = dlopen(appPath.c_str(), RTLD_NOW | RTLD_GLOBAL); if (handleAppLib_ == nullptr) { APP_LOGE("Fail to dlopen %{public}s, [%{public}s]", appPath.c_str(), dlerror()); exit(-1); } + APP_LOGI("MainThread::handleLaunchApplication End calling dlopen."; #endif // APPLICATION_LIBRARY_LOADER ApplicationInfo appInfo = appLaunchData.GetApplicationInfo(); @@ -600,11 +633,13 @@ void MainThread::HandleLaunchApplication(const AppLaunchData &appLaunchData) return; } + APP_LOGI("MainThread::handleLaunchApplication. Start calling GetBundleManager."); sptr bundleMgr = contextDeal->GetBundleManager(); if (bundleMgr == nullptr) { APP_LOGE("MainThread::handleLaunchApplication GetBundleManager is nullptr"); return; } + APP_LOGI("MainThread::handleLaunchApplication. End calling GetBundleManager."); BundleInfo bundleInfo; APP_LOGI("MainThread::handleLaunchApplication length: %{public}zu, bundleName: %{public}s", @@ -612,19 +647,23 @@ void MainThread::HandleLaunchApplication(const AppLaunchData &appLaunchData) appInfo.bundleName.c_str()); bundleMgr->GetBundleInfo(appInfo.bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); - APP_LOGI("MainThread::handleLaunchApplication moduleResPaths count: %{public}zu", bundleInfo.moduleResPaths.size()); + APP_LOGI("MainThread::handleLaunchApplication moduleResPaths count: %{public}zu start", bundleInfo.moduleResPaths.size()); for (auto moduleResPath : bundleInfo.moduleResPaths) { if (!moduleResPath.empty()) { APP_LOGI("MainThread::handleLaunchApplication length: %{public}zu, moduleResPath: %{public}s", moduleResPath.length(), moduleResPath.c_str()); + APP_LOGI("MainThread::handleLaunchApplication. before resourceManager->AddResource."); if (!resourceManager->AddResource(moduleResPath.c_str())) { APP_LOGE("MainThread::handleLaunchApplication AddResource failed"); } + APP_LOGI("MainThread::handleLaunchApplication. after resourceManager->AddResource."); } } - + APP_LOGI("MainThread::handleLaunchApplication moduleResPaths end."); + APP_LOGI("MainThread::handleLaunchApplication before Resource::CreateResConfig."); std::unique_ptr resConfig(Global::Resource::CreateResConfig()); + APP_LOGI("MainThread::handleLaunchApplication after Resource::CreateResConfig."); resConfig->SetLocaleInfo("zh", "Hans", "CN"); const icu::Locale *localeInfo = resConfig->GetLocaleInfo(); if (localeInfo != nullptr) { @@ -636,10 +675,21 @@ void MainThread::HandleLaunchApplication(const AppLaunchData &appLaunchData) APP_LOGI("MainThread::handleLaunchApplication localeInfo is nullptr."); } + APP_LOGI("MainThread::handleLaunchApplication. Start calling UpdateResConfig."); resourceManager->UpdateResConfig(*resConfig); + APP_LOGI("MainThread::handleLaunchApplication. End calling UpdateResConfig."); + + APP_LOGI("MainThread::handleLaunchApplication. Start calling initResourceManager."); contextDeal->initResourceManager(resourceManager); + APP_LOGI("MainThread::handleLaunchApplication. End calling initResourceManager."); + + APP_LOGI("MainThread::handleLaunchApplication. Start calling SetApplicationContext."); contextDeal->SetApplicationContext(application_); + APP_LOGI("MainThread::handleLaunchApplication. End calling SetApplicationContext."); + + APP_LOGI("MainThread::handleLaunchApplication. Start calling AttachBaseContext."); application_->AttachBaseContext(contextDeal); + APP_LOGI("MainThread::handleLaunchApplication. End calling AttachBaseContext."); abilityRecordMgr_ = std::make_shared(); if (abilityRecordMgr_ == nullptr) { @@ -647,22 +697,29 @@ void MainThread::HandleLaunchApplication(const AppLaunchData &appLaunchData) return; } + APP_LOGI("MainThread::handleLaunchApplication. Start calling SetAbilityRecordMgr."); application_->SetAbilityRecordMgr(abilityRecordMgr_); + APP_LOGI("MainThread::handleLaunchApplication. End calling SetAbilityRecordMgr."); applicationImpl_->SetRecordId(appLaunchData.GetRecordId()); applicationImpl_->SetApplication(application_); mainThreadState_ = MainThreadState::READY; + APP_LOGI("MainThread::handleLaunchApplication before PerformAppReady."); if (!applicationImpl_->PerformAppReady()) { APP_LOGE("HandleLaunchApplication::application applicationImpl_->PerformAppReady failed"); return; } - + APP_LOGI("MainThread::handleLaunchApplication after PerformAppReady."); // L1 needs to add corresponding interface ApplicationEnvImpl *pAppEvnIml = ApplicationEnvImpl::GetInstance(); if (pAppEvnIml) { pAppEvnIml->SetAppInfo(*applicationInfo_.get()); + } else { + APP_LOGE("HandleLaunchApplication::application pAppEvnIml is null"); } + + APP_LOGI("MainThread::handleLaunchApplication called end."); } /** @@ -674,26 +731,26 @@ void MainThread::HandleLaunchApplication(const AppLaunchData &appLaunchData) */ void MainThread::HandleLaunchAbility(const std::shared_ptr &abilityRecord) { - APP_LOGI("MainThread::handleLaunchAbility called"); + APP_LOGI("MainThread::handleLaunchAbility called start."); if (applicationImpl_ == nullptr) { - APP_LOGE("MainThread::ScheduleLaunchAbility applicationImpl_ is null"); + APP_LOGE("MainThread::HandleLaunchAbility applicationImpl_ is null"); return; } if (abilityRecordMgr_ == nullptr) { - APP_LOGE("MainThread::ScheduleLaunchAbility abilityRecordMgr_ is null"); + APP_LOGE("MainThread::HandleLaunchAbility abilityRecordMgr_ is null"); return; } if (abilityRecord == nullptr) { - APP_LOGE("MainThread::ScheduleLaunchAbility parameter(abilityRecord) is null"); + APP_LOGE("MainThread::HandleLaunchAbility parameter(abilityRecord) is null"); return; } auto abilityToken = abilityRecord->GetToken(); if (abilityToken == nullptr) { - APP_LOGE("MainThread::ScheduleLaunchAbility failed. abilityRecord->GetToken failed"); + APP_LOGE("MainThread::HandleLaunchAbility failed. abilityRecord->GetToken failed"); return; } @@ -712,10 +769,15 @@ void MainThread::HandleLaunchAbility(const std::shared_ptr & mainThreadState_ = MainThreadState::RUNNING; #ifdef APP_ABILITY_USE_TWO_RUNNER + APP_LOGI("MainThread::handleLaunchAbility. Start calling AbilityThreadMain start."); AbilityThread::AbilityThreadMain(application_, abilityRecord); + APP_LOGI("MainThread::handleLaunchAbility. Start calling AbilityThreadMain end."); #else + APP_LOGI("MainThread::handleLaunchAbility. Start calling 2 AbilityThreadMain start."); AbilityThread::AbilityThreadMain(application_, abilityRecord, mainHandler_->GetEventRunner()); + APP_LOGI("MainThread::handleLaunchAbility. Start calling 2 AbilityThreadMain end."); #endif + APP_LOGI("MainThread::handleLaunchAbility called end."); } /** @@ -727,7 +789,7 @@ void MainThread::HandleLaunchAbility(const std::shared_ptr & */ void MainThread::HandleCleanAbilityLocal(const sptr &token) { - APP_LOGI("MainThread::HandleCleanAbilityLocal called"); + APP_LOGI("MainThread::HandleCleanAbilityLocal called start."); if (!IsApplicationReady()) { APP_LOGE("MainThread::HandleCleanAbilityLocal not init OHOSApplication, should launch application first"); return; @@ -765,6 +827,7 @@ void MainThread::HandleCleanAbilityLocal(const sptr &token) APP_LOGW("MainThread::HandleCleanAbilityLocal runner not found"); } #endif + APP_LOGI("MainThread::HandleCleanAbilityLocal called end."); } /** @@ -776,7 +839,7 @@ void MainThread::HandleCleanAbilityLocal(const sptr &token) */ void MainThread::HandleCleanAbility(const sptr &token) { - APP_LOGI("MainThread::handleCleanAbility called"); + APP_LOGI("MainThread::handleCleanAbility called start."); if (!IsApplicationReady()) { APP_LOGE("MainThread::handleCleanAbility not init OHOSApplication, should launch application first"); return; @@ -814,7 +877,10 @@ void MainThread::HandleCleanAbility(const sptr &token) APP_LOGW("MainThread::handleCleanAbility runner not found"); } #endif + APP_LOGI("MainThread::handleCleanAbility before AbilityCleaned."); appMgr_->AbilityCleaned(token); + APP_LOGI("MainThread::handleCleanAbility after AbilityCleaned."); + APP_LOGI("MainThread::handleCleanAbility called end."); } /** @@ -824,7 +890,7 @@ void MainThread::HandleCleanAbility(const sptr &token) */ void MainThread::HandleForegroundApplication() { - APP_LOGI("MainThread::handleForegroundApplication called..."); + APP_LOGI("MainThread::handleForegroundApplication called start."); if ((application_ == nullptr) || (appMgr_ == nullptr)) { APP_LOGE("MainThread::handleForegroundApplication error!"); return; @@ -835,7 +901,10 @@ void MainThread::HandleForegroundApplication() return; } + APP_LOGI("MainThread::handleForegroundApplication before ApplicationForegrounded"); appMgr_->ApplicationForegrounded(applicationImpl_->GetRecordId()); + APP_LOGI("MainThread::handleForegroundApplication after ApplicationForegrounded"); + APP_LOGI("MainThread::handleForegroundApplication called end"); } /** @@ -845,7 +914,7 @@ void MainThread::HandleForegroundApplication() */ void MainThread::HandleBackgroundApplication() { - APP_LOGI("MainThread::handleBackgroundApplication called..."); + APP_LOGI("MainThread::handleBackgroundApplication called start."); if ((application_ == nullptr) || (appMgr_ == nullptr)) { APP_LOGE("MainThread::handleBackgroundApplication error!"); @@ -856,8 +925,11 @@ void MainThread::HandleBackgroundApplication() APP_LOGE("MainThread::handleForegroundApplication error!, applicationImpl_->PerformBackground() failed"); return; } - + APP_LOGI("MainThread::handleBackgroundApplication before ApplicationBackgrounded"); appMgr_->ApplicationBackgrounded(applicationImpl_->GetRecordId()); + APP_LOGI("MainThread::handleBackgroundApplication after ApplicationBackgrounded"); + + APP_LOGI("MainThread::handleBackgroundApplication called end"); } /** @@ -867,31 +939,40 @@ void MainThread::HandleBackgroundApplication() */ void MainThread::HandleTerminateApplication() { - APP_LOGI("MainThread::handleTerminateApplication called..."); + APP_LOGI("MainThread::handleTerminateApplication called start."); if ((application_ == nullptr) || (appMgr_ == nullptr)) { APP_LOGE("MainThread::handleTerminateApplication error!"); return; } + APP_LOGI("MainThread::handleTerminateApplication before PerformTerminate"); if (!applicationImpl_->PerformTerminate()) { APP_LOGE("MainThread::handleForegroundApplication error!, applicationImpl_->PerformTerminate() failed"); return; } + APP_LOGI("MainThread::handleTerminateApplication after PerformTerminate"); + APP_LOGI("MainThread::handleTerminateApplication before ApplicationTerminated"); appMgr_->ApplicationTerminated(applicationImpl_->GetRecordId()); + APP_LOGI("MainThread::handleTerminateApplication after ApplicationTerminated"); std::shared_ptr runner = mainHandler_->GetEventRunner(); if (runner == nullptr) { APP_LOGE("MainThread::handleTerminateApplication get manHandler error"); return; } + + APP_LOGI("MainThread::handleTerminateApplication before stop runner"); int ret = runner->Stop(); + APP_LOGI("MainThread::handleTerminateApplication after stop runner"); if (ret != ERR_OK) { APP_LOGE("MainThread::handleTerminateApplication failed. runner->Run failed ret = %{public}d", ret); } SetRunnerStarted(false); #ifdef ABILITY_LIBRARY_LOADER + APP_LOGI("MainThread::handleTerminateApplication. Start callint CloseAbilityLibrary."); CloseAbilityLibrary(); + APP_LOGI("MainThread::handleTerminateApplication. End callint CloseAbilityLibrary."); #endif // ABILITY_LIBRARY_LOADER #ifdef APPLICATION_LIBRARY_LOADER if (handleAppLib_ != nullptr) { @@ -899,6 +980,7 @@ void MainThread::HandleTerminateApplication() handleAppLib_ = nullptr; } #endif // APPLICATION_LIBRARY_LOADER + APP_LOGI("MainThread::handleTerminateApplication called end."); } /** @@ -910,7 +992,7 @@ void MainThread::HandleTerminateApplication() */ void MainThread::HandleShrinkMemory(const int level) { - APP_LOGI("MainThread::HandleShrinkMemory called..."); + APP_LOGI("MainThread::HandleShrinkMemory called start."); if (applicationImpl_ == nullptr) { APP_LOGE("MainThread::HandleShrinkMemory error! applicationImpl_ is null"); @@ -918,6 +1000,7 @@ void MainThread::HandleShrinkMemory(const int level) } applicationImpl_->PerformMemoryLevel(level); + APP_LOGI("MainThread::HandleShrinkMemory called end."); } /** @@ -929,7 +1012,7 @@ void MainThread::HandleShrinkMemory(const int level) */ void MainThread::HandleConfigurationUpdated(const Configuration &config) { - APP_LOGI("MainThread::HandleConfigurationUpdated called..."); + APP_LOGI("MainThread::HandleConfigurationUpdated called start."); if (applicationImpl_ == nullptr) { APP_LOGE("MainThread::HandleConfigurationUpdated error! applicationImpl_ is null"); @@ -937,10 +1020,12 @@ void MainThread::HandleConfigurationUpdated(const Configuration &config) } applicationImpl_->PerformConfigurationUpdated(config); + APP_LOGI("MainThread::HandleConfigurationUpdated called end."); } void MainThread::Init(const std::shared_ptr &runner) { + APP_LOGI("MainThread:Init Start"); mainHandler_ = std::make_shared(runner, this); auto task = [appThread = this]() { APP_LOGI("MainThread:MainHandler Start"); @@ -949,8 +1034,10 @@ void MainThread::Init(const std::shared_ptr &runner) if (!mainHandler_->PostTask(task)) { APP_LOGE("MainThread::Init PostTask task failed"); } - + APP_LOGI("MainThread:Init before CreateRunner."); TaskHandlerClient::GetInstance()->CreateRunner(); + APP_LOGI("MainThread:Init after CreateRunner."); + APP_LOGI("MainThread:Init end."); } void MainThread::Start() @@ -967,8 +1054,13 @@ void MainThread::Start() return; } + APP_LOGI("MainThread::main called start Init"); thread->Init(runner); + APP_LOGI("MainThread::main called end Init"); + + APP_LOGI("MainThread::main called start Attach"); thread->Attach(); + APP_LOGI("MainThread::main called end Attach"); int ret = runner->Run(); if (ret != ERR_OK) { @@ -976,7 +1068,7 @@ void MainThread::Start() } thread->RemoveAppMgrDeathRecipient(); - APP_LOGW("MainThread::main runner stopped"); + APP_LOGI("MainThread::main runner stopped"); } MainThread::MainHandler::MainHandler(const std::shared_ptr &runner, const sptr &thread) @@ -1002,10 +1094,13 @@ void MainThread::MainHandler::ProcessEvent(const OHOS::AppExecFwk::InnerEvent::P */ bool MainThread::IsApplicationReady() const { + APP_LOGI("MainThread::IsApplicationReady called start"); if (application_ == nullptr || applicationImpl_ == nullptr) { + APP_LOGI("MainThread::IsApplicationReady called. application_=null or applicationImpl_=null"); return false; } + APP_LOGI("MainThread::IsApplicationReady called end"); return true; } @@ -1019,9 +1114,11 @@ bool MainThread::IsApplicationReady() const */ void MainThread::LoadAbilityLibrary(const std::vector &libraryPaths) { + APP_LOGI("MainThread::LoadAbilityLibrary called start"); #ifdef ACEABILITY_LIBRARY_LOADER std::string acelibdir("/system/lib/libace.z.so"); void *AceAbilityLib = nullptr; + APP_LOGI("MainThread::LoadAbilityLibrary. Start calling dlopen acelibdir."); AceAbilityLib = dlopen(acelibdir.c_str(), RTLD_NOW | RTLD_GLOBAL); if (AceAbilityLib == nullptr) { APP_LOGE("Fail to dlopen %{public}s, [%{public}s]", acelibdir.c_str(), dlerror()); @@ -1029,10 +1126,13 @@ void MainThread::LoadAbilityLibrary(const std::vector &libraryPaths APP_LOGI("Success to dlopen %{public}s", acelibdir.c_str()); handleAbilityLib_.emplace_back(AceAbilityLib); } + APP_LOGI("MainThread::LoadAbilityLibrary. End calling dlopen."); #endif // ACEABILITY_LIBRARY_LOADER int size = libraryPaths.size(); + APP_LOGI("MainThread::LoadAbilityLibrary. size=%{public}d.", size); for (int index = 0; index < size; index++) { std::string libraryPath = libraryPaths[index]; + APP_LOGI("Try to scanDir %{public}s", libraryPath.c_str()); if (!ScanDir(libraryPath)) { APP_LOGE("Fail to scanDir %{public}s", libraryPath.c_str()); continue; @@ -1047,7 +1147,9 @@ void MainThread::LoadAbilityLibrary(const std::vector &libraryPaths void *handleAbilityLib = nullptr; for (auto fileEntry : fileEntries_) { if (!fileEntry.empty()) { + APP_LOGI("MainThread::LoadAbilityLibrary. Start calling dlopen fileEntry."); handleAbilityLib = dlopen(fileEntry.c_str(), RTLD_NOW | RTLD_GLOBAL); + APP_LOGI("MainThread::LoadAbilityLibrary. End calling dlopen fileEntry."); if (handleAbilityLib == nullptr) { APP_LOGE("Fail to dlopen %{public}s, [%{public}s]", fileEntry.c_str(), dlerror()); exit(-1); @@ -1057,6 +1159,7 @@ void MainThread::LoadAbilityLibrary(const std::vector &libraryPaths handleAbilityLib_.emplace_back(handleAbilityLib); } } + APP_LOGI("MainThread::LoadAbilityLibrary called end."); } /** @@ -1066,14 +1169,18 @@ void MainThread::LoadAbilityLibrary(const std::vector &libraryPaths */ void MainThread::CloseAbilityLibrary() { + APP_LOGI("MainThread::CloseAbilityLibrary called start"); for (auto iter : handleAbilityLib_) { if (iter != nullptr) { + APP_LOGI("MainThread::CloseAbilityLibrary before dlclose"); dlclose(iter); + APP_LOGI("MainThread::CloseAbilityLibrary after dlclose"); iter = nullptr; } } handleAbilityLib_.clear(); fileEntries_.clear(); + APP_LOGI("MainThread::CloseAbilityLibrary called end"); } /** @@ -1085,15 +1192,19 @@ void MainThread::CloseAbilityLibrary() */ bool MainThread::ScanDir(const std::string &dirPath) { + APP_LOGI("MainThread::ScanDir called start. dirPath: %{public}s.", dirPath.c_str()); + APP_LOGI("MainThread::ScanDir before opendir."); DIR *dirp = opendir(dirPath.c_str()); if (dirp == nullptr) { APP_LOGE("MainThread::ScanDir open dir:%{private}s fail", dirPath.c_str()); return false; } - + APP_LOGI("MainThread::ScanDir after opendir."); struct dirent *df = nullptr; for (;;) { + APP_LOGI("MainThread::ScanDir before readdir."); df = readdir(dirp); + APP_LOGI("MainThread::ScanDir after readdir."); if (df == nullptr) { break; } @@ -1109,9 +1220,12 @@ bool MainThread::ScanDir(const std::string &dirPath) } } + APP_LOGI("MainThread::ScanDir before closedir."); if (closedir(dirp) == -1) { APP_LOGW("close dir fail"); } + APP_LOGI("MainThread::ScanDir after closedir."); + APP_LOGI("MainThread::ScanDir called end."); return true; } @@ -1127,7 +1241,10 @@ bool MainThread::ScanDir(const std::string &dirPath) */ bool MainThread::CheckFileType(const std::string &fileName, const std::string &extensionName) { - APP_LOGD("path is %{public}s, support suffix is %{public}s", fileName.c_str(), extensionName.c_str()); + APP_LOGD("MainThread::CheckFileType path is %{public}s, support suffix is %{public}s", + fileName.c_str(), + extensionName.c_str()); + if (fileName.empty()) { APP_LOGE("the file name is empty"); return false; @@ -1140,6 +1257,7 @@ bool MainThread::CheckFileType(const std::string &fileName, const std::string &e } std::string suffixStr = fileName.substr(position); + APP_LOGD("MainThread::CheckFileType end."); return LowerStr(suffixStr) == extensionName; } #endif // ABILITY_LIBRARY_LOADER diff --git a/kits/appkit/native/test/BUILD.gn b/kits/appkit/native/test/BUILD.gn index 653f2576e6..2e16344899 100755 --- a/kits/appkit/native/test/BUILD.gn +++ b/kits/appkit/native/test/BUILD.gn @@ -294,6 +294,7 @@ config("ability_start_setting_config") { "//foundation/appexecfwk/standard/kits/appkit/native/app/include", "//foundation/appexecfwk/common/log/include/", "//utils/native/base/include", + "//foundation/aafwk/standard/interfaces/innerkits/ability_manager/include", ] } @@ -305,7 +306,10 @@ ohos_unittest("ability_start_setting_test") { ":ability_start_setting_config", ] - sources = [ "unittest/ability_start_setting_test.cpp" ] + sources = [ + "//foundation/aafwk/standard/services/abilitymgr/src/ability_start_setting.cpp", + "unittest/ability_start_setting_test.cpp", + ] deps = [ "//foundation/appexecfwk/standard/kits:appkit_native", diff --git a/kits/appkit/native/test/mock/include/mock_ability_manager_client_interface1.h b/kits/appkit/native/test/mock/include/mock_ability_manager_client_interface1.h index c886941269..92a308e6c2 100644 --- a/kits/appkit/native/test/mock/include/mock_ability_manager_client_interface1.h +++ b/kits/appkit/native/test/mock/include/mock_ability_manager_client_interface1.h @@ -281,6 +281,23 @@ public: { return nullptr; }; + bool QueryAbilityInfos(const Want &want, std::vector &abilityInfos) + { + return true; + } + bool GetShortcutInfos(const std::string &bundleName, std::vector &shortcutInfos) + { + return true; + } + bool GetModuleUsageRecords(const int32_t number, std::vector &moduleUsageRecords) + { + return true; + } + bool NotifyActivityLifeStatus( + const std::string &bundleName, const std::string &abilityName, const int64_t launchTime) + { + return true; + } }; class MockAbilityContextDeal : public ContextDeal { diff --git a/kits/appkit/native/test/mock/include/mock_resourceManager_interface1.cpp b/kits/appkit/native/test/mock/include/mock_resourceManager_interface1.cpp index 9f1cbeb88f..f06f278212 100644 --- a/kits/appkit/native/test/mock/include/mock_resourceManager_interface1.cpp +++ b/kits/appkit/native/test/mock/include/mock_resourceManager_interface1.cpp @@ -1,4 +1,17 @@ - +/* + * Copyright (c) 2021 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 #include "gmock/gmock.h" diff --git a/kits/appkit/native/test/unittest/ability_start_setting_test.cpp b/kits/appkit/native/test/unittest/ability_start_setting_test.cpp index 9661682ce8..1720b17392 100755 --- a/kits/appkit/native/test/unittest/ability_start_setting_test.cpp +++ b/kits/appkit/native/test/unittest/ability_start_setting_test.cpp @@ -25,7 +25,7 @@ namespace AppExecFwk { using namespace testing::ext; using namespace OHOS; using namespace OHOS::AppExecFwk; - +using namespace OHOS::AAFwk; class AbilityStartSettingTest : public testing::Test { public: AbilityStartSettingTest() : abilityStartSetting_(nullptr) diff --git a/libs/test/moduletest/common/event_handler/event_handler_fd_listener_module_test.cpp b/libs/test/moduletest/common/event_handler/event_handler_fd_listener_module_test.cpp index f1e3e8e5ca..f062eabe23 100644 --- a/libs/test/moduletest/common/event_handler/event_handler_fd_listener_module_test.cpp +++ b/libs/test/moduletest/common/event_handler/event_handler_fd_listener_module_test.cpp @@ -139,7 +139,7 @@ HWTEST_F(EventHandlerFdListenerModuleTest, AddListener001, TestSize.Level1) */ int32_t fds[] = {-1, -1}; int32_t pipe = pipe2(fds, O_NONBLOCK); - ASSERT_GE(pipe, 0); + EXPECT_GE(pipe, 0); auto listener = std::make_shared(); auto myRunner = EventRunner::Create(false); @@ -191,7 +191,7 @@ HWTEST_F(EventHandlerFdListenerModuleTest, AddListener003, TestSize.Level1) */ int32_t fds[] = {-1, -1}; int32_t pipe = pipe2(fds, O_NONBLOCK); - ASSERT_GE(pipe, 0); + EXPECT_GE(pipe, 0); auto listener = std::make_shared(); auto myRunner = EventRunner::Create(true); @@ -216,7 +216,7 @@ HWTEST_F(EventHandlerFdListenerModuleTest, AddListener004, TestSize.Level1) */ int32_t fds[] = {-1, -1}; int32_t pipe = pipe2(fds, O_NONBLOCK); - ASSERT_GE(pipe, 0); + EXPECT_GE(pipe, 0); auto myRunner = EventRunner::Create(true); auto handler = std::make_shared(myRunner); @@ -239,7 +239,7 @@ HWTEST_F(EventHandlerFdListenerModuleTest, AddListener005, TestSize.Level1) */ int32_t fds[] = {-1, -1}; int32_t pipe = pipe2(fds, O_NONBLOCK); - ASSERT_GE(pipe, 0); + EXPECT_GE(pipe, 0); auto listener = std::make_shared(); auto handler = std::make_shared(nullptr); @@ -262,7 +262,7 @@ HWTEST_F(EventHandlerFdListenerModuleTest, RemoveListener001, TestSize.Level1) */ int32_t fds[] = {-1, -1}; int32_t pipe = pipe2(fds, O_NONBLOCK); - ASSERT_GE(pipe, 0); + EXPECT_GE(pipe, 0); auto listener = std::make_shared(); auto myRunner = EventRunner::Create(false); @@ -294,7 +294,7 @@ HWTEST_F(EventHandlerFdListenerModuleTest, RemoveListener002, TestSize.Level1) */ int32_t fds[] = {-1, -1}; int32_t pipe = pipe2(fds, O_NONBLOCK); - ASSERT_GE(pipe, 0); + EXPECT_GE(pipe, 0); auto listener = std::make_shared(); auto myRunner = EventRunner::Create(false); @@ -326,7 +326,7 @@ HWTEST_F(EventHandlerFdListenerModuleTest, TriggerShutdown001, TestSize.Level1) */ int32_t fds[] = {-1, -1}; int32_t pipe = pipe2(fds, O_NONBLOCK); - ASSERT_GE(pipe, 0); + EXPECT_GE(pipe, 0); auto listener = std::make_shared(); auto myRunner = EventRunner::Create(false); @@ -362,7 +362,7 @@ HWTEST_F(EventHandlerFdListenerModuleTest, TriggerException001, TestSize.Level1) */ int32_t fds[] = {-1, -1}; int32_t pipe = pipe2(fds, O_NONBLOCK); - ASSERT_GE(pipe, 0); + EXPECT_GE(pipe, 0); auto listener = std::make_shared(fds[0]); auto myRunner = EventRunner::Create(false); diff --git a/libs/test/moduletest/common/event_handler/event_handler_press_module_test.cpp b/libs/test/moduletest/common/event_handler/event_handler_press_module_test.cpp index 0d035a301c..49dd92d300 100644 --- a/libs/test/moduletest/common/event_handler/event_handler_press_module_test.cpp +++ b/libs/test/moduletest/common/event_handler/event_handler_press_module_test.cpp @@ -205,7 +205,7 @@ HWTEST_F(EventHandlerPressModuleTest, FdListenerPress001, TestSize.Level3) */ int32_t fds[] = {-1, -1}; int32_t pipe = pipe2(fds, O_NONBLOCK); - ASSERT_GE(pipe, 0); + EXPECT_GE(pipe, 0); auto listener = std::make_shared(); auto myRunner = EventRunner::Create(false); diff --git a/ohos.build b/ohos.build index fa4f3cb8c9..a189b8a533 100644 --- a/ohos.build +++ b/ohos.build @@ -1,95 +1,115 @@ -{ - "parts": { - "appexecfwk_standard": { - "inner_kits": [ - { - "header": { - "header_base": "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base/include", - "header_files": [ - "ability_info.h", - "appexecfwk_errors.h", - "application_info.h", - "element_name.h", - "bundle_info.h" - ] - }, - "name": "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base:appexecfwk_base" - }, - { - "header": { - "header_base": "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include", - "header_files": [ - "appmgr/app_mgr_client.h", - "appmgr/iapp_state_callback.h", - "appmgr/app_state_callback_host.h", - "appmgr/app_mgr_constants.h", - "bundlemgr/bundle_installer_interface.h", - "bundlemgr/bundle_mgr_interface.h", - "bundlemgr/bundle_status_callback_interface.h", - "bundlemgr/clean_cache_callback_interface.h", - "bundlemgr/status_receiver_interface.h", - "appmgr/app_process_data.h" - ] - }, - "name": "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core:appexecfwk_core" - }, - { - "header": { - "header_base": "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler/include", - "header_files": [ - "event_handler_errors.h", - "event_handler.h", - "event_queue.h", - "event_runner.h", - "inner_event.h", - "file_descriptor_listener.h", - "native_implement_eventhandler.h" - ] - }, - "name": "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler:libeventhandler" - }, - { - "header": { - "header_base": "//foundation/appexecfwk/standard/interfaces/innerkits/eventhandler_native/eventhandler", - "header_files": [ - "native_interface_eventhandler.h" - ] - }, - "name": "//foundation/appexecfwk/standard/interfaces/innerkits/eventhandler_native:eventhandler_native" - } - ], - "module_list": [ - "//foundation/appexecfwk/standard/common:common_target", - "//foundation/appexecfwk/standard/services:services_target", - "//foundation/appexecfwk/standard/tools:tools_target", - "//foundation/appexecfwk/standard/interfaces/innerkits:innerkits_target", - "//foundation/appexecfwk/standard/kits:appkit_native", - "//foundation/appexecfwk/standard/kits:appexec", - "//foundation/appexecfwk/standard/sa_profile:appexecfwk_sa_profile", - "//foundation/appexecfwk/standard/sa_profile:foundation.rc", - "//foundation/appexecfwk/standard/test/resource/amssystemtestability/abilitySrc:ams_system_test_app", - "//foundation/appexecfwk/standard/kits/appkit/napi:napi_packages" - ], - "test_list": [ - "//foundation/appexecfwk/standard/kits/appkit/native/test:unittest", - "//foundation/appexecfwk/standard/kits/appkit/test:moduletest", - "//foundation/appexecfwk/standard/services/test:moduletest", - "//foundation/appexecfwk/standard/services/bundlemgr/test:unittest", - "//foundation/appexecfwk/standard/services/appmgr/test:unittest", - "//foundation/appexecfwk/standard/test/systemtest:systemtest", - "//foundation/appexecfwk/standard/tools/test:moduletest", - "//foundation/appexecfwk/standard/tools/test:unittest", - "//foundation/appexecfwk/standard/libs/libeventhandler/test:unittest", - "//foundation/appexecfwk/standard/libs/test:moduletest", - "//foundation/appexecfwk/standard/interfaces/innerkits/task_dispatcher/test:unittest", - "//foundation/appexecfwk/standard/interfaces/innerkits/test:moduletest" - ], - - "variants": [ - "phone", - "ivi" - ] - } - }, - "subsystem": "appexecfwk" -} +{ + "aosp_java_api_allowlist": "//foundation/appexecfwk/adapter/appexecfwk-java-aosp-apis.txt", + "aosp_cxx_api_allowlist": "//foundation/appexecfwk/adapter/appexecfwk_cxx_api_allowlist.txt", + "parts": { + "appexecfwk_standard": { + "inner_kits": [ + { + "header": { + "header_base": "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base/include", + "header_files": [ + "ability_info.h", + "appexecfwk_errors.h", + "application_info.h", + "element_name.h", + "bundle_info.h", + "form_constants.h", + "form_js_info.h" + ] + }, + "name": "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base:appexecfwk_base" + }, + { + "header": { + "header_base": "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include", + "header_files": [ + "appmgr/app_mgr_client.h", + "appmgr/iapp_state_callback.h", + "appmgr/app_state_callback_host.h", + "appmgr/app_mgr_constants.h", + "bundlemgr/bundle_installer_interface.h", + "bundlemgr/bundle_mgr_interface.h", + "bundlemgr/bundle_status_callback_interface.h", + "bundlemgr/clean_cache_callback_interface.h", + "bundlemgr/status_receiver_interface.h", + "appmgr/app_process_data.h", + "formmgr/form_mgr_interface.h" + + ] + }, + "name": "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core:appexecfwk_core" + }, + { + "header": { + "header_base": "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler/include", + "header_files": [ + "event_handler_errors.h", + "event_handler.h", + "event_queue.h", + "event_runner.h", + "inner_event.h", + "file_descriptor_listener.h", + "native_implement_eventhandler.h" + ] + }, + "name": "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler:libeventhandler" + }, + { + "header": { + "header_base": "//foundation/appexecfwk/standard/interfaces/innerkits/eventhandler_native/eventhandler", + "header_files": [ + "native_interface_eventhandler.h" + ] + }, + "name": "//foundation/appexecfwk/standard/interfaces/innerkits/eventhandler_native:eventhandler_native" + }, + { + "header": { + "header_base": "//foundation/appexecfwk/standard/interfaces/innerkits/fmskit/native/include", + "header_files": [ + "form_callback_interface.h", + "form_host_client.h", + "form_mgr.h" + ] + }, + "name": "//foundation/appexecfwk/standard/interfaces/innerkits/fmskit:fmskit_native" + } + ], + "module_list": [ + "//foundation/appexecfwk/standard/common:common_target", + "//foundation/appexecfwk/standard/services:services_target", + "//foundation/appexecfwk/standard/tools:tools_target", + "//foundation/appexecfwk/standard/interfaces/innerkits:innerkits_target", + "//foundation/appexecfwk/standard/kits:appkit_native", + "//foundation/appexecfwk/standard/kits:appexec", + "//foundation/appexecfwk/standard/sa_profile:appexecfwk_sa_profile", + "//foundation/appexecfwk/standard/sa_profile:foundation.rc", + "//foundation/appexecfwk/standard/test/resource/amssystemtestability/abilitySrc:ams_system_test_app", + "//foundation/appexecfwk/standard/test/resource/bmssystemtestability/abilitySrc:bms_system_test_app", + "//foundation/appexecfwk/standard/kits/appkit/napi:napi_packages" + ], + "test_list": [ + "//foundation/appexecfwk/standard/kits/appkit/native/test:unittest", + "//foundation/appexecfwk/standard/kits/appkit/test:moduletest", + "//foundation/appexecfwk/standard/services/test:moduletest", + "//foundation/appexecfwk/standard/services/bundlemgr/test:unittest", + "//foundation/appexecfwk/standard/services/appmgr/test:unittest", + "//foundation/appexecfwk/standard/services/formmgr/test:unittest", + "//foundation/appexecfwk/standard/test/systemtest:systemtest", + "//foundation/appexecfwk/standard/tools/test:moduletest", + "//foundation/appexecfwk/standard/tools/test:systemtest", + "//foundation/appexecfwk/standard/tools/test:unittest", + "//foundation/appexecfwk/standard/libs/libeventhandler/test:unittest", + "//foundation/appexecfwk/standard/libs/test:moduletest", + "//foundation/appexecfwk/standard/interfaces/innerkits/task_dispatcher/test:unittest", + "//foundation/appexecfwk/standard/interfaces/innerkits/test:moduletest" + ], + + "variants": [ + "phone", + "ivi" + ] + } + }, + "subsystem": "appexecfwk" +} diff --git a/sa_profile/403.xml b/sa_profile/403.xml new file mode 100644 index 0000000000..7176a66dd1 --- /dev/null +++ b/sa_profile/403.xml @@ -0,0 +1,27 @@ + + + + foundation + + 403 + /system/lib64/libfms.z.so + + + true + false + 1 + + diff --git a/sa_profile/BUILD.gn b/sa_profile/BUILD.gn index 56173ba8a6..180d06646b 100644 --- a/sa_profile/BUILD.gn +++ b/sa_profile/BUILD.gn @@ -17,6 +17,7 @@ import("//build/ohos/sa_profile/sa_profile.gni") ohos_sa_profile("appexecfwk_sa_profile") { sources = [ "401.xml", + "403.xml", "501.xml", ] diff --git a/sa_profile/foundation.cfg b/sa_profile/foundation.cfg index 67a08206cc..bc7d4b9cfe 100644 --- a/sa_profile/foundation.cfg +++ b/sa_profile/foundation.cfg @@ -2,22 +2,52 @@ "jobs" : [{ "name" : "init", "cmds" : [ + "mkdir /dev/memcg", + "mount cgroup none /dev/memcg memory", + "chown system system /dev/memcg", + "chown system system /dev/memcg/tasks", + "chown system system /dev/memcg/memory.oom_control", + "chown system system /dev/memcg/cgroup.event_control", + "chown system system /dev/memcg/memory.pressure_level", + "chmod 0755 /dev/memcg", + "chmod 0755 /dev/memcg/tasks", + "chmod 0755 /dev/memcg/memory.oom_control", + "chmod 0755 /dev/memcg/cgroup.event_control", + "chmod 0755 /dev/memcg/memory.pressure_level", + "mkdir /dev/cpuset", + "mount cgroup none /dev/cpuset cpuset", + "mkdir /dev/cpuset/background", + "chown system system /dev/cpuset", + "chown system system /dev/cpuset/tasks", + "chown system system /dev/cpuset/background", + "chown system system /dev/cpuset/background/tasks", + "chmod 0755 /dev/cpuset", + "chmod 0755 /dev/cpuset/tasks", + "chmod 0755 /dev/cpuset/background", + "chmod 0755 /dev/cpuset/background/tasks", + "write /dev/cpuset/background/cpuset.cpus 0", + "mkdir /dev/cpuctl", + "mount cgroup none /dev/cpuctl cpu", "mkdir /dev/cpuctl/background", + "chown system system /dev/cpuctl", + "chown system system /dev/cpuctl/tasks", "chown system system /dev/cpuctl/background", + "chown system system /dev/cpuctl/background/tasks", + "chmod 0755 /dev/cpuctl", + "chmod 0755 /dev/cpuctl/tasks", "chmod 0755 /dev/cpuctl/background", "chmod 0755 /dev/cpuctl/background/tasks", "write /dev/cpuctl/background/cpu.shares 512", - "write /dev/cpuset/background/cpus 0", "mkdir /dev/freezer", - "chown system system /dev/freezer", - "chmod 0755 /dev/freezer", "mount cgroup none /dev/freezer freezer", "mkdir /dev/freezer/frozen", "mkdir /dev/freezer/thawed", + "chown system system /dev/freezer", "chown system system /dev/freezer/frozen", "chown system system /dev/freezer/frozen/tasks", "chown system system /dev/freezer/thawed", "chown system system /dev/freezer/thawed/tasks", + "chmod 0755 /dev/freezer", "chmod 0755 /dev/freezer/frozen", "chmod 0755 /dev/freezer/frozen/tasks", "chmod 0755 /dev/freezer/thawed", diff --git a/sa_profile/foundation.rc b/sa_profile/foundation.rc index 805d83e87d..69909f50ff 100755 --- a/sa_profile/foundation.rc +++ b/sa_profile/foundation.rc @@ -15,9 +15,10 @@ on init # cpuctl subsystem # set background cpuctl mkdir /dev/cpuctl/background - chown system system /dev/cpuctl/background chmod 0755 /dev/cpuctl/background chmod 0755 /dev/cpuctl/background/tasks + chown system system /dev/cpuctl/background + chown system system /dev/cpuctl/background/tasks write /dev/cpuctl/background/cpu.shares 512 # cpuset subsystem diff --git a/services/BUILD.gn b/services/BUILD.gn index 03d564f616..ae099a3474 100644 --- a/services/BUILD.gn +++ b/services/BUILD.gn @@ -15,5 +15,6 @@ group("services_target") { deps = [ "appmgr:ams_target", "bundlemgr:bms_target", + "formmgr:fms_target", ] } diff --git a/services/appmgr/BUILD.gn b/services/appmgr/BUILD.gn index 2915693ea5..116cb2e063 100644 --- a/services/appmgr/BUILD.gn +++ b/services/appmgr/BUILD.gn @@ -62,7 +62,11 @@ ohos_executable("lmks") { } ohos_prebuilt_etc("lmks.rc") { - source = "lmks.rc" + if (use_musl) { + source = "lmks.cfg" + } else { + source = "lmks.rc" + } relative_install_dir = "init" subsystem_name = "appexecfwk" part_name = "appexecfwk_standard" diff --git a/services/appmgr/include/ability_running_record.h b/services/appmgr/include/ability_running_record.h index 5188c25211..630a806edf 100644 --- a/services/appmgr/include/ability_running_record.h +++ b/services/appmgr/include/ability_running_record.h @@ -154,7 +154,7 @@ private: int32_t visibility_ = 0; int32_t perceptibility_ = 0; int32_t connectionState_ = 0; - int64_t eventId_; + int64_t eventId_ = 0; AbilityState state_ = AbilityState::ABILITY_STATE_BEGIN; std::shared_ptr info_; sptr token_; diff --git a/services/appmgr/include/app_mgr_service_inner.h b/services/appmgr/include/app_mgr_service_inner.h index 18d6d27549..d2694287da 100644 --- a/services/appmgr/include/app_mgr_service_inner.h +++ b/services/appmgr/include/app_mgr_service_inner.h @@ -450,6 +450,14 @@ public: */ int CompelVerifyPermission(const std::string &permission, int pid, int uid, std::string &message); + /** + * SuspendApplication, Application state changed. + * + * @param appRecord, the app information. + * @param state, the app state. + */ + void OnAppStateChanged(const std::shared_ptr &appRecord, const ApplicationState state); + private: /** * StartAbility, load the ability that needed to be started(Start on the basis of the original process). @@ -513,14 +521,6 @@ private: std::shared_ptr GetAbilityRunningRecordByAbilityToken( const sptr &abilityToken) const; - /** - * SuspendApplication, Application state changed. - * - * @param appRecord, the app information. - * @param state, the app state. - */ - void OnAppStateChanged(const std::shared_ptr &appRecord, const ApplicationState state); - /** * StartProcess, load the ability that needed to be started(Start on a new boot process). * diff --git a/services/appmgr/include/app_running_manager.h b/services/appmgr/include/app_running_manager.h index 3f5c4a18f8..235ed77ab9 100644 --- a/services/appmgr/include/app_running_manager.h +++ b/services/appmgr/include/app_running_manager.h @@ -126,6 +126,8 @@ public: void TerminateAbility(const sptr &token); bool GetPidsByBundleName(const std::string &bundleName, std::list &pids); + std::shared_ptr GetTerminatingAppRunningRecord(const sptr &abilityToken); + private: std::shared_ptr GetAbilityRunningRecord(const int64_t eventId); diff --git a/services/appmgr/include/app_running_record.h b/services/appmgr/include/app_running_record.h index bbc2cb3f72..a08cf5d9ad 100644 --- a/services/appmgr/include/app_running_record.h +++ b/services/appmgr/include/app_running_record.h @@ -40,7 +40,7 @@ namespace AppExecFwk { class AbilityRunningRecord; class AppMgrServiceInner; -class AppRunningRecord { +class AppRunningRecord : public std::enable_shared_from_this { public: AppRunningRecord( const std::shared_ptr &info, const int32_t recordId, const std::string &processName); @@ -273,6 +273,8 @@ public: */ std::shared_ptr GetAbilityRunningRecordByToken(const sptr &token) const; + std::shared_ptr GetAbilityByTerminateLists(const sptr &token) const; + /** * UpdateAbilityState, update the ability status. * @@ -407,6 +409,7 @@ private: int64_t eventId_ = 0; // List of abilities running in the process std::map, std::shared_ptr> abilities_; + std::map, std::shared_ptr> terminateAbilitys_; std::list> foregroundingAbilityTokens_; std::weak_ptr appMgrServiceInner_; sptr appDeathRecipient_; diff --git a/services/appmgr/include/cgroup_manager.h b/services/appmgr/include/cgroup_manager.h index 71162d501c..ea8d773c9c 100644 --- a/services/appmgr/include/cgroup_manager.h +++ b/services/appmgr/include/cgroup_manager.h @@ -74,12 +74,12 @@ public: private: std::shared_ptr eventHandler_; - int cpusetTasksFds_[SCHED_POLICY_CPU_MAX]; - int cpuctlTasksFds_[SCHED_POLICY_CPU_MAX]; - int freezerTasksFds_[SCHED_POLICY_FREEZER_MAX]; - int memoryEventControlFd_; - int memoryEventFds_[LOW_MEMORY_LEVEL_MAX]; - int memoryPressureFds_[LOW_MEMORY_LEVEL_MAX]; + int cpusetTasksFds_[SCHED_POLICY_CPU_MAX] = {-1}; + int cpuctlTasksFds_[SCHED_POLICY_CPU_MAX] = {-1}; + int freezerTasksFds_[SCHED_POLICY_FREEZER_MAX] = {-1}; + int memoryEventControlFd_ = -1; + int memoryEventFds_[LOW_MEMORY_LEVEL_MAX] = {-1}; + int memoryPressureFds_[LOW_MEMORY_LEVEL_MAX] = {-1}; bool RegisterLowMemoryMonitor(const int memoryEventFds[LOW_MEMORY_LEVEL_MAX], const int memoryPressureFds[LOW_MEMORY_LEVEL_MAX], const int memoryEventControlFd, const LowMemoryLevel level, diff --git a/services/appmgr/include/process_optimizer.h b/services/appmgr/include/process_optimizer.h index 8e7b2f8a20..18f446769e 100644 --- a/services/appmgr/include/process_optimizer.h +++ b/services/appmgr/include/process_optimizer.h @@ -40,7 +40,8 @@ public: using CgroupManagerPtr = std::shared_ptr; using LmksClientPtr = std::shared_ptr; - static constexpr int APP_SUSPEND_TIMEOUT_DEFAULT = 5000; // in milliseconds + static constexpr int APP_SUSPEND_TIMEOUT_DEFAULT = 5000; // in milliseconds + static constexpr int APP_SUSPEND_TIMEOUT_MAX = 30 * 1000; // in milliseconds public: ProcessOptimizer(const LmksClientPtr &lmksClient = nullptr, int suspendTimeout = APP_SUSPEND_TIMEOUT_DEFAULT); diff --git a/services/appmgr/lmks.cfg b/services/appmgr/lmks.cfg new file mode 100755 index 0000000000..e02a386509 --- /dev/null +++ b/services/appmgr/lmks.cfg @@ -0,0 +1,17 @@ +{ + "jobs" : [{ + "name" : "late-fs", + "cmds" : [ + "start lmks" + ] + } + ], + "services" : [{ + "name" : "lmks", + "path" : ["/system/bin/lmks"], + "importance" : -20, + "uid" : "root", + "gid" : ["root"] + } + ] +} diff --git a/services/appmgr/src/app_mgr_service_inner.cpp b/services/appmgr/src/app_mgr_service_inner.cpp index 29fb059ca3..4c4ffcd736 100644 --- a/services/appmgr/src/app_mgr_service_inner.cpp +++ b/services/appmgr/src/app_mgr_service_inner.cpp @@ -748,11 +748,13 @@ void AppMgrServiceInner::AbilityTerminated(const sptr &token) APP_LOGE("token is null!"); return; } - auto appRecord = GetAppRunningRecordByAbilityToken(token); + + auto appRecord = appRunningManager_->GetTerminatingAppRunningRecord(token); if (!appRecord) { APP_LOGE("app is not exist!"); return; } + appRecord->AbilityTerminated(token); APP_LOGD("end"); } @@ -782,6 +784,7 @@ void AppMgrServiceInner::OnAppStateChanged( processData.processName = appRecord->GetProcessName(); processData.pid = appRecord->GetPriorityObject()->GetPid(); processData.appState = state; + processData.uid = appRecord->GetUid(); callback->OnAppStateChanged(processData); } } diff --git a/services/appmgr/src/app_running_manager.cpp b/services/appmgr/src/app_running_manager.cpp index c42cdbf13f..e2aa28e0b9 100644 --- a/services/appmgr/src/app_running_manager.cpp +++ b/services/appmgr/src/app_running_manager.cpp @@ -198,7 +198,7 @@ void AppRunningManager::HandleTerminateTimeOut(int64_t eventId) return; } auto abilityToken = abilityRecord->GetToken(); - auto appRecord = GetAppRunningRecordByAbilityToken(abilityToken); + auto appRecord = GetTerminatingAppRunningRecord(abilityToken); if (!appRecord) { APP_LOGE("%{public}s, appRecord is nullptr", __func__); return; @@ -207,6 +207,19 @@ void AppRunningManager::HandleTerminateTimeOut(int64_t eventId) APP_LOGI("%{public}s, end", __func__); } +std::shared_ptr AppRunningManager::GetTerminatingAppRunningRecord( + const sptr &abilityToken) +{ + std::lock_guard guard(lock_); + for (const auto &item : appRunningRecordMap_) { + const auto &appRecord = item.second; + if (appRecord && appRecord->GetAbilityByTerminateLists(abilityToken)) { + return appRecord; + } + } + return nullptr; +} + std::shared_ptr AppRunningManager::GetAbilityRunningRecord(const int64_t eventId) { APP_LOGI("%{public}s, called", __func__); @@ -246,6 +259,10 @@ void AppRunningManager::HandleAbilityAttachTimeOut(const sptr &to return; } + if (appRecord->IsLastAbilityRecord(token)) { + appRecord->SetTerminating(); + } + appRecord->TerminateAbility(token, true); } void AppRunningManager::TerminateAbility(const sptr &token) diff --git a/services/appmgr/src/app_running_record.cpp b/services/appmgr/src/app_running_record.cpp index 1219d72cca..d6937a2642 100644 --- a/services/appmgr/src/app_running_record.cpp +++ b/services/appmgr/src/app_running_record.cpp @@ -125,7 +125,17 @@ std::shared_ptr AppRunningRecord::GetAbilityRunningRecord( const auto &iter = std::find_if(abilities_.begin(), abilities_.end(), [eventId](const auto &pair) { return pair.second->GetEventId() == eventId; }); - return ((iter == abilities_.end()) ? nullptr : iter->second); + if (iter != abilities_.end()) { + return iter->second; + } + + const auto &finder = std::find_if(terminateAbilitys_.begin(), + terminateAbilitys_.end(), + [eventId](const auto &pair) { return pair.second->GetEventId() == eventId; }); + if (finder != terminateAbilitys_.end()) { + return finder->second; + } + return nullptr; } void AppRunningRecord::ClearAbility(const std::shared_ptr &record) @@ -248,6 +258,20 @@ std::shared_ptr AppRunningRecord::GetAbilityRunningRecordB return nullptr; } +std::shared_ptr AppRunningRecord::GetAbilityByTerminateLists( + const sptr &token) const +{ + if (!token) { + APP_LOGE("token is null"); + return nullptr; + } + const auto &iter = terminateAbilitys_.find(token); + if (iter != terminateAbilitys_.end()) { + return iter->second; + } + return nullptr; +} + void AppRunningRecord::UpdateAbilityState(const sptr &token, const AbilityState state) { APP_LOGD("state is :%{public}d", static_cast(state)); @@ -293,6 +317,10 @@ void AppRunningRecord::AbilityForeground(const std::shared_ptrOnAppStateChanged(shared_from_this(), curState_); + } } else { APP_LOGW("wrong application state"); } @@ -359,6 +387,9 @@ void AppRunningRecord::TerminateAbility(const sptr &token, const return; } + terminateAbilitys_.emplace(token, abilityRecord); + abilities_.erase(token); + SendEvent( AMSEventHandler::TERMINATE_ABILITY_TIMEOUT_MSG, AMSEventHandler::TERMINATE_ABILITY_TIMEOUT, abilityRecord); @@ -389,15 +420,15 @@ void AppRunningRecord::AbilityTerminated(const sptr &token) APP_LOGE("eventHandler_ is nullptr"); return; } - - auto abilityRecord = GetAbilityRunningRecordByToken(token); + + auto abilityRecord = GetAbilityByTerminateLists(token); if (!abilityRecord) { APP_LOGE("AppRunningRecord::AbilityTerminated can not find ability record"); return; } - + eventHandler_->RemoveEvent(AMSEventHandler::TERMINATE_ABILITY_TIMEOUT_MSG, abilityRecord->GetEventId()); - abilities_.erase(token); + terminateAbilitys_.erase(token); if (abilities_.empty()) { ScheduleTerminate(); } diff --git a/services/appmgr/src/cgroup_manager.cpp b/services/appmgr/src/cgroup_manager.cpp index 56773b0af6..bf563c2659 100644 --- a/services/appmgr/src/cgroup_manager.cpp +++ b/services/appmgr/src/cgroup_manager.cpp @@ -13,7 +13,6 @@ * limitations under the License. */ #include "cgroup_manager.h" -#include #include #include #include @@ -115,17 +114,8 @@ int WriteValue(int fd, int v, bool newLine = true) } // namespace -CgroupManager::CgroupManager() : memoryEventControlFd_(-1) -{ - for (int i = 0; i < SCHED_POLICY_MAX; ++i) { - cpusetTasksFds_[i] = -1; - } - - for (int i = 0; i < LOW_MEMORY_LEVEL_MAX; ++i) { - memoryEventFds_[i] = -1; - memoryPressureFds_[i] = -1; - } -} +CgroupManager::CgroupManager() +{} CgroupManager::~CgroupManager() { @@ -145,7 +135,7 @@ CgroupManager::~CgroupManager() close(memoryEventControlFd_); } - for (int i = 0; i < SCHED_POLICY_MAX; ++i) { + for (int i = 0; i < SCHED_POLICY_CPU_MAX; ++i) { if (cpusetTasksFds_[i] >= 0) { close(cpusetTasksFds_[i]); } @@ -166,12 +156,12 @@ bool CgroupManager::Init() return false; } - UniqueFd cpusetTasksFds[SCHED_POLICY_MAX]; + UniqueFd cpusetTasksFds[SCHED_POLICY_CPU_MAX]; if (!InitCpusetTasksFds(cpusetTasksFds)) { return false; } - UniqueFd cpuctlTasksFds[SCHED_POLICY_MAX]; + UniqueFd cpuctlTasksFds[SCHED_POLICY_CPU_MAX]; if (!InitCpuctlTasksFds(cpuctlTasksFds)) { return false; } @@ -357,7 +347,12 @@ void CgroupManager::OnReadable(int32_t fd) return false; } if (count < 1) { - APP_LOGW("%{public}s(%{public}d) invalid eventfd count %{public}" PRIu64 ".", __func__, __LINE__, count); +#if BINDER_IPC_32BIT + APP_LOGW("%{public}s(%{public}d) invalid eventfd count %{public}llu.", __func__, __LINE__, count); +#else + APP_LOGW("%{public}s(%{public}d) invalid eventfd count %{public}lu.", __func__, __LINE__, count); +#endif + return false; } APP_LOGW( diff --git a/services/appmgr/src/lmks/lmks_server.cpp b/services/appmgr/src/lmks/lmks_server.cpp index 59a33fbe3a..0b89cd3d6b 100644 --- a/services/appmgr/src/lmks/lmks_server.cpp +++ b/services/appmgr/src/lmks/lmks_server.cpp @@ -28,25 +28,28 @@ namespace OHOS { namespace LMKS { namespace { +#ifdef __MUSL__ +const std::string LMKS_SOCKET_NAME = "/dev/unix/socket/lmks"; +#else const std::string LMKS_SOCKET_NAME = "/dev/socket/lmks"; -constexpr uint32_t LISTEN_CLIENTS = 5; // 5: max num of clients -constexpr uint32_t WAIT_DELAY_US = 100 * 1000; // 100ms +#endif +constexpr uint32_t LISTEN_CLIENTS = 5; // 5: max num of clients +constexpr uint32_t WAIT_DELAY_US = 100 * 1000; // 100ms constexpr int LMKS_CMD_TARGET = 0; constexpr int LMKS_CMD_PROCPRIO = 1; constexpr int LMKS_CMD_PROCREMOVE = 2; constexpr int LMKS_CMD_PROCPURGE = 3; -constexpr uid_t LMKS_ID_ROOT = 0; // chown owner -constexpr gid_t LMKS_ID_SYSTEM = 1000; // chown group -constexpr mode_t SOCKET_PERM = 0666; // root system can read and write lmks socket +constexpr uid_t LMKS_ID_ROOT = 0; // chown owner +constexpr gid_t LMKS_ID_SYSTEM = 1000; // chown group +constexpr mode_t SOCKET_PERM = 0666; // root system can read and write lmks socket constexpr struct timeval SOCKET_TIMEOUT = {5, 0}; // 5, 0: { 5 sec, 0 msec } for timeout } // namespace using namespace OHOS::HiviewDFX; static constexpr HiLogLabel LABEL = {LOG_CORE, 0, "LmksServer"}; -LmksServer::LmksServer() - : isStart_(false), socketFd_(-1), socketAddrLen_(0), lmksUtils_(nullptr) +LmksServer::LmksServer() : isStart_(false), socketFd_(-1), socketAddrLen_(0), lmksUtils_(nullptr) { memset_s(&socketAddr_, sizeof(socketAddr_), 0, sizeof(socketAddr_)); } @@ -59,7 +62,7 @@ LmksServer::~LmksServer() void LmksServer::StartServer() { if (isStart_) { - HiLog::Error(LABEL, "Lmks server has started."); + HiLog::Error(LABEL, "Lmks server has started."); return; } @@ -81,7 +84,7 @@ void LmksServer::StartServer() } LMKS_PACKET cmds; - int len = RecvSocketMessage(connectFd, (void*)cmds, sizeof(cmds)); + int len = RecvSocketMessage(connectFd, (void *)cmds, sizeof(cmds)); if (len <= 0) { HiLog::Error(LABEL, "Failed to read socket message, len %{public}d", len); close(connectFd); @@ -114,7 +117,7 @@ int LmksServer::RegisterSocket() } if (strcpy_s(socketAddr_.sun_path, sizeof(socketAddr_.sun_path), LMKS_SOCKET_NAME.c_str()) != 0) { - HiLog::Error(LABEL, "Failed to snprint32_tf_s socket addr, err %{public}s", strerror(errno)); + HiLog::Error(LABEL, "Failed to snprint32_tf_s socket addr, err %{public}s", strerror(errno)); return (-errno); } @@ -160,7 +163,8 @@ int LmksServer::RegisterSocket() return 0; } -int LmksServer::WaitConnection() { +int LmksServer::WaitConnection() +{ if (socketFd_ < 0) { HiLog::Error(LABEL, "lmks server not register."); return -1; @@ -168,6 +172,7 @@ int LmksServer::WaitConnection() { struct sockaddr_un clientAddr; socklen_t clientLen = sizeof(clientAddr); + if (memset_s(&clientAddr, clientLen, 0, clientLen) != 0) { HiLog::Warn(LABEL, "Failed to memset client addr, err %{public}s", strerror(errno)); } @@ -181,6 +186,7 @@ int LmksServer::WaitConnection() { if ((setsockopt(connFd, SOL_SOCKET, SO_RCVTIMEO, &SOCKET_TIMEOUT, sizeof(SOCKET_TIMEOUT)) < 0) || (setsockopt(connFd, SOL_SOCKET, SO_SNDTIMEO, &SOCKET_TIMEOUT, sizeof(SOCKET_TIMEOUT)) < 0)) { HiLog::Error(LABEL, "Failed to set opt of Connection %d, err %{public}s", connFd, strerror(errno)); + close(connFd); return (-errno); } @@ -236,7 +242,8 @@ int LmksServer::RecvSocketMessage(int connectFd, void *buf, int len) void LmksServer::ProcessMessage(int connectFd, LMKS_PACKET cmds, int len) { if (!isStart_ || (lmksUtils_ == nullptr)) { - HiLog::Error(LABEL, "Lmks server not start isStart_ %{public}d lmksUtils_%{public}p", isStart_, lmksUtils_.get()); + HiLog::Error( + LABEL, "Lmks server not start isStart_ %{public}d lmksUtils_%{public}p", isStart_, lmksUtils_.get()); close(connectFd); return; } @@ -250,27 +257,27 @@ void LmksServer::ProcessMessage(int connectFd, LMKS_PACKET cmds, int len) int ret = -1; pid_t pid = 0; - switch(cmds[0]){ - case LMKS_CMD_TARGET: - HiLog::Info(LABEL, "ProcessMessage LMKS_CMD_TARGET "); - break; - case LMKS_CMD_PROCPRIO: - HiLog::Info(LABEL, "ProcessMessage LMKS_CMD_PROCPRIO"); - break; - case LMKS_CMD_PROCREMOVE: - HiLog::Info(LABEL, "ProcessMessage LMKS_CMD_PROCREMOVE"); - pid = cmds[1]; - ret = lmksUtils_->RemoveProcess(pid); - if (SendSocketMessage(connectFd, &ret, sizeof(ret)) <= 0){ - HiLog::Error(LABEL, "Failed to return the result of remove process"); - } - break; - case LMKS_CMD_PROCPURGE: - HiLog::Info(LABEL, "ProcessMessage LMKS_CMD_PROCPURGE"); - break; - default: - HiLog::Error(LABEL, "Wrong cmd %d", cmds[0]); - break; + switch (cmds[0]) { + case LMKS_CMD_TARGET: + HiLog::Info(LABEL, "ProcessMessage LMKS_CMD_TARGET "); + break; + case LMKS_CMD_PROCPRIO: + HiLog::Info(LABEL, "ProcessMessage LMKS_CMD_PROCPRIO"); + break; + case LMKS_CMD_PROCREMOVE: + HiLog::Info(LABEL, "ProcessMessage LMKS_CMD_PROCREMOVE"); + pid = cmds[1]; + ret = lmksUtils_->RemoveProcess(pid); + if (SendSocketMessage(connectFd, &ret, sizeof(ret)) <= 0) { + HiLog::Error(LABEL, "Failed to return the result of remove process"); + } + break; + case LMKS_CMD_PROCPURGE: + HiLog::Info(LABEL, "ProcessMessage LMKS_CMD_PROCPURGE"); + break; + default: + HiLog::Error(LABEL, "Wrong cmd %d", cmds[0]); + break; } // close connect fd. diff --git a/services/appmgr/src/lmks/lmks_utils.cpp b/services/appmgr/src/lmks/lmks_utils.cpp index 1066ee8d8d..1c373b0807 100644 --- a/services/appmgr/src/lmks/lmks_utils.cpp +++ b/services/appmgr/src/lmks/lmks_utils.cpp @@ -60,7 +60,8 @@ int LmksUtils::RemoveProcess(pid_t pid) HiLog::Warn(LABEL, "kill pid %{public}d err %{public}s", pid, strerror(errno)); return (-errno); } else { - HiLog::Info(LABEL, "kill pid %{public}d success, name %{public}s size %{public}d", pid, procName.c_str(), procSize); + HiLog::Info( + LABEL, "kill pid %{public}d success, name %{public}s size %{public}d", pid, procName.c_str(), procSize); } return 0; @@ -103,11 +104,11 @@ std::string LmksUtils::GetProcName(pid_t pid) ret = ReadAll(fd, line, sizeof(line) - 1); if (ret < 0) { - close(fd); + close(fd); return name; } - if (strlen(line) != 0) { + if (strlen(line) < PROC_LINE_MAX && strlen(line) != 0) { name = line; } else { HiLog::Error(LABEL, "cmdline no data"); @@ -159,8 +160,7 @@ int LmksUtils::GetProcSize(pid_t pid) return -1; } - if ((strlen(line) != 0) && - (sscanf_s(line, "%d %d ", &total, &rss) > 0)) { + if ((strlen(line) < PROC_LINE_MAX && strlen(line) != 0) && (sscanf_s(line, "%d %d ", &total, &rss) > 0)) { HiLog::Info(LABEL, "pid %{public}d total %{public}d rss %{public}d", pid, total, rss); } else { HiLog::Error(LABEL, "strlen or sscanf_s err %{public}s", strerror(errno)); @@ -193,5 +193,5 @@ ssize_t LmksUtils::ReadAll(int fd, char *buf, size_t maxLen) return ret; } -} // namespace AppExecFwk +} // namespace LMKS } // namespace OHOS diff --git a/services/appmgr/src/process_optimizer.cpp b/services/appmgr/src/process_optimizer.cpp index da02f7a07a..96a9340a6e 100644 --- a/services/appmgr/src/process_optimizer.cpp +++ b/services/appmgr/src/process_optimizer.cpp @@ -700,7 +700,7 @@ void ProcessOptimizer::SetAppFreezingTime(int time) { APP_LOGE("%{public}s input second time:[%{public}d]", __func__, time); - if (time < 0) { + if (time > APP_SUSPEND_TIMEOUT_MAX && time < 0) { APP_LOGE("%{public}s input time error.", __func__); return; } diff --git a/services/appmgr/test/mock/include/mock_bundle_manager.h b/services/appmgr/test/mock/include/mock_bundle_manager.h index 312d5f4182..4dfc90f987 100644 --- a/services/appmgr/test/mock/include/mock_bundle_manager.h +++ b/services/appmgr/test/mock/include/mock_bundle_manager.h @@ -60,6 +60,10 @@ public: { return true; }; + virtual bool QueryAbilityInfos(const Want &want, std::vector &abilityInfos) override + { + return true; + }; virtual bool GetBundleInfo(const std::string &bundleName, const BundleFlag flag, BundleInfo &bundleInfo) override { return true; @@ -174,6 +178,16 @@ public: { return nullptr; }; + virtual bool GetModuleUsageRecords( + const int32_t number, std::vector &moduleUsageRecords) override + { + return true; + } + virtual bool NotifyActivityLifeStatus( + const std::string &bundleName, const std::string &abilityName, const int64_t launchTime) override + { + return true; + } }; class BundleMgrStub : public IRemoteStub { @@ -214,6 +228,10 @@ public: { return true; }; + virtual bool QueryAbilityInfos(const Want &want, std::vector &abilityInfos) override + { + return true; + }; virtual bool GetBundleInfo(const std::string &bundleName, const BundleFlag flag, BundleInfo &bundleInfo) override; virtual bool GetBundleInfos(const BundleFlag flag, std::vector &bundleInfos) override { @@ -328,7 +346,8 @@ public: { return true; } - virtual bool GetFormsInfoByModule(const std::string &bundleName, const std::string &moduleName, std::vector &formInfos) override + virtual bool GetFormsInfoByModule( + const std::string &bundleName, const std::string &moduleName, std::vector &formInfos) override { return true; } @@ -336,6 +355,15 @@ public: { return true; } + virtual bool GetModuleUsageRecords(const int32_t number, std::vector &moduleUsageRecords) override + { + return true; + } + virtual bool NotifyActivityLifeStatus( + const std::string &bundleName, const std::string &abilityName, const int64_t launchTime) override + { + return true; + } }; } // namespace AppExecFwk diff --git a/services/appmgr/test/mock/src/mock_bundle_manager.cpp b/services/appmgr/test/mock/src/mock_bundle_manager.cpp index 7befaaed6d..e9d6280bf9 100644 --- a/services/appmgr/test/mock/src/mock_bundle_manager.cpp +++ b/services/appmgr/test/mock/src/mock_bundle_manager.cpp @@ -28,6 +28,7 @@ bool BundleMgrProxy::QueryAbilityInfo(const AAFwk::Want &want, AbilityInfo &abil if (eleName.GetBundleName().empty()) { return false; } + abilityInfo.visible = true; abilityInfo.name = eleName.GetAbilityName(); abilityInfo.bundleName = eleName.GetBundleName(); abilityInfo.applicationName = "Helloworld"; @@ -70,6 +71,7 @@ bool BundleMgrService::QueryAbilityInfo(const AAFwk::Want &want, AbilityInfo &ab if (std::string::npos != elementName.GetBundleName().find("service")) { abilityInfo.type = AppExecFwk::AbilityType::SERVICE; } + abilityInfo.visible = true; abilityInfo.name = elementName.GetAbilityName(); abilityInfo.bundleName = elementName.GetBundleName(); abilityInfo.applicationName = elementName.GetBundleName(); diff --git a/services/appmgr/test/unittest/ams_ability_running_record_test/ams_ability_running_record_test.cpp b/services/appmgr/test/unittest/ams_ability_running_record_test/ams_ability_running_record_test.cpp index 6b45f6bb00..2b7a5ac48b 100644 --- a/services/appmgr/test/unittest/ams_ability_running_record_test/ams_ability_running_record_test.cpp +++ b/services/appmgr/test/unittest/ams_ability_running_record_test/ams_ability_running_record_test.cpp @@ -183,7 +183,7 @@ HWTEST_F(AmsAbilityRunningRecordTest, UpdateAbilityRunningRecord_001, TestSize.L sptr token = new MockAbilityToken(); auto abilityRunningRecord = appRunningRecord->AddAbility(token, abilityInfo); - ASSERT_TRUE(abilityRunningRecord != nullptr); + EXPECT_TRUE(abilityRunningRecord != nullptr); abilityRunningRecord->SetState(AbilityState::ABILITY_STATE_READY); appRunningRecord->SetState(ApplicationState::APP_STATE_READY); @@ -216,7 +216,7 @@ HWTEST_F(AmsAbilityRunningRecordTest, UpdateAbilityRunningRecord_002, TestSize.L sptr token = new MockAbilityToken(); auto abilityRunningRecord = appRunningRecord->AddAbility(token, abilityInfo); - ASSERT_TRUE(abilityRunningRecord != nullptr); + EXPECT_TRUE(abilityRunningRecord != nullptr); AbilityState state = abilityRunningRecord->GetState(); appRunningRecord->UpdateAbilityState(token, AbilityState::ABILITY_STATE_END); @@ -241,7 +241,7 @@ HWTEST_F(AmsAbilityRunningRecordTest, UpdateAbilityRunningRecord_003, TestSize.L abilityInfo->name = GetTestAbilityName(); sptr token = new MockAbilityToken(); auto abilityRunningRecord = appRunningRecord->AddAbility(token, abilityInfo); - ASSERT_TRUE(abilityRunningRecord != nullptr); + EXPECT_TRUE(abilityRunningRecord != nullptr); AbilityState state = abilityRunningRecord->GetState(); @@ -272,7 +272,7 @@ HWTEST_F(AmsAbilityRunningRecordTest, UpdateAbilityRunningRecord_004, TestSize.L sptr token2 = new MockAbilityToken(); auto abilityRunningRecord = appRunningRecord->AddAbility(token, abilityInfo); - ASSERT_TRUE(abilityRunningRecord != nullptr); + EXPECT_TRUE(abilityRunningRecord != nullptr); AbilityState state = abilityRunningRecord->GetState(); EXPECT_TRUE(appRunningRecord->GetAbilityRunningRecordByToken(token2) == nullptr); @@ -304,8 +304,8 @@ HWTEST_F(AmsAbilityRunningRecordTest, UpdateAbilityRunningRecord_005, TestSize.L auto abilityRunningRecord = appRunningRecord->AddAbility(token, abilityInfo); auto anotherAbilityRunningRecord = appRunningRecord->AddAbility(anotherToken, anotherAbilityInfo); - ASSERT_TRUE(abilityRunningRecord != nullptr); - ASSERT_TRUE(anotherAbilityRunningRecord != nullptr); + EXPECT_TRUE(abilityRunningRecord != nullptr); + EXPECT_TRUE(anotherAbilityRunningRecord != nullptr); anotherAbilityRunningRecord->SetState(AbilityState::ABILITY_STATE_BACKGROUND); appRunningRecord->SetState(ApplicationState::APP_STATE_BACKGROUND); @@ -373,7 +373,7 @@ HWTEST_F(AmsAbilityRunningRecordTest, UpdateAbilityRunningRecord_007, TestSize.L auto abilityRunningRecord = appRunningRecord->AddAbility(token, abilityInfo); auto anotherAbilityRunningRecord = appRunningRecord->AddAbility(anotherToken, anotherAbilityInfo); EXPECT_TRUE(abilityRunningRecord != nullptr); - ASSERT_TRUE(anotherAbilityRunningRecord != nullptr); + EXPECT_TRUE(anotherAbilityRunningRecord != nullptr); anotherAbilityRunningRecord->SetState(AbilityState::ABILITY_STATE_BACKGROUND); appRunningRecord->SetState(ApplicationState::APP_STATE_BACKGROUND); abilityRunningRecord->SetState(AbilityState::ABILITY_STATE_BACKGROUND); @@ -406,7 +406,7 @@ HWTEST_F(AmsAbilityRunningRecordTest, DeleteAbilityRunningRecord_001, TestSize.L auto abilityRunningRecord = appRunningRecord->AddAbility(token, abilityInfo); EXPECT_TRUE(abilityRunningRecord != nullptr); - ASSERT_TRUE(appRunningRecord->GetAbilityRunningRecordByToken(token) != nullptr); + EXPECT_TRUE(appRunningRecord->GetAbilityRunningRecordByToken(token) != nullptr); appRunningRecord->ClearAbility(abilityRunningRecord); EXPECT_TRUE(appRunningRecord->GetAbilityRunningRecordByToken(token) == nullptr); @@ -431,7 +431,7 @@ HWTEST_F(AmsAbilityRunningRecordTest, DeleteAbilityRunningRecord_002, TestSize.L auto abilityRunnningRecord = appRunningRecord->AddAbility(token, abilityInfo); EXPECT_TRUE(abilityRunnningRecord != nullptr); - ASSERT_TRUE(appRunningRecord->GetAbilityRunningRecordByToken(token) != nullptr); + EXPECT_TRUE(appRunningRecord->GetAbilityRunningRecordByToken(token) != nullptr); appRunningRecord->ClearAbility(nullptr); EXPECT_TRUE(appRunningRecord->GetAbilityRunningRecordByToken(token) != nullptr); @@ -517,7 +517,7 @@ HWTEST_F(AmsAbilityRunningRecordTest, SetGetAbilityRecord_001, TestSize.Level0) sptr token = new MockAbilityToken(); auto abilityRunningRecord = appRunningRecord->AddAbility(token, abilityInfo); - ASSERT_TRUE(abilityRunningRecord != nullptr); + EXPECT_TRUE(abilityRunningRecord != nullptr); abilityRunningRecord->SetVisibility(1); abilityRunningRecord->SetPerceptibility(1); abilityRunningRecord->SetConnectionState(1); diff --git a/services/appmgr/test/unittest/ams_app_workflow_test/ams_workflow_test.cpp b/services/appmgr/test/unittest/ams_app_workflow_test/ams_workflow_test.cpp index 74f5053434..e6582b3821 100644 --- a/services/appmgr/test/unittest/ams_app_workflow_test/ams_workflow_test.cpp +++ b/services/appmgr/test/unittest/ams_app_workflow_test/ams_workflow_test.cpp @@ -90,6 +90,7 @@ void AmsWorkFlowTest::TearDown() AbilityInfo AmsWorkFlowTest::CreateAbilityInfo(const std::string &ability, const std::string &app) const { AbilityInfo abilityInfo; + abilityInfo.visible = true; abilityInfo.name = "test_ability" + ability; abilityInfo.applicationName = "test_app" + app; return abilityInfo; diff --git a/services/appmgr/test/unittest/ams_process_optimizer_test/ams_process_optimizer_test.cpp b/services/appmgr/test/unittest/ams_process_optimizer_test/ams_process_optimizer_test.cpp index 49686a5c44..bad957fbc5 100644 --- a/services/appmgr/test/unittest/ams_process_optimizer_test/ams_process_optimizer_test.cpp +++ b/services/appmgr/test/unittest/ams_process_optimizer_test/ams_process_optimizer_test.cpp @@ -1,3 +1,17 @@ +/* + * Copyright (c) 2021 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 #define private public diff --git a/services/appmgr/test/unittest/ams_recent_app_list_test/ams_recent_app_list_test.cpp b/services/appmgr/test/unittest/ams_recent_app_list_test/ams_recent_app_list_test.cpp index b8c9c1a8b0..1364cffb53 100644 --- a/services/appmgr/test/unittest/ams_recent_app_list_test/ams_recent_app_list_test.cpp +++ b/services/appmgr/test/unittest/ams_recent_app_list_test/ams_recent_app_list_test.cpp @@ -104,7 +104,7 @@ void AmsRecentAppListTest::StartProcessSuccess(const int32_t index) const auto appInfo = GetApplicationByIndex(index); sptr token = new (std::nothrow) MockAbilityToken(); MockAppSpawnClient *mockClientPtr = new (std::nothrow) MockAppSpawnClient(); - ASSERT_TRUE(mockClientPtr); + EXPECT_TRUE(mockClientPtr); // mock start process success, and pid is right. EXPECT_CALL(*mockClientPtr, StartProcess(_, _)).Times(1).WillOnce(DoAll(SetArgReferee<1>(pid), Return(ERR_OK))); @@ -150,7 +150,7 @@ HWTEST_F(AmsRecentAppListTest, Create_002, TestSize.Level1) // mock start process failed. MockAppSpawnClient *mockClientPtr = new (std::nothrow) MockAppSpawnClient(); - ASSERT_TRUE(mockClientPtr); + EXPECT_TRUE(mockClientPtr); EXPECT_CALL(*mockClientPtr, StartProcess(_, _)).WillOnce(Return(ERR_APPEXECFWK_ASSEMBLE_START_MSG_FAILED)); serviceInner_->SetAppSpawnClient(std::unique_ptr(mockClientPtr)); @@ -175,7 +175,7 @@ HWTEST_F(AmsRecentAppListTest, Create_003, TestSize.Level1) auto appInfo = GetApplicationByIndex(INDEX_NUM_1); sptr token = new (std::nothrow) MockAbilityToken(); MockAppSpawnClient *mockClientPtr = new (std::nothrow) MockAppSpawnClient(); - ASSERT_TRUE(mockClientPtr); + EXPECT_TRUE(mockClientPtr); // mock start process success, and pid is right. EXPECT_CALL(*mockClientPtr, StartProcess(_, _)).Times(1).WillOnce(DoAll(SetArgReferee<1>(pid), Return(ERR_OK))); @@ -370,7 +370,7 @@ HWTEST_F(AmsRecentAppListTest, RecentAppList_001, TestSize.Level1) auto appInfo = GetApplicationByIndex(INDEX_NUM_1); sptr token = new (std::nothrow) MockAbilityToken(); MockAppSpawnClient *mockClientPtr = new (std::nothrow) MockAppSpawnClient(); - ASSERT_TRUE(mockClientPtr); + EXPECT_TRUE(mockClientPtr); EXPECT_CALL(*mockClientPtr, StartProcess(_, _)).Times(1).WillOnce(DoAll(SetArgReferee<1>(pid), Return(ERR_OK))); serviceInner_->SetAppSpawnClient(std::unique_ptr(mockClientPtr)); @@ -398,7 +398,7 @@ HWTEST_F(AmsRecentAppListTest, PushAppFront_001, TestSize.Level1) auto appInfo = GetApplicationByIndex(INDEX_NUM_1); sptr token = new (std::nothrow) MockAbilityToken(); MockAppSpawnClient *mockClientPtr = new (std::nothrow) MockAppSpawnClient(); - ASSERT_TRUE(mockClientPtr); + EXPECT_TRUE(mockClientPtr); EXPECT_CALL(*mockClientPtr, StartProcess(_, _)).Times(1).WillOnce(DoAll(SetArgReferee<1>(pid), Return(ERR_OK))); serviceInner_->SetAppSpawnClient(std::unique_ptr(mockClientPtr)); diff --git a/services/bundlemgr/BUILD.gn b/services/bundlemgr/BUILD.gn old mode 100644 new mode 100755 index 39078241eb..e786a2a14a --- a/services/bundlemgr/BUILD.gn +++ b/services/bundlemgr/BUILD.gn @@ -121,6 +121,7 @@ ohos_shared_library("libbms") { "//foundation/distributedschedule/dmsfwk/services/dtbschedmgr/include", "//base/notification/ces_standard/interfaces/innerkits/native/include", "//utils/system/safwk/native/include", + "//third_party/jsoncpp/include", ] sources = [ @@ -133,6 +134,8 @@ ohos_shared_library("libbms") { "src/bundle_scanner.cpp", "src/bundle_status_callback_death_recipient.cpp", "src/kvstore_death_recipient_callback.cpp", + "src/module_usage_data_storage.cpp", + "src/permission_changed_death_recipient.cpp", "src/system_ability_helper.cpp", ] @@ -163,6 +166,7 @@ ohos_shared_library("libbms") { "//foundation/distributeddatamgr/distributeddatamgr/interfaces/innerkits/distributeddata:distributeddata_inner", "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/jsoncpp:jsoncpp", ] external_deps = [ @@ -196,6 +200,7 @@ ohos_executable("installs") { ":parser_common", "${common_path}:libappexecfwk_common", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/jsoncpp:jsoncpp", ] external_deps = [ diff --git a/services/bundlemgr/include/base_bundle_installer.h b/services/bundlemgr/include/base_bundle_installer.h index 22d0871bf4..266ba2b411 100644 --- a/services/bundlemgr/include/base_bundle_installer.h +++ b/services/bundlemgr/include/base_bundle_installer.h @@ -106,32 +106,36 @@ private: * to install or update. * @param installParam Indicates the install parameters. * @param appType Indicates the application type. + * @param uid Indicates the uid of the application. * @return Returns ERR_OK if the bundle install successfully; returns error code otherwise. */ - ErrCode ProcessBundleInstall( - const std::string &bundlePath, const InstallParam &installParam, const Constants::AppType appType); + ErrCode ProcessBundleInstall(const std::string &bundlePath, const InstallParam &installParam, + const Constants::AppType appType, int32_t &uid); /** * @brief The real procedure function for uninstall a bundle. * @param bundleName Indicates the bundle name of the application to uninstall. * @param installParam Indicates the uninstall parameters. + * @param uid Indicates the uid of the application. * @return Returns ERR_OK if the bundle uninstall successfully; returns error code otherwise. */ - ErrCode ProcessBundleUninstall(const std::string &bundleName, const InstallParam &installParam); + ErrCode ProcessBundleUninstall(const std::string &bundleName, const InstallParam &installParam, int32_t &uid); /** * @brief The real procedure for uninstall a module in a specific bundle. * @param bundleName Indicates the bundle name of the application to uninstall. * @param modulePackage Indicates the module package of the module to uninstall. * @param installParam Indicates the uninstall parameters. + * @param uid Indicates the uid of the application. * @return Returns ERR_OK if the module uninstall successfully; returns error code otherwise. */ - ErrCode ProcessBundleUninstall( - const std::string &bundleName, const std::string &modulePackage, const InstallParam &installParam); + ErrCode ProcessBundleUninstall(const std::string &bundleName, const std::string &modulePackage, + const InstallParam &installParam, int32_t &uid); /** * @brief The process of installing a new bundle. * @param info Indicates the InnerBundleInfo parsed from the config.json in the HAP package. + * @param uid Indicates the uid of the application. * @return Returns ERR_OK if the new bundle install successfully; returns error code otherwise. */ - ErrCode ProcessBundleInstallStatus(InnerBundleInfo &info); + ErrCode ProcessBundleInstallStatus(InnerBundleInfo &info, int32_t &uid); /** * @brief The process of updating an exist bundle. * @param oldInfo Indicates the exist InnerBundleInfo object get from the database. diff --git a/services/bundlemgr/include/bundle_data_mgr.h b/services/bundlemgr/include/bundle_data_mgr.h index 0a962c6856..7f78b68d15 100755 --- a/services/bundlemgr/include/bundle_data_mgr.h +++ b/services/bundlemgr/include/bundle_data_mgr.h @@ -21,6 +21,7 @@ #include #include #include +#include #include "ohos/aafwk/content/want.h" @@ -29,6 +30,10 @@ #include "inner_bundle_info.h" #include "bundle_status_callback_interface.h" #include "bundle_data_storage_interface.h" +#include "module_usage_record.h" +#include "module_usage_data_storage.h" +#include "on_permission_changed_callback_interface.h" +#include "common_event_manager.h" namespace OHOS { namespace AppExecFwk { @@ -119,6 +124,13 @@ public: * @return Returns true if the AbilityInfo is successfully obtained; returns false otherwise. */ bool QueryAbilityInfo(const Want &want, AbilityInfo &abilityInfo) const; + /** + * @brief Query a AbilityInfo of list by the given Want. + * @param want Indicates the information of the ability. + * @param abilityInfo Indicates the obtained AbilityInfo of list. + * @return Returns true if the AbilityInfo is successfully obtained; returns false otherwise. + */ + bool QueryAbilityInfos(const Want &want, std::vector &abilityInfo) const; /** * @brief Query the AbilityInfo by ability.uri in config.json. * @param abilityUri Indicates the uri of the ability. @@ -306,10 +318,11 @@ public: * @param resultCode Indicates the status code returned for the application installation, update, or uninstall * result. * @param type Indicates the NotifyType object. + * @param uid Indicates the uid of the application. * @return Returns true if this function is successfully called; returns false otherwise. */ bool NotifyBundleStatus(const std::string &bundleName, const std::string &modulePackage, - const std::string &mainAbility, const ErrCode resultCode, const NotifyType type); + const std::string &mainAbility, const ErrCode resultCode, const NotifyType type, const int32_t &uid); /** * @brief Get a mutex for locking by bundle name. * @param bundleName Indicates the bundle name. @@ -379,6 +392,72 @@ public: * @return Returns true if this function is successfully called; returns false otherwise. */ bool GetShortcutInfos(const std::string &bundleName, std::vector &shortcutInfos) const; + /** + * @brief Notify a specified ability for activity. + * @param bundleName Indicates the bundle name of the ability to activity. + * @param abilityName Indicates the name of the ability to activity. + * @param launchTime Indicates the ability launchTime. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool NotifyActivityLifeStatus( + const std::string &bundleName, const std::string &abilityName, const int64_t launchTime) const; + /** + * @brief Query ModuleUsageRecord objects ordered by lastLaunchTime desc + * @param maxNum Indicates the max number ShortcutInfo objects to get. + * @param records List of ModuleUsageRecord objects if obtained. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool GetUsageRecords(int32_t maxNum, std::vector &records); + /** + * @brief Registers a callback for listening for permission changes of all UIDs. + * @param callback Indicates the callback method to register. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool RegisterAllPermissionsChanged(const sptr &callback); + /** + * @brief Registers a callback for listening for permission changes of specified UIDs. + * @param uids Indicates the list of UIDs whose permission changes will be monitored. + * @param callback Indicates the callback method to register. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool RegisterPermissionsChanged(const std::vector &uids, const sptr &callback); + /** + * @brief Add death recipient for specified callback registerd. + * @param callback Indicates the callback for death recipient. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool AddDeathRecipient(const sptr &callback); + /** + * @brief Unregisters a specified callback for listening for permission changes. + * @param callback Indicates the callback method to unregister. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool UnregisterPermissionsChanged(const sptr &callback); + /** + * @brief Call callback for listening the uid permission changes. + * @param uid Indicates the bundle uid whose permission changes. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool NotifyPermissionsChanged(int32_t uid); + /** + * @brief Update bundle usage record on bundle removed. + * @param keepUsage Indicates the flag record is remove on bundle removed. + * @param userId Indicates the user Id of the application. + * @param bundleName Indicates the bundle name of the application. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool UpdateUsageRecordOnBundleRemoved(bool keepUsage, const int userId, const std::string &bundleName) const; + /** + * @brief Update bundle usage record on module removed. + * @param keepUsage Indicates the flag record is remove on module removed. + * @param userId Indicates the user Id of the application. + * @param bundleName Indicates the bundle name of the application. + * @param moduleName Indicates the module name of the application. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool UpdateUsageRecordOnModuleRemoved( + bool keepUsage, const int userId, const std::string &bundleName, const std::string &moduleName) const; + private: /** * @brief Init transferStates. @@ -429,6 +508,8 @@ private: mutable std::mutex uidMapMutex_; mutable std::mutex callbackMutex_; mutable std::shared_mutex bundleMutex_; + mutable std::mutex allPermissionsChangedLock_; + mutable std::mutex permissionsChangedLock_; bool allInstallFlag_ = false; // using for locking by bundleName std::unordered_map bundleMutexMap_; @@ -447,6 +528,10 @@ private: // current-status:previous-statue pair std::multimap transferStates_; std::shared_ptr dataStorage_; + std::shared_ptr usageRecordStorage_; + std::set> allPermissionsCallbacks_; + // map. + std::map>> permissionsCallbacks_; }; } // namespace AppExecFwk diff --git a/services/bundlemgr/include/bundle_mgr_host_impl.h b/services/bundlemgr/include/bundle_mgr_host_impl.h index aba344a399..8c2b84b3af 100644 --- a/services/bundlemgr/include/bundle_mgr_host_impl.h +++ b/services/bundlemgr/include/bundle_mgr_host_impl.h @@ -108,6 +108,13 @@ public: * @return Returns true if the AbilityInfo is successfully obtained; returns false otherwise. */ virtual bool QueryAbilityInfo(const Want &want, AbilityInfo &abilityInfo) override; + /** + * @brief Query the AbilityInfo of list by the given Want. + * @param want Indicates the information of the ability. + * @param abilityInfos Indicates the obtained AbilityInfos object. + * @return Returns true if the AbilityInfos is successfully obtained; returns false otherwise. + */ + virtual bool QueryAbilityInfos(const Want &want, std::vector &abilityInfos) override; /** * @brief Query the AbilityInfo by ability.uri in config.json. * @param abilityUri Indicates the uri of the ability. @@ -357,6 +364,23 @@ public: * @return Returns true if GetShortcutInfos successfully; returns false otherwise. */ virtual bool GetShortcutInfos(const std::string &bundleName, std::vector &shortcutInfos) override; + /** + * @brief Get module usage record list in descending order of lastLaunchTime. + * @param maxNum the return size of the records, must be in range of 1 to 1000. + * @param moduleUsageRecords List of ModuleUsageRecord objects if obtained. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool GetModuleUsageRecords(const int32_t number, std::vector &moduleUsageRecords) override; + /** + * @brief Notify a specified ability for activity. + * @param bundleName Indicates the bundle name of the ability to activity. + * @param abilityName Indicates the name of the ability to activity. + * @param launchTime Indicates the ability launchTime. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool NotifyActivityLifeStatus( + const std::string &bundleName, const std::string &abilityName, const int64_t launchTime) override; + private: const std::shared_ptr GetDataMgrFromService(); }; diff --git a/services/bundlemgr/include/bundle_mgr_service.h b/services/bundlemgr/include/bundle_mgr_service.h index d2308c6c1f..5482114b8d 100644 --- a/services/bundlemgr/include/bundle_mgr_service.h +++ b/services/bundlemgr/include/bundle_mgr_service.h @@ -25,6 +25,7 @@ #include "bundle_installer_host.h" #include "bundle_mgr_host_impl.h" #include "bundle_mgr_service_event_handler.h" +#include "bundle_permissions_changed_monitor.h" namespace OHOS { namespace AppExecFwk { @@ -81,6 +82,7 @@ private: std::shared_ptr dataMgr_; sptr host_; sptr installer_; + std::shared_ptr perChangeSub_; DISALLOW_COPY_AND_MOVE(BundleMgrService); }; diff --git a/services/bundlemgr/include/bundle_permissions_changed_monitor.h b/services/bundlemgr/include/bundle_permissions_changed_monitor.h new file mode 100644 index 0000000000..a128d4a09c --- /dev/null +++ b/services/bundlemgr/include/bundle_permissions_changed_monitor.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_PERMISSIONS_CHANGED_MONITOR_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_PERMISSIONS_CHANGED_MONITOR_H +#include +#include "bundle_mgr_host.h" +#include "bundle_data_mgr.h" +#include "common_event_manager.h" +#include "common_event_support.h" +#include "common_event_subscriber.h" +#include "common_event_subscribe_info.h" +#include "bundle_mgr_service.h" +#include "bundle_util.h" + +#include "bundle_data_mgr.h" +#include "json_serializer.h" +#include "app_log_wrapper.h" + + +#include "bundle_parser.h" +#include "installd_client.h" +#include "bundle_permission_mgr.h" + +namespace OHOS { +namespace AppExecFwk { +class BundlePermissionsChangedMonitor : public EventFwk::CommonEventSubscriber { +public: + BundlePermissionsChangedMonitor(const std::shared_ptr &dataMgr, + const EventFwk::CommonEventSubscribeInfo& sp):CommonEventSubscriber(sp) + { + dataMgr_ = dataMgr; + } + ~BundlePermissionsChangedMonitor(){ + if(!dataMgr_){ + dataMgr_.reset(); + } + } + void OnReceiveEvent(const EventFwk::CommonEventData &data) + { + OHOS::AAFwk::Want want = data.GetWant(); + std::string action = want.GetAction(); + int32_t uid = data.GetCode(); + if ( dataMgr_ != nullptr && uid >=0 ) { + dataMgr_->NotifyPermissionsChanged(uid); + } + } +private: + std::shared_ptr dataMgr_; +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_MONITOR_H \ No newline at end of file diff --git a/services/bundlemgr/include/common_profile.h b/services/bundlemgr/include/common_profile.h index 144b19fe04..98624b7cf3 100644 --- a/services/bundlemgr/include/common_profile.h +++ b/services/bundlemgr/include/common_profile.h @@ -32,6 +32,8 @@ const std::string PROFILE_KEY_LABEL_ID = "labelId"; const std::string PROFILE_KEY_DESCRIPTION = "description"; const std::string PROFILE_KEY_DESCRIPTION_ID = "descriptionId"; const std::string PROFILE_KEY_TYPE = "type"; +const std::string PROFILE_KEY_SRCPATH = "srcPath"; +const std::string PROFILE_KEY_SRCLANGUAGE = "srcLanguage"; // bundle profile tag const std::string BUNDLE_PROFILE_KEY_APP = "app"; @@ -121,6 +123,7 @@ const std::string BUNDLE_MODULE_PROFILE_KEY_CUSTOMIZE_DATA = "customizeData"; const std::string BUNDLE_MODULE_PROFILE_KEY_DELIVERY_WITH_INSTALL = "deliveryWithInstall"; const std::string BUNDLE_MODULE_PROFILE_KEY_MODULE_NAME = "moduleName"; const std::string BUNDLE_MODULE_PROFILE_KEY_MODULE_TYPE = "moduleType"; +const std::string BUNDLE_MODULE_PROFILE_KEY_MODULE_INSTALLATION_FREE = "installationFree"; // sub BUNDLE_MODULE_PROFILE_KEY_SKILLS const std::string BUNDLE_MODULE_PROFILE_KEY_ACTIONS = "actions"; const std::string BUNDLE_MODULE_PROFILE_KEY_ENTITIES = "entities"; @@ -190,6 +193,8 @@ const std::string BUNDLE_MODULE_PROFILE_FORMS_UPDATE_DURATION = "updateDuration" const std::string BUNDLE_MODULE_PROFILE_FORMS_DEEP_LINK = "deepLink"; const std::string BUNDLE_MODULE_PROFILE_FORMS_JS_COMPONENT_NAME = "jsComponentName"; const std::string BUNDLE_MODULE_PROFILE_FORMS_VALUE = "value"; +const std::string BUNDLE_MODULE_PROFILE_FORMS_FORM_CONFIG_ABILITY = "formConfigAbility"; +const std::string BUNDLE_MODULE_PROFILE_FORMS_FORM_VISIBLE_NOTIFY = "formEnabled"; // sub BUNDLE_MODULE_PROFILE_KEY_JS const std::string BUNDLE_MODULE_PROFILE_KEY_PAGES = "pages"; const std::string BUNDLE_MODULE_PROFILE_KEY_WINDOW = "window"; diff --git a/services/bundlemgr/include/inner_bundle_info.h b/services/bundlemgr/include/inner_bundle_info.h index d67c71738e..f1c6749a20 100644 --- a/services/bundlemgr/include/inner_bundle_info.h +++ b/services/bundlemgr/include/inner_bundle_info.h @@ -37,6 +37,7 @@ struct Distro { bool deliveryWithInstall; std::string moduleName; std::string moduleType; + bool installationFree = false; }; struct DefPermission { @@ -66,8 +67,12 @@ struct InnerModuleInfo { std::string modulePath; std::string moduleDataDir; std::string moduleResPath; + std::string label; + int32_t labelId = 0; std::string description; + int32_t descriptionId = 0; bool isEntry; + bool installationFree; MetaData metaData; ModuleColorMode colorMode = ModuleColorMode::AUTO; Distro distro; @@ -108,7 +113,7 @@ enum class ArrayType { NOT_ARRAY, }; -template +template void CheckArrayType( const nlohmann::json &jsonObject, const std::string &key, dataType &data, ArrayType arrayType, int32_t &parseResult) { @@ -119,7 +124,7 @@ void CheckArrayType( } switch (arrayType) { case ArrayType::STRING: - for (const auto& array : arrays) { + for (const auto &array : arrays) { if (!array.is_string()) { APP_LOGE("array %{public}s is not string type", key.c_str()); parseResult = ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR; @@ -130,7 +135,7 @@ void CheckArrayType( } break; case ArrayType::OBJECT: - for (const auto& array : arrays) { + for (const auto &array : arrays) { if (!array.is_object()) { APP_LOGE("array %{public}s is not object type", key.c_str()); parseResult = ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR; @@ -142,7 +147,7 @@ void CheckArrayType( } break; case ArrayType::NUMBER: - for (const auto& array : arrays) { + for (const auto &array : arrays) { if (!array.is_number()) { APP_LOGE("array %{public}s is not number type", key.c_str()); parseResult = ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR; @@ -161,7 +166,7 @@ void CheckArrayType( } } -template +template void GetValueIfFindKey(const nlohmann::json &jsonObject, const nlohmann::detail::iter_impl &end, const std::string &key, dataType &data, JsonType jsonType, bool isNecessary, int32_t &parseResult, ArrayType arrayType) @@ -290,6 +295,12 @@ public: * @return Returns the AbilityInfo object if find it; returns null otherwise. */ std::optional FindAbilityInfo(const std::string &bundleName, const std::string &abilityName) const; + /** + * @brief Find abilityInfo of list by bundle name. + * @param bundleName Indicates the bundle name. + * @return Returns the AbilityInfo of list if find it; returns null otherwise. + */ + std::optional> FindAbilityInfos(const std::string &bundleName) const; /** * @brief Transform the InnerBundleInfo object to string. * @return Returns the string object @@ -322,23 +333,23 @@ public: * @param formInfos Indicates the Forms object to be add. * @return */ - void AddModuleFormInfo(const std::map> &formInfos) - { - for (const auto &forms : formInfos) { - formInfos_.try_emplace(forms.first, forms.second); - } - } + void AddModuleFormInfo(const std::map> &formInfos) + { + for (const auto &forms : formInfos) { + formInfos_.try_emplace(forms.first, forms.second); + } + } /** * @brief Add shortcut infos to old InnerBundleInfo object. * @param shortcutInfos Indicates the Shortcut object to be add. * @return */ - void AddModuleShortcutInfo(const std::map &shortcutInfos) - { - for (const auto &shortcut : shortcutInfos) { - shortcutInfos_.try_emplace(shortcut.first, shortcut.second); - } - } + void AddModuleShortcutInfo(const std::map &shortcutInfos) + { + for (const auto &shortcut : shortcutInfos) { + shortcutInfos_.try_emplace(shortcut.first, shortcut.second); + } + } /** * @brief Add innerModuleInfos to old InnerBundleInfo object. * @param innerModuleInfos Indicates the InnerModuleInfo object to be add. @@ -548,8 +559,14 @@ public: */ std::optional FindAbilityInfoByUri(const std::string &abilityUri) const { + APP_LOGI("Uri is %{public}s", abilityUri.c_str()); for (const auto &ability : baseAbilityInfos_) { - if (ability.second.uri == abilityUri) { + if (ability.second.uri.size() < Constants::DATA_ABILITY_URI_PREFIX.size()) { + continue; + } + auto configUri = ability.second.uri.substr(Constants::DATA_ABILITY_URI_PREFIX.size()); + APP_LOGI("configUri is %{public}s", configUri.c_str()); + if (configUri == abilityUri) { return ability.second; } } @@ -918,19 +935,19 @@ public: * @param keyName Indicates object as key. * @param formInfos Indicates the formInfo object as value. */ - void InsertFormInfos(const std::string &keyName, const std::vector &formInfos) - { - formInfos_.emplace(keyName, formInfos); - } + void InsertFormInfos(const std::string &keyName, const std::vector &formInfos) + { + formInfos_.emplace(keyName, formInfos); + } /** * @brief Insert shortcutInfos. * @param keyName Indicates object as key. * @param shortcutInfos Indicates the shortcutInfos object as value. */ - void InsertShortcutInfos(const std::string &keyName, const ShortcutInfo &shortcutInfos) - { - shortcutInfos_.emplace(keyName, shortcutInfos); - } + void InsertShortcutInfos(const std::string &keyName, const ShortcutInfo &shortcutInfos) + { + shortcutInfos_.emplace(keyName, shortcutInfos); + } // use for new Info in updating progress void RestoreFromOldInfo(const InnerBundleInfo &oldInfo) { @@ -970,17 +987,22 @@ public: * @param moduleName Indicates the module name of the application. * @param formInfos List of FormInfo objects if obtained; */ - void GetFormsInfoByModule(const std::string &moduleName, std::vector &formInfos) const; + void GetFormsInfoByModule(const std::string &moduleName, std::vector &formInfos) const; /** * @brief Obtains the FormInfo objects provided by a specified application on the device. * @param formInfos List of FormInfo objects if obtained; */ - void GetFormsInfoByApp(std::vector &formInfos) const; + void GetFormsInfoByApp(std::vector &formInfos) const; /** * @brief Obtains the ShortcutInfo objects provided by a specified application on the device. * @param shortcutInfos List of ShortcutInfo objects if obtained. */ void GetShortcutInfos(std::vector &shortcutInfos) const; + + std::optional GetInnerModuleInfoByModuleName(const std::string &moduleName) const; + + void GetModuleNames(std::vector &moduleNames) const; + private: // using for get bool isSupportBackup_ = false; @@ -1000,7 +1022,7 @@ private: std::string currentPackage_; std::string mainAbilityName_; - std::map> formInfos_; + std::map> formInfos_; std::map baseAbilityInfos_; std::map innerModuleInfos_; std::map> skillInfos_; diff --git a/services/bundlemgr/include/module_usage_data_storage.h b/services/bundlemgr/include/module_usage_data_storage.h new file mode 100644 index 0000000000..d8c7e6a159 --- /dev/null +++ b/services/bundlemgr/include/module_usage_data_storage.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_MODULE_USAGE_DATA_STORAGE_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_MODULE_USAGE_DATA_STORAGE_H + +#include +#include + +#include "module_usage_record.h" + +#include "bundle_constants.h" +#include "distributed_kv_data_manager.h" +#include "inner_bundle_info.h" + + +namespace OHOS { +namespace AppExecFwk { +class DataMgr; + +class ModuleUsageRecordStorage : public std::enable_shared_from_this { +public: + ModuleUsageRecordStorage(); + virtual ~ModuleUsageRecordStorage(); + + // add&update + bool AddOrUpdateRecord(ModuleUsageRecord& data, const std::string& deviceId, int32_t userId); + bool DeleteRecordByUserId(int32_t userId); + bool DeleteUsageRecord(const InnerBundleInfo& data, int32_t userId); + bool MarkUsageRecordRemoved(const InnerBundleInfo &data, int32_t userId); + bool QueryRecordByNum(int32_t maxNum, std::vector& records, int32_t userId); + void SetDataMgr(const std::weak_ptr& dataMgr) const; + void OnKvStoreDeath(); + void RegisterKvStoreDeathListener(); +private: + + bool DeleteRecordByKeys(const std::string& bundleName, std::vector& keys); + bool QueryRecordByCondition(DistributedKv::DataQuery& query, std::vector& records); + void AbilityRecordToKey(const std::string& userId, const std::string& deviceId, + const std::string& bundleName, const std::string& moduleName, std::string& key) const; + void InnerBundleInfoToKeys(const InnerBundleInfo& data, int32_t userId, + std::vector& keys) const; + void FillDataStorageKeys(const std::string& userId, const std::string& bundleName, + const std::string& moduleName, std::vector& keys) const; + bool ParseKey(const std::string& key, ModuleUsageRecord& record) const; + void UpdateUsageRecord(const std::string& jsonString, ModuleUsageRecord& data); + void SaveEntries(const std::vector& allEntries, + std::vector& records) const; + void TryTwice(const std::function& func) const; + bool CheckKvStore(); + DistributedKv::Status GetKvStore(); + bool ResetKvStore(); + +private: + const DistributedKv::AppId appId_ { Constants::APP_ID }; + const DistributedKv::StoreId storeId_ { Constants::ABILITY_USAGE_STORE_ID }; + DistributedKv::DistributedKvDataManager dataManager_; + std::unique_ptr kvStorePtr_; + mutable std::mutex kvStorePtrMutex_; + enum { + DATABASE_KEY_INDEX_USER_ID = 0, + DATABASE_KEY_INDEX_DEVICE_ID, + DATABASE_KEY_INDEX_BUNDLE_NAME, + DATABASE_KEY_INDEX_MODULE_NAME, + DATABASE_KEY_INDEX_MAX_LENGTH, + }; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_MODULE_USAGE_DATA_STORAGE_H \ No newline at end of file diff --git a/services/bundlemgr/include/permission_changed_death_recipient.h b/services/bundlemgr/include/permission_changed_death_recipient.h new file mode 100644 index 0000000000..1f4e04072f --- /dev/null +++ b/services/bundlemgr/include/permission_changed_death_recipient.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_PERMISSION_CHANGED_DEATH_RECIPIENT_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_PERMISSION_CHANGED_DEATH_RECIPIENT_H + +#include "iremote_object.h" + +#include "on_permission_changed_callback_interface.h" + +namespace OHOS { +namespace AppExecFwk { + +class PermissionChangedDeathRecipient : public IRemoteObject::DeathRecipient { + +public: + virtual void OnRemoteDied(const wptr& object) override; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_PERMISSION_CHANGED_DEATH_RECIPIENT_H \ No newline at end of file diff --git a/services/bundlemgr/src/base_bundle_installer.cpp b/services/bundlemgr/src/base_bundle_installer.cpp index 77e367097b..023be8c65e 100755 --- a/services/bundlemgr/src/base_bundle_installer.cpp +++ b/services/bundlemgr/src/base_bundle_installer.cpp @@ -111,10 +111,15 @@ ErrCode BaseBundleInstaller::InstallBundle( APP_LOGI("begin to process %{public}s bundle install", bundlePath.c_str()); PerfProfile::GetInstance().SetBundleInstallStartTime(GetTickCount()); - ErrCode result = ProcessBundleInstall(bundlePath, installParam, appType); + int32_t uid = Constants::INVALID_UID; + ErrCode result = ProcessBundleInstall(bundlePath, installParam, appType, uid); if (dataMgr_ && !bundleName_.empty() && !modulePackage_.empty()) { - dataMgr_->NotifyBundleStatus( - bundleName_, modulePackage_, mainAbility_, result, isAppExist_ ? NotifyType::UPDATE : NotifyType::INSTALL); + dataMgr_->NotifyBundleStatus(bundleName_, + modulePackage_, + mainAbility_, + result, + isAppExist_ ? NotifyType::UPDATE : NotifyType::INSTALL, + uid); } PerfProfile::GetInstance().SetBundleInstallEndTime(GetTickCount()); @@ -127,10 +132,11 @@ ErrCode BaseBundleInstaller::UninstallBundle(const std::string &bundleName, cons APP_LOGD("begin to process %{public}s bundle uninstall", bundleName.c_str()); PerfProfile::GetInstance().SetBundleUninstallStartTime(GetTickCount()); - ErrCode result = ProcessBundleUninstall(bundleName, installParam); + int32_t uid = Constants::INVALID_UID; + ErrCode result = ProcessBundleUninstall(bundleName, installParam, uid); if (dataMgr_) { dataMgr_->NotifyBundleStatus( - bundleName, Constants::EMPTY_STRING, Constants::EMPTY_STRING, result, NotifyType::UNINSTALL_BUNDLE); + bundleName, Constants::EMPTY_STRING, Constants::EMPTY_STRING, result, NotifyType::UNINSTALL_BUNDLE, uid); } PerfProfile::GetInstance().SetBundleUninstallEndTime(GetTickCount()); @@ -144,10 +150,11 @@ ErrCode BaseBundleInstaller::UninstallBundle( APP_LOGD("begin to process %{public}s module in %{public}s uninstall", modulePackage.c_str(), bundleName.c_str()); PerfProfile::GetInstance().SetBundleUninstallStartTime(GetTickCount()); - ErrCode result = ProcessBundleUninstall(bundleName, modulePackage, installParam); + int32_t uid = Constants::INVALID_UID; + ErrCode result = ProcessBundleUninstall(bundleName, modulePackage, installParam, uid); if (dataMgr_) { dataMgr_->NotifyBundleStatus( - bundleName, modulePackage, Constants::EMPTY_STRING, result, NotifyType::UNINSTALL_MODULE); + bundleName, modulePackage, Constants::EMPTY_STRING, result, NotifyType::UNINSTALL_MODULE, uid); } PerfProfile::GetInstance().SetBundleUninstallEndTime(GetTickCount()); @@ -162,7 +169,7 @@ void BaseBundleInstaller::UpdateInstallerState(const InstallerState state) } ErrCode BaseBundleInstaller::ProcessBundleInstall( - const std::string &inBundlePath, const InstallParam &installParam, const Constants::AppType appType) + const std::string &inBundlePath, const InstallParam &installParam, const Constants::AppType appType, int32_t &uid) { APP_LOGI("ProcessBundleInstall bundlePath %{public}s", inBundlePath.c_str()); if (installParam.userId == Constants::INVALID_USERID) { @@ -179,9 +186,11 @@ ErrCode BaseBundleInstaller::ProcessBundleInstall( UpdateInstallerState(InstallerState::INSTALL_BUNDLE_CHECKED); Security::Verify::HapVerifyResult hapVerifyResult; - if (!BundleVerifyMgr::HapVerify(bundlePath, hapVerifyResult)) { - APP_LOGE("hap file verify failed"); - return ERR_APPEXECFWK_INSTALL_NO_SIGNATURE_INFO; + if (installParam.noCheckSignature == false) { + if (!BundleVerifyMgr::HapVerify(bundlePath, hapVerifyResult)) { + APP_LOGE("hap file verify failed"); + return ERR_APPEXECFWK_INSTALL_NO_SIGNATURE_INFO; + } } // parse the single bundle info to get the bundle name. @@ -190,9 +199,6 @@ ErrCode BaseBundleInstaller::ProcessBundleInstall( newInfo.SetAppType(appType); newInfo.SetUserId(installParam.userId); newInfo.SetIsKeepData(installParam.isKeepData); - auto provisionInfo = hapVerifyResult.GetProvisionInfo(); - newInfo.SetProvisionId(provisionInfo.appId); - if (!ModifyInstallDirByHapType(newInfo)) { APP_LOGE("modify bundle install dir failed %{public}d", result); return ERR_APPEXECFWK_INSTALL_PARAM_ERROR; @@ -202,8 +208,11 @@ ErrCode BaseBundleInstaller::ProcessBundleInstall( APP_LOGE("bundle parse failed %{public}d", result); return result; } - newInfo.SetAppFeature(provisionInfo.bundleInfo.appFeature); - + if (installParam.noCheckSignature == false) { + auto provisionInfo = hapVerifyResult.GetProvisionInfo(); + newInfo.SetProvisionId(provisionInfo.appId); + newInfo.SetAppFeature(provisionInfo.bundleInfo.appFeature); + } UpdateInstallerState(InstallerState::INSTALL_PARSED); bundleName_ = newInfo.GetBundleName(); @@ -226,13 +235,15 @@ ErrCode BaseBundleInstaller::ProcessBundleInstall( isAppExist_ = dataMgr_->GetInnerBundleInfo(bundleName_, Constants::CURRENT_DEVICE_ID, oldInfo); if (isAppExist_) { APP_LOGI("app is exist"); + uid = oldInfo.GetUid(); bool isReplace = (installParam.installFlag == InstallFlag::REPLACE_EXISTING); return ProcessBundleUpdateStatus(oldInfo, newInfo, isReplace); // app exist, but module may not } - return ProcessBundleInstallStatus(newInfo); + return ProcessBundleInstallStatus(newInfo, uid); } -ErrCode BaseBundleInstaller::ProcessBundleUninstall(const std::string &bundleName, const InstallParam &installParam) +ErrCode BaseBundleInstaller::ProcessBundleUninstall( + const std::string &bundleName, const InstallParam &installParam, int32_t &uid) { if (bundleName.empty()) { APP_LOGE("uninstall bundle name empty"); @@ -255,6 +266,7 @@ ErrCode BaseBundleInstaller::ProcessBundleUninstall(const std::string &bundleNam APP_LOGE("uninstall bundle info missing"); return ERR_APPEXECFWK_UNINSTALL_MISSING_INSTALLED_BUNDLE; } + uid = oldInfo.GetUid(); ScopeGuard enableGuard([&] { dataMgr_->EnableBundle(bundleName); }); if (oldInfo.GetAppType() == Constants::AppType::SYSTEM_APP) { APP_LOGE("uninstall system app"); @@ -283,7 +295,7 @@ ErrCode BaseBundleInstaller::ProcessBundleUninstall(const std::string &bundleNam } ErrCode BaseBundleInstaller::ProcessBundleUninstall( - const std::string &bundleName, const std::string &modulePackage, const InstallParam &installParam) + const std::string &bundleName, const std::string &modulePackage, const InstallParam &installParam, int32_t &uid) { if (bundleName.empty() || modulePackage.empty()) { APP_LOGE("uninstall bundle name or module name empty"); @@ -306,6 +318,7 @@ ErrCode BaseBundleInstaller::ProcessBundleUninstall( APP_LOGE("uninstall bundle info missing"); return ERR_APPEXECFWK_UNINSTALL_MISSING_INSTALLED_BUNDLE; } + uid = oldInfo.GetUid(); ScopeGuard enableGuard([&] { dataMgr_->EnableBundle(bundleName); }); if (oldInfo.GetAppType() == Constants::AppType::SYSTEM_APP) { @@ -369,7 +382,7 @@ ErrCode BaseBundleInstaller::RemoveBundle(InnerBundleInfo &info) return ERR_OK; } -ErrCode BaseBundleInstaller::ProcessBundleInstallStatus(InnerBundleInfo &info) +ErrCode BaseBundleInstaller::ProcessBundleInstallStatus(InnerBundleInfo &info, int32_t &uid) { APP_LOGI("ProcessBundleInstallStatus %{public}s", info.GetBundleName().c_str()); if (!dataMgr_->UpdateBundleInstallState(bundleName_, InstallState::INSTALL_START)) { @@ -382,6 +395,7 @@ ErrCode BaseBundleInstaller::ProcessBundleInstallStatus(InnerBundleInfo &info) APP_LOGE("create bundle and data dir failed"); return result; } + uid = info.GetUid(); UpdateInstallerState(InstallerState::INSTALL_CREATDIR); ScopeGuard bundleGuard([&] { RemoveBundleAndDataDir(info, false); }); diff --git a/services/bundlemgr/src/bundle_data_mgr.cpp b/services/bundlemgr/src/bundle_data_mgr.cpp index 53268c42bb..5d65fd7db9 100755 --- a/services/bundlemgr/src/bundle_data_mgr.cpp +++ b/services/bundlemgr/src/bundle_data_mgr.cpp @@ -27,6 +27,7 @@ #include "common_event_manager.h" #include "common_event_support.h" #include "bundle_status_callback_death_recipient.h" +#include "permission_changed_death_recipient.h" namespace OHOS { namespace AppExecFwk { @@ -34,9 +35,10 @@ namespace AppExecFwk { BundleDataMgr::BundleDataMgr() { InitStateTransferMap(); - if (!dataStorage_) { - dataStorage_ = std::make_shared(); - } + dataStorage_ = std::make_shared(); + usageRecordStorage_ = std::make_shared(); + // register distributed data process death listener. + usageRecordStorage_->RegisterKvStoreDeathListener(); APP_LOGI("BundleDataMgr instance is created"); } @@ -308,32 +310,98 @@ bool BundleDataMgr::QueryAbilityInfo(const Want &want, AbilityInfo &abilityInfo) return true; } +bool BundleDataMgr::QueryAbilityInfos(const Want &want, std::vector &abilityInfo) const +{ + ElementName element = want.GetElement(); + std::string abilityName = element.GetAbilityName(); + std::string bundleName = element.GetBundleName(); + APP_LOGI("bundle name:%{public}s, ability name:%{public}s", bundleName.c_str(), abilityName.c_str()); + + std::string keyName = bundleName + abilityName; + APP_LOGI("ability, name:%{public}s", keyName.c_str()); + std::lock_guard lock(bundleInfoMutex_); + if (bundleInfos_.empty()) { + APP_LOGI("bundleInfos_ is empty"); + return false; + } + auto item = bundleInfos_.find(bundleName); + if (item == bundleInfos_.end()) { + APP_LOGI("bundle:%{public}s not find", bundleName.c_str()); + return false; + } + + auto infoWithIdItem = item->second.find(Constants::CURRENT_DEVICE_ID); + if (infoWithIdItem == item->second.end()) { + APP_LOGI("bundle:%{public}s device id not find", bundleName.c_str()); + return false; + } + if (infoWithIdItem->second.IsDisabled()) { + APP_LOGI("app %{public}s is disabled", infoWithIdItem->second.GetBundleName().c_str()); + return false; + } + auto ability = infoWithIdItem->second.FindAbilityInfos(bundleName); + if (!ability) { + APP_LOGE("ability:%{public}s not find", keyName.c_str()); + return false; + } + abilityInfo = (*ability); + for (auto &ability : abilityInfo) { + infoWithIdItem->second.GetApplicationInfo( + ApplicationFlag::GET_APPLICATION_INFO_WITH_PERMS, 0, ability.applicationInfo); + } + + return true; +} + bool BundleDataMgr::QueryAbilityInfoByUri(const std::string &abilityUri, AbilityInfo &abilityInfo) const { - APP_LOGI("QueryAbilityInfoByUri"); + APP_LOGI("abilityUri is %{public}s", abilityUri.c_str()); if (abilityUri.empty()) { return false; } + if (abilityUri.find(Constants::DATA_ABILITY_URI_PREFIX) == std::string::npos) { + return false; + } std::lock_guard lock(bundleInfoMutex_); if (bundleInfos_.empty()) { APP_LOGI("bundleInfos_ data is empty"); return false; } + std::string noPpefixUri = abilityUri.substr(Constants::DATA_ABILITY_URI_PREFIX.size()); + auto posFirstSeparator = noPpefixUri.find(Constants::DATA_ABILITY_URI_SEPARATOR); + if (posFirstSeparator == std::string::npos) { + return false; + } + auto posSecondSeparator = noPpefixUri.find(Constants::DATA_ABILITY_URI_SEPARATOR, posFirstSeparator + 1); + std::string uri; + if (posSecondSeparator == std::string::npos) { + uri = noPpefixUri.substr(posFirstSeparator + 1, noPpefixUri.size() - posFirstSeparator - 1); + } else { + uri = noPpefixUri.substr(posFirstSeparator + 1, posSecondSeparator - posFirstSeparator - 1); + } + + std::string deviceId = noPpefixUri.substr(0, posFirstSeparator); + if (deviceId.empty()) { + deviceId = Constants::CURRENT_DEVICE_ID; + } for (const auto &item : bundleInfos_) { - for (const auto &info : item.second) { - if (info.second.IsDisabled()) { - APP_LOGI("app %{public}s is disabled", info.second.GetBundleName().c_str()); - continue; - } - auto ability = info.second.FindAbilityInfoByUri(abilityUri); - if (!ability) { - continue; - } - abilityInfo = (*ability); - info.second.GetApplicationInfo( - ApplicationFlag::GET_APPLICATION_INFO_WITH_PERMS, 0, abilityInfo.applicationInfo); - return true; + auto infoWithIdItem = item.second.find(deviceId); + if (infoWithIdItem == item.second.end()) { + APP_LOGI("bundle device id:%{public}s not find", deviceId.c_str()); + return false; + } + if (infoWithIdItem->second.IsDisabled()) { + APP_LOGI("app %{public}s is disabled", infoWithIdItem->second.GetBundleName().c_str()); + continue; + } + auto ability = infoWithIdItem->second.FindAbilityInfoByUri(uri); + if (!ability) { + continue; } + abilityInfo = (*ability); + infoWithIdItem->second.GetApplicationInfo( + ApplicationFlag::GET_APPLICATION_INFO_WITH_PERMS, 0, abilityInfo.applicationInfo); + return true; } return false; } @@ -1062,6 +1130,67 @@ bool BundleDataMgr::RecycleUidAndGid(const InnerBundleInfo &info) return true; } +bool BundleDataMgr::GetUsageRecords(const int32_t maxNum, std::vector &records) +{ + APP_LOGI("GetUsageRecords, maxNum: %{public}d", maxNum); + records.clear(); + std::vector usageRecords; + bool result = usageRecordStorage_->QueryRecordByNum(maxNum, usageRecords, 0); + if (!result) { + APP_LOGI("GetUsageRecords error"); + return false; + } + for (ModuleUsageRecord &item : usageRecords) { + APP_LOGD("GetUsageRecords item:%{public}s,%{public}s,%{public}s", + item.bundleName.c_str(), + item.name.c_str(), + item.abilityName.c_str()); + + std::lock_guard lock(bundleInfoMutex_); + if (bundleInfos_.empty()) { + APP_LOGI("bundleInfos_ data is empty"); + break; + } + auto infoItem = bundleInfos_.find(item.bundleName); + if (infoItem == bundleInfos_.end()) { + continue; + } + APP_LOGI("GetUsageRecords %{public}s", infoItem->first.c_str()); + auto bundleInfo = infoItem->second.find(Constants::CURRENT_DEVICE_ID); + if (bundleInfo == infoItem->second.end()) { + continue; + } + if (bundleInfo->second.IsDisabled()) { + APP_LOGI("app %{public}s is disabled", bundleInfo->second.GetBundleName().c_str()); + continue; + } + auto innerModuleInfo = bundleInfo->second.GetInnerModuleInfoByModuleName(item.name); + if (!innerModuleInfo) { + continue; + } + item.labelId = innerModuleInfo->labelId; + item.descriptionId = innerModuleInfo->descriptionId; + item.installationFreeSupported = innerModuleInfo->installationFree; + auto appInfo = bundleInfo->second.GetBaseApplicationInfo(); + item.appLabelId = appInfo.labelId; + auto ability = bundleInfo->second.FindAbilityInfo(item.bundleName, item.abilityName); + if (!ability) { + APP_LOGE("ability:%{public}s not find", item.abilityName.c_str()); + continue; + } + if (ability->type != AbilityType::PAGE) { + APP_LOGE("ability:%{public}s type is not PAGE", item.abilityName.c_str()); + continue; + } + item.abilityName = ability->name; + item.abilityLabelId = ability->labelId; + item.abilityDescriptionId = ability->descriptionId; + item.abilityIconId = ability->iconId; + records.emplace_back(item); + } + return true; +} + bool BundleDataMgr::RestoreUidAndGid() { // this function should be called with bundleInfoMutex_ locked @@ -1081,7 +1210,7 @@ bool BundleDataMgr::RestoreUidAndGid() } bool BundleDataMgr::NotifyBundleStatus(const std::string &bundleName, const std::string &modulePackage, - const std::string &mainAbility, const ErrCode resultCode, const NotifyType type) + const std::string &mainAbility, const ErrCode resultCode, const NotifyType type, const int32_t &uid) { APP_LOGI("notify type %{public}d with %{public}d for %{public}s-%{public}s in %{public}s", type, @@ -1130,6 +1259,8 @@ bool BundleDataMgr::NotifyBundleStatus(const std::string &bundleName, const std: element.SetBundleName(bundleName); element.SetAbilityName(mainAbility); want.SetElement(element); + want.SetParam(Constants::UID, uid); + APP_LOGI("want.SetParam uid %{public}d", uid); EventFwk::CommonEventData commonData{want}; EventFwk::CommonEventManager::PublishCommonEvent(commonData); return true; @@ -1315,6 +1446,75 @@ bool BundleDataMgr::GetFormsInfoByApp(const std::string &bundleName, std::vector return true; } +bool BundleDataMgr::NotifyActivityLifeStatus( + const std::string &bundleName, const std::string &abilityName, const int64_t launchTime) const +{ + APP_LOGI("NotifyActivityLifeStatus %{public}s, %{public}s", bundleName.c_str(), abilityName.c_str()); + if (bundleName.empty() || abilityName.empty()) { + return false; + } + std::lock_guard lock(bundleInfoMutex_); + if (bundleInfos_.empty()) { + APP_LOGI("bundleInfos_ data is empty"); + return false; + } + auto infoItem = bundleInfos_.find(bundleName); + if (infoItem == bundleInfos_.end()) { + return false; + } + APP_LOGI("NotifyActivityLifeStatus %{public}s", infoItem->first.c_str()); + auto bundleInfo = infoItem->second.find(Constants::CURRENT_DEVICE_ID); + if (bundleInfo == infoItem->second.end()) { + return false; + } + if (bundleInfo->second.IsDisabled()) { + APP_LOGI("app %{public}s is disabled", bundleInfo->second.GetBundleName().c_str()); + return false; + } + auto ability = bundleInfo->second.FindAbilityInfo(bundleName, abilityName); + if (!ability) { + APP_LOGE("ability:%{public}s not find", abilityName.c_str()); + return false; + } + if (ability->type != AbilityType::PAGE) { + APP_LOGE("ability:%{public}s type is not PAGE", abilityName.c_str()); + return false; + } + ModuleUsageRecord moduleUsageRecord; + moduleUsageRecord.bundleName = bundleName; + moduleUsageRecord.name = ability->moduleName; + moduleUsageRecord.abilityName = abilityName; + moduleUsageRecord.lastLaunchTime = launchTime; + moduleUsageRecord.launchedCount = 1; + return usageRecordStorage_->AddOrUpdateRecord(moduleUsageRecord, Constants::CURRENT_DEVICE_ID, 0); +} + +bool BundleDataMgr::UpdateUsageRecordOnBundleRemoved( + bool keepUsage, const int userId, const std::string &bundleName) const +{ + std::lock_guard lock(bundleInfoMutex_); + if (bundleInfos_.empty()) { + APP_LOGI("bundleInfos_ data is empty"); + return false; + } + auto infoItem = bundleInfos_.find(bundleName); + if (infoItem == bundleInfos_.end()) { + return false; + } + APP_LOGI("UpdateUsageRecordOnBundleRemoved %{public}s", infoItem->first.c_str()); + auto bundleInfo = infoItem->second.find(Constants::CURRENT_DEVICE_ID); + if (bundleInfo == infoItem->second.end()) { + return false; + } + if (bundleInfo->second.IsDisabled()) { + APP_LOGI("app %{public}s is disabled", bundleInfo->second.GetBundleName().c_str()); + return false; + } + std::vector moduleNames; + return keepUsage ? usageRecordStorage_->MarkUsageRecordRemoved(bundleInfo->second, userId) + : usageRecordStorage_->DeleteUsageRecord(bundleInfo->second, userId); +} + bool BundleDataMgr::GetShortcutInfos(const std::string &bundleName, std::vector &shortcutInfos) const { if (bundleName.empty()) { @@ -1343,5 +1543,164 @@ bool BundleDataMgr::GetShortcutInfos(const std::string &bundleName, std::vector< return true; } +bool BundleDataMgr::RegisterAllPermissionsChanged(const sptr &callback) +{ + if (!callback) { + APP_LOGE("callback is nullptr"); + return false; + } + std::lock_guard lock(allPermissionsChangedLock_); + std::set>::iterator it = allPermissionsCallbacks_.begin(); + while (it != allPermissionsCallbacks_.end()) { + if ((*it)->AsObject() == callback->AsObject()) { + break; + } + it++; + } + if (it == allPermissionsCallbacks_.end()) { + allPermissionsCallbacks_.emplace(callback); + } + APP_LOGD("all permissions callbacks size = %{public}zu", allPermissionsCallbacks_.size()); + return AddDeathRecipient(callback); +} + +bool BundleDataMgr::RegisterPermissionsChanged( + const std::vector &uids, const sptr &callback) +{ + if (!callback) { + APP_LOGE("callback is nullptr"); + return false; + } + std::lock_guard lock(permissionsChangedLock_); + for (int32_t uid : uids) { + std::set>::iterator it = permissionsCallbacks_[uid].begin(); + while (it != permissionsCallbacks_[uid].end()) { + if ((*it)->AsObject() == callback->AsObject()) { + break; + } + it++; + } + if (it == permissionsCallbacks_[uid].end()) { + permissionsCallbacks_[uid].emplace(callback); + } + } + APP_LOGD("specified permissions callbacks size = %{public}zu", permissionsCallbacks_.size()); + + for (const auto &item1 : permissionsCallbacks_) { + APP_LOGD("item1->first = %{public}d", item1.first); + APP_LOGD("item1->second.size() = %{public}zu", item1.second.size()); + } + return AddDeathRecipient(callback); +} + +bool BundleDataMgr::AddDeathRecipient(const sptr &callback) +{ + if (!callback) { + APP_LOGE("callback is nullptr"); + return false; + } + auto object = callback->AsObject(); + if (!object) { + APP_LOGW("callback object is nullptr"); + return false; + } + // add callback death recipient. + sptr deathRecipient = new PermissionChangedDeathRecipient(); + object->AddDeathRecipient(deathRecipient); + return true; +} + +bool BundleDataMgr::UnregisterPermissionsChanged(const sptr &callback) +{ + bool ret = false; + if (!callback) { + APP_LOGE("callback is nullptr"); + return ret; + } + { + std::lock_guard lock(allPermissionsChangedLock_); + + for (auto it = allPermissionsCallbacks_.begin(); it != allPermissionsCallbacks_.end();) { + if ((*it)->AsObject() == callback->AsObject()) { + it = allPermissionsCallbacks_.erase(it); + APP_LOGI("unregister from all permissions callbacks success!"); + ret = true; + break; + } else { + it++; + } + } + } + { + std::lock_guard lock(permissionsChangedLock_); + for (auto mapIter = permissionsCallbacks_.begin(); mapIter != permissionsCallbacks_.end();) { + for (auto it = mapIter->second.begin(); it != mapIter->second.end();) { + if ((*it)->AsObject() == callback->AsObject()) { + it = mapIter->second.erase(it); + APP_LOGI("unregister from specific permissions callbacks success!"); + APP_LOGD("mapIter->first = %{public}d", (*mapIter).first); + APP_LOGD("*mapIter.second.size() = %{public}zu", (*mapIter).second.size()); + ret = true; + } else { + it++; + } + } + if (mapIter->second.empty()) { + mapIter = permissionsCallbacks_.erase(mapIter); + } else { + mapIter++; + } + } + } + for (const auto &item1 : permissionsCallbacks_) { + APP_LOGD("item1->first = %{public}d", item1.first); + APP_LOGD("item1->second.size() = %{public}zu", item1.second.size()); + } + return ret; +} +bool BundleDataMgr::NotifyPermissionsChanged(int32_t uid) +{ + if (uid < 0) { + APP_LOGE("uid(%{private}d) is invalid", uid); + return false; + } + APP_LOGI("notify permission changed, uid = %{public}d", uid); + // for all permissions callback. + { + std::lock_guard lock(allPermissionsChangedLock_); + for (const auto &item : allPermissionsCallbacks_) { + if (!item) { + APP_LOGE("callback is nullptr"); + return false; + } + + item->OnChanged(uid); + APP_LOGD("all permissions changed callback"); + } + } + // for uid permissions callback. + { + std::lock_guard lock(permissionsChangedLock_); + APP_LOGD("specified permissions callbacks size = %{public}zu", permissionsCallbacks_.size()); + for (const auto &item1 : permissionsCallbacks_) { + APP_LOGD("item1->first = %{public}d", item1.first); + APP_LOGD("item1->second.size() = %{public}zu", item1.second.size()); + } + auto callbackItem = permissionsCallbacks_.find(uid); + if (callbackItem != permissionsCallbacks_.end()) { + auto callbacks = callbackItem->second; + for (const auto &item : callbacks) { + if (!item) { + APP_LOGE("callback is nullptr"); + return false; + } + item->OnChanged(uid); + APP_LOGD("specified permissions changed callback"); + } + } + } + return true; +} + } // namespace AppExecFwk -} // namespace OHOS +} // namespace OHOS \ No newline at end of file diff --git a/services/bundlemgr/src/bundle_data_storage_database.cpp b/services/bundlemgr/src/bundle_data_storage_database.cpp index cb8f45a7d5..dcca4b3068 100644 --- a/services/bundlemgr/src/bundle_data_storage_database.cpp +++ b/services/bundlemgr/src/bundle_data_storage_database.cpp @@ -34,6 +34,7 @@ BundleDataStorageDatabase::BundleDataStorageDatabase() { APP_LOGI("instance:%{private}p is created", this); TryTwice([this] { return GetKvStore(); }); + RegisterKvStoreDeathListener(); } BundleDataStorageDatabase::~BundleDataStorageDatabase() diff --git a/services/bundlemgr/src/bundle_mgr_host_impl.cpp b/services/bundlemgr/src/bundle_mgr_host_impl.cpp index 7d9a94cda7..a68c60b46b 100755 --- a/services/bundlemgr/src/bundle_mgr_host_impl.cpp +++ b/services/bundlemgr/src/bundle_mgr_host_impl.cpp @@ -140,6 +140,16 @@ bool BundleMgrHostImpl::QueryAbilityInfo(const Want &want, AbilityInfo &abilityI return dataMgr->QueryAbilityInfo(want, abilityInfo); } +bool BundleMgrHostImpl::QueryAbilityInfos(const Want &want, std::vector &abilityInfos) +{ + auto dataMgr = GetDataMgrFromService(); + if (dataMgr == nullptr) { + APP_LOGE("DataMgr is nullptr"); + return false; + } + return dataMgr->QueryAbilityInfos(want, abilityInfos); +} + bool BundleMgrHostImpl::QueryAbilityInfoByUri(const std::string &abilityUri, AbilityInfo &abilityInfo) { auto dataMgr = GetDataMgrFromService(); @@ -471,23 +481,52 @@ bool BundleMgrHostImpl::RequestPermissionFromUser( APP_LOGE("fail to CanRequestPermission due to params empty"); return false; } - return BundlePermissionMgr::RequestPermissionFromUser(bundleName, permissionName, userId); + bool ret = BundlePermissionMgr::RequestPermissionFromUser(bundleName, permissionName, userId); + // send Permissions Changed event + APP_LOGI("send Permissions Changed event"); + BundleInfo info; + bool ret_getInfo = GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, info); + APP_LOGI("ret_getInfo = %{public}d",ret_getInfo); + if ( ret && ret_getInfo) { + Want want; + want.SetAction("PERMISSIONS_CHANGED_EVENT"); + EventFwk::CommonEventData commonData; + commonData.SetWant(want); + commonData.SetCode(info.uid); + EventFwk::CommonEventManager::PublishCommonEvent(commonData); + } + return ret; } bool BundleMgrHostImpl::RegisterAllPermissionsChanged(const sptr &callback) { - return true; + auto dataMgr = GetDataMgrFromService(); + if (dataMgr == nullptr) { + APP_LOGE("DataMgr is nullptr"); + return false; + } + return dataMgr->RegisterAllPermissionsChanged(callback); } bool BundleMgrHostImpl::RegisterPermissionsChanged( const std::vector &uids, const sptr &callback) { - return true; + auto dataMgr = GetDataMgrFromService(); + if (dataMgr == nullptr) { + APP_LOGE("DataMgr is nullptr"); + return false; + } + return dataMgr->RegisterPermissionsChanged(uids,callback); } bool BundleMgrHostImpl::UnregisterPermissionsChanged(const sptr &callback) { - return true; + auto dataMgr = GetDataMgrFromService(); + if (dataMgr == nullptr) { + APP_LOGE("DataMgr is nullptr"); + return false; + } + return dataMgr->UnregisterPermissionsChanged(callback); } bool BundleMgrHostImpl::GetAllFormsInfo(std::vector &formInfos) @@ -531,6 +570,28 @@ bool BundleMgrHostImpl::GetShortcutInfos(const std::string &bundleName, std::vec return dataMgr->GetShortcutInfos(bundleName, shortcutInfos); } +bool BundleMgrHostImpl::GetModuleUsageRecords(const int32_t number, std::vector &moduleUsageRecords) +{ + auto dataMgr = GetDataMgrFromService(); + if (dataMgr == nullptr) { + APP_LOGE("DataMgr is nullptr"); + return false; + } + return dataMgr->GetUsageRecords(number, moduleUsageRecords); +} + +bool BundleMgrHostImpl::NotifyActivityLifeStatus( + const std::string &bundleName, const std::string &abilityName, const int64_t launchTime) +{ + APP_LOGI("NotifyActivityLifeStatus begin"); + std::thread([this, bundleName, abilityName, launchTime]() { + auto dataMgr = GetDataMgrFromService(); + dataMgr->NotifyActivityLifeStatus(bundleName, abilityName, launchTime); + }).detach(); + APP_LOGI("NotifyActivityLifeStatus end"); + return true; +} + const std::shared_ptr BundleMgrHostImpl::GetDataMgrFromService() { return DelayedSingleton::GetInstance()->GetDataMgr(); diff --git a/services/bundlemgr/src/bundle_mgr_service.cpp b/services/bundlemgr/src/bundle_mgr_service.cpp index fd3020f0b7..0de41228d3 100644 --- a/services/bundlemgr/src/bundle_mgr_service.cpp +++ b/services/bundlemgr/src/bundle_mgr_service.cpp @@ -51,6 +51,9 @@ BundleMgrService::~BundleMgrService() if (dataMgr_) { dataMgr_.reset(); } + if (perChangeSub_) { + perChangeSub_.reset(); + } APP_LOGI("instance is destroyed"); } @@ -81,6 +84,9 @@ void BundleMgrService::OnStop() { APP_LOGI("OnStop is called"); SelfClean(); + if (perChangeSub_) { + EventFwk::CommonEventManager::UnSubscribeCommonEvent(perChangeSub_); + } } bool BundleMgrService::IsServiceReady() const @@ -143,7 +149,13 @@ bool BundleMgrService::Init() handler_->SendEvent(BMSEventHandler::BUNDLE_SCAN_START); needToScan_ = true; } - + if (!perChangeSub_) { + EventFwk::MatchingSkills matchingSkills; + matchingSkills.AddEvent("PERMISSIONS_CHANGED_EVENT"); + EventFwk::CommonEventSubscribeInfo subscribeInfo(matchingSkills); + perChangeSub_ = std::make_shared(dataMgr_, subscribeInfo); + EventFwk::CommonEventManager::SubscribeCommonEvent(perChangeSub_); + } ready_ = true; APP_LOGI("init end success"); return true; diff --git a/services/bundlemgr/src/bundle_permission_mgr.cpp b/services/bundlemgr/src/bundle_permission_mgr.cpp index be095ae15f..91a84da117 100644 --- a/services/bundlemgr/src/bundle_permission_mgr.cpp +++ b/services/bundlemgr/src/bundle_permission_mgr.cpp @@ -26,8 +26,8 @@ namespace AppExecFwk { using namespace OHOS::Security; namespace { -const std::string HOS_NORMAL_APP = "hos_normal_app"; -const std::string HOS_SYSTEM_APP = "hos_system_app"; +const std::string HOS_NORMAL_APP = "ohos_normal_app"; +const std::string HOS_SYSTEM_APP = "ohos_system_app"; // convert the Permission::PermissionDef struct to // AppExecFwk::PermissionDef struct that can be used in IPC process bool ConvertPermissionDef(const Permission::PermissionDef &permDef, PermissionDef &permissionDef) diff --git a/services/bundlemgr/src/bundle_profile.cpp b/services/bundlemgr/src/bundle_profile.cpp index b1b62331e6..1f53df16c4 100644 --- a/services/bundlemgr/src/bundle_profile.cpp +++ b/services/bundlemgr/src/bundle_profile.cpp @@ -149,6 +149,8 @@ struct Forms { std::string scheduledUpateTime = "0:0"; int32_t updateDuration = 0; std::string deepLink; + std::string formConfigAbility; + bool formVisibleNotify = false; std::string jsComponentName; FormsMetaData metaData; }; @@ -174,7 +176,7 @@ struct CustomizeData { struct MetaData { std::vector parameters; std::vector results; - std::vector customizeData; + std::vector customizeData; }; struct UriPermission { @@ -201,6 +203,8 @@ struct Ability { std::vector deviceCapability; MetaData metaData; std::string type; + std::string srcPath; + std::string srcLanguage = "js"; bool formEnabled = false; Form form; std::string orientation = "unspecified"; @@ -256,6 +260,7 @@ struct Module { std::string package; std::string name; std::string description; + int32_t descriptionId = 0; std::string colorMode = "auto"; std::vector supportedModes; std::vector reqCapabilities; @@ -789,7 +794,7 @@ void from_json(const nlohmann::json &jsonObject, MetaData &metaData) { // these are not required fields. const auto &jsonObjectEnd = jsonObject.end(); - GetValueIfFindKey>(jsonObject, + GetValueIfFindKey>(jsonObject, jsonObjectEnd, BUNDLE_MODULE_META_KEY_CUSTOMIZE_DATA, metaData.customizeData, @@ -976,6 +981,22 @@ void from_json(const nlohmann::json &jsonObject, Forms &forms) false, parseResult, ArrayType::NOT_ARRAY); + GetValueIfFindKey(jsonObject, + jsonObjectEnd, + BUNDLE_MODULE_PROFILE_FORMS_FORM_CONFIG_ABILITY, + forms.formConfigAbility, + JsonType::STRING, + false, + parseResult, + ArrayType::NOT_ARRAY); + GetValueIfFindKey(jsonObject, + jsonObjectEnd, + BUNDLE_MODULE_PROFILE_FORMS_FORM_VISIBLE_NOTIFY, + forms.formVisibleNotify, + JsonType::BOOLEAN, + false, + parseResult, + ArrayType::NOT_ARRAY); GetValueIfFindKey(jsonObject, jsonObjectEnd, BUNDLE_MODULE_PROFILE_KEY_META_DATA, @@ -1037,6 +1058,22 @@ void from_json(const nlohmann::json &jsonObject, Ability &ability) parseResult, ArrayType::NOT_ARRAY); // these are not required fields. + GetValueIfFindKey(jsonObject, + jsonObjectEnd, + PROFILE_KEY_SRCPATH, + ability.srcPath, + JsonType::STRING, + false, + parseResult, + ArrayType::NOT_ARRAY); + GetValueIfFindKey(jsonObject, + jsonObjectEnd, + PROFILE_KEY_SRCLANGUAGE, + ability.srcLanguage, + JsonType::STRING, + false, + parseResult, + ArrayType::NOT_ARRAY); GetValueIfFindKey(jsonObject, jsonObjectEnd, PROFILE_KEY_DESCRIPTION, @@ -1509,6 +1546,14 @@ void from_json(const nlohmann::json &jsonObject, Module &module) false, parseResult, ArrayType::NOT_ARRAY); + GetValueIfFindKey(jsonObject, + jsonObjectEnd, + PROFILE_KEY_DESCRIPTION_ID, + module.descriptionId, + JsonType::NUMBER, + false, + parseResult, + ArrayType::NOT_ARRAY); GetValueIfFindKey>(jsonObject, jsonObjectEnd, BUNDLE_MODULE_PROFILE_KEY_SUPPORTED_MODES, @@ -1686,8 +1731,7 @@ bool CheckModuleInfosIsValid(ProfileReader::ConfigJson &configJson) } return true; } - -uint32_t GetFormEntity(const std::vector& formEntity) +uint32_t GetFormEntity(const std::vector &formEntity) { if (ProfileReader::formEntityMap.empty()) { ProfileReader::formEntityMap.insert({ProfileReader::KEY_HOME_SCREEN, ProfileReader::VALUE_HOME_SCREEN}); @@ -1695,7 +1739,7 @@ uint32_t GetFormEntity(const std::vector& formEntity) } uint32_t formEntityInBinary = 0; - for (const auto& item : formEntity) { + for (const auto &item : formEntity) { if (ProfileReader::formEntityMap.find(item) != ProfileReader::formEntityMap.end()) { formEntityInBinary |= ProfileReader::formEntityMap[item]; } @@ -1708,7 +1752,8 @@ bool ConvertFormInfo(FormInfo &forminfos, const ProfileReader::Forms &form) forminfos.name = form.name; forminfos.description = form.description; forminfos.descriptionId = form.descriptionId; - forminfos.formConfigAbility = form.deepLink; + forminfos.formConfigAbility = form.formConfigAbility; + forminfos.formVisibleNotify = form.formVisibleNotify; forminfos.deepLink = form.deepLink; forminfos.defaultFlag = form.isDefault; auto type = std::find_if(std::begin(ProfileReader::formTypeMap), @@ -1727,13 +1772,13 @@ bool ConvertFormInfo(FormInfo &forminfos, const ProfileReader::Forms &form) forminfos.scheduledUpateTime = form.scheduledUpateTime; forminfos.updateDuration = form.updateDuration; forminfos.jsComponentName = form.jsComponentName; - for (auto data : form.metaData.customizeData) { + for (auto &data : form.metaData.customizeData) { FormCustomizeData customizeData; customizeData.name = data.name; customizeData.value = data.value; forminfos.customizeDatas.emplace_back(customizeData); } - for (const auto dimensions : form.supportDimensions) { + for (const auto &dimensions : form.supportDimensions) { auto dimension = std::find_if(std::begin(ProfileReader::dimensionMap), std::end(ProfileReader::dimensionMap), [&dimensions](const auto &item) { return item.first == dimensions; }); @@ -1801,21 +1846,21 @@ bool TransformToInfo(const ProfileReader::ConfigJson &configJson, BundleInfo &bu void GetMetaData(MetaData &metaData, const ProfileReader::MetaData &profileMetaData) { - for (const auto& item : profileMetaData.parameters) { + for (const auto &item : profileMetaData.parameters) { Parameters parameter; parameter.description = item.description; parameter.name = item.name; parameter.type = item.type; metaData.parameters.emplace_back(parameter); } - for (const auto& item : profileMetaData.results) { + for (const auto &item : profileMetaData.results) { Results result; result.description = item.description; result.name = item.name; result.type = item.type; metaData.results.emplace_back(result); } - for (const auto& item : profileMetaData.customizeData) { + for (const auto &item : profileMetaData.customizeData) { CustomizeData customizeData; customizeData.name = item.name; customizeData.extra = item.extra; @@ -1829,6 +1874,7 @@ bool TransformToInfo(const ProfileReader::ConfigJson &configJson, InnerModuleInf innerModuleInfo.modulePackage = configJson.module.package; innerModuleInfo.moduleName = configJson.module.distro.moduleName; innerModuleInfo.description = configJson.module.description; + innerModuleInfo.descriptionId = configJson.module.descriptionId; auto colorModeInfo = std::find_if(std::begin(ProfileReader::moduleColorMode), std::end(ProfileReader::moduleColorMode), [&configJson](const auto &item) { return item.first == configJson.module.colorMode; }); @@ -1847,11 +1893,19 @@ bool TransformToInfo( const ProfileReader::ConfigJson &configJson, const ProfileReader::Ability &ability, AbilityInfo &abilityInfo) { abilityInfo.name = ability.name; + if (ability.srcLanguage != "c++" && ability.name.substr(0, 1) == ".") { + abilityInfo.name = configJson.module.package + ability.name; + } abilityInfo.label = ability.label; abilityInfo.description = ability.description; abilityInfo.iconPath = ability.icon; + abilityInfo.labelId = ability.labelId; + abilityInfo.descriptionId = ability.descriptionId; + abilityInfo.iconId = ability.iconId; abilityInfo.visible = ability.visible; abilityInfo.kind = ability.type; + abilityInfo.srcPath = ability.srcPath; + abilityInfo.srcLanguage = ability.srcLanguage; auto iterType = std::find_if(std::begin(ProfileReader::ABILITY_TYPE_MAP), std::end(ProfileReader::ABILITY_TYPE_MAP), [&ability](const auto &item) { return item.first == ability.type; }); @@ -1882,6 +1936,10 @@ bool TransformToInfo( abilityInfo.theme = ability.theme; abilityInfo.deviceTypes = configJson.module.deviceType; abilityInfo.deviceCapabilities = ability.deviceCapability; + if (iterType->second == AbilityType::DATA && + ability.uri.find(Constants::DATA_ABILITY_URI_PREFIX) == std::string::npos) { + return false; + } abilityInfo.uri = ability.uri; abilityInfo.package = configJson.module.package; abilityInfo.bundleName = configJson.app.bundleName; @@ -1889,8 +1947,10 @@ bool TransformToInfo( abilityInfo.applicationName = configJson.app.bundleName; abilityInfo.targetAbility = ability.targetAbility; abilityInfo.enabled = true; + abilityInfo.supportPipMode = ability.supportPipMode; abilityInfo.readPermission = ability.readPermission; abilityInfo.writePermission = ability.writePermission; + abilityInfo.configChanges = ability.configChanges; abilityInfo.formEntity = GetFormEntity(ability.form.formEntity); abilityInfo.minFormHeight = ability.form.minHeight; abilityInfo.defaultFormHeight = ability.form.defaultHeight; @@ -1951,6 +2011,9 @@ bool TransformToInfo(ProfileReader::ConfigJson &configJson, InnerBundleInfo &inn FormInfo formInfo; ConvertFormInfo(formInfo, form); formInfo.abilityName = ability.name; + if (ability.srcLanguage != "c++" && ability.name.substr(0, 1) == ".") { + formInfo.abilityName = configJson.module.package + ability.name; + } formInfo.bundleName = configJson.app.bundleName; formInfo.moduleName = configJson.module.distro.moduleName; formInfo.package = configJson.module.package; @@ -1967,6 +2030,9 @@ bool TransformToInfo(ProfileReader::ConfigJson &configJson, InnerBundleInfo &inn (find == false)) { innerBundleInfo.SetMainAbility(keyName); innerBundleInfo.SetMainAbilityName(ability.name); + if (ability.srcLanguage != "c++" && ability.name.substr(0, 1) == ".") { + innerBundleInfo.SetMainAbilityName(configJson.module.package + ability.name); + } // if there is main ability, it's label will be the application's label applicationInfo.label = ability.label; applicationInfo.labelId = ability.labelId; @@ -1974,6 +2040,10 @@ bool TransformToInfo(ProfileReader::ConfigJson &configJson, InnerBundleInfo &inn applicationInfo.iconId = ability.iconId; applicationInfo.description = ability.description; applicationInfo.descriptionId = ability.descriptionId; + if (innerModuleInfo.label.empty()) { + innerModuleInfo.label = ability.label; + innerModuleInfo.labelId = ability.labelId; + } find = true; } if (std::find(skill.entities.begin(), skill.entities.end(), Constants::FLAG_HOME_INTENT_FROM_SYSTEM) != diff --git a/services/bundlemgr/src/inner_bundle_info.cpp b/services/bundlemgr/src/inner_bundle_info.cpp index 8d4251b3c3..5e6bd27c98 100644 --- a/services/bundlemgr/src/inner_bundle_info.cpp +++ b/services/bundlemgr/src/inner_bundle_info.cpp @@ -41,6 +41,10 @@ const std::string MODULE_PACKAGE = "modulePackage"; const std::string MODULE_PATH = "modulePath"; const std::string MODULE_NAME = "moduleName"; const std::string MODULE_DESCRIPTION = "description"; +const std::string MODULE_DESCRIPTION_ID = "descriptionId"; +const std::string MODULE_LABEL = "label"; +const std::string MODULE_LABEL_ID = "labelId"; +const std::string MODULE_DESCRIPTION_INSTALLATION_FREE = "installationFree"; const std::string MODULE_IS_ENTRY = "isEntry"; const std::string MODULE_METADATA = "metaData"; const std::string MODULE_COLOR_MODE = "colorMode"; @@ -67,14 +71,13 @@ InnerBundleInfo::~InnerBundleInfo() APP_LOGD("inner bundle info instance is destroyed"); } - - void to_json(nlohmann::json &jsonObject, const Distro &distro) { jsonObject = nlohmann::json{ {ProfileReader::BUNDLE_MODULE_PROFILE_KEY_DELIVERY_WITH_INSTALL, distro.deliveryWithInstall}, {ProfileReader::BUNDLE_MODULE_PROFILE_KEY_MODULE_NAME, distro.moduleName}, - {ProfileReader::BUNDLE_MODULE_PROFILE_KEY_MODULE_TYPE, distro.moduleType} + {ProfileReader::BUNDLE_MODULE_PROFILE_KEY_MODULE_TYPE, distro.moduleType}, + {ProfileReader::BUNDLE_MODULE_PROFILE_KEY_MODULE_INSTALLATION_FREE, distro.installationFree} }; } @@ -121,6 +124,10 @@ void to_json(nlohmann::json &jsonObject, const InnerModuleInfo &info) {MODULE_COLOR_MODE, info.colorMode}, {MODULE_DISTRO, info.distro}, {MODULE_DESCRIPTION, info.description}, + {MODULE_DESCRIPTION_ID, info.descriptionId}, + {MODULE_LABEL, info.label}, + {MODULE_LABEL_ID, info.labelId}, + {MODULE_DESCRIPTION_INSTALLATION_FREE, info.installationFree}, {MODULE_REQ_CAPABILITIES, info.reqCapabilities}, {MODULE_REQ_PERMS, info.reqPermissions}, {MODULE_DEF_PERMS, info.defPermissions}, @@ -255,6 +262,38 @@ void from_json(const nlohmann::json &jsonObject, InnerModuleInfo &info) false, ProfileReader::parseResult, ArrayType::NOT_ARRAY); + GetValueIfFindKey(jsonObject, + jsonObjectEnd, + MODULE_DESCRIPTION_ID, + info.descriptionId, + JsonType::NUMBER, + false, + ProfileReader::parseResult, + ArrayType::NOT_ARRAY); + GetValueIfFindKey(jsonObject, + jsonObjectEnd, + MODULE_LABEL, + info.label, + JsonType::STRING, + false, + ProfileReader::parseResult, + ArrayType::NOT_ARRAY); + GetValueIfFindKey(jsonObject, + jsonObjectEnd, + MODULE_LABEL_ID, + info.labelId, + JsonType::NUMBER, + false, + ProfileReader::parseResult, + ArrayType::NOT_ARRAY); + GetValueIfFindKey(jsonObject, + jsonObjectEnd, + MODULE_DESCRIPTION_INSTALLATION_FREE, + info.installationFree, + JsonType::BOOLEAN, + false, + ProfileReader::parseResult, + ArrayType::NOT_ARRAY); GetValueIfFindKey>(jsonObject, jsonObjectEnd, MODULE_REQ_CAPABILITIES, @@ -374,8 +413,6 @@ void from_json(const nlohmann::json &jsonObject, Skill &skill) ArrayType::OBJECT); } - - void from_json(const nlohmann::json &jsonObject, Distro &distro) { const auto &jsonObjectEnd = jsonObject.end(); @@ -403,6 +440,15 @@ void from_json(const nlohmann::json &jsonObject, Distro &distro) true, ProfileReader::parseResult, ArrayType::NOT_ARRAY); + // mustFlag decide by distro.moduleType + GetValueIfFindKey(jsonObject, + jsonObjectEnd, + ProfileReader::BUNDLE_MODULE_PROFILE_KEY_MODULE_INSTALLATION_FREE, + distro.installationFree, + JsonType::BOOLEAN, + false, + ProfileReader::parseResult, + ArrayType::NOT_ARRAY); } void from_json(const nlohmann::json &jsonObject, UsedScene &usedScene) @@ -723,6 +769,26 @@ std::optional InnerBundleInfo::FindAbilityInfo( return std::nullopt; } +std::optional> InnerBundleInfo::FindAbilityInfos(const std::string &bundleName) const +{ + std::vector abilitys; + + if (bundleName.empty()) { + return std::nullopt; + } + + for (const auto &ability : baseAbilityInfos_) { + if ((ability.second.bundleName == bundleName)) { + abilitys.emplace_back(ability.second); + } + } + if (!abilitys.empty()) { + return abilitys; + } + + return std::nullopt; +} + bool InnerBundleInfo::AddModuleInfo(const InnerBundleInfo &newInfo) { if (newInfo.currentPackage_.empty()) { @@ -941,5 +1007,22 @@ void InnerBundleInfo::GetShortcutInfos(std::vector &shortcutInfos) } } +std::optional InnerBundleInfo::GetInnerModuleInfoByModuleName(const std::string &moduleName) const +{ + for (const auto &innerModuleInfo : innerModuleInfos_) { + if (innerModuleInfo.second.moduleName == moduleName) { + return innerModuleInfo.second; + } + } + return std::nullopt; +} + +void InnerBundleInfo::GetModuleNames(std::vector &moduleNames) const +{ + for (const auto &innerModuleInfo : innerModuleInfos_) { + moduleNames.emplace_back(innerModuleInfo.second.moduleName); + } +} + } // namespace AppExecFwk } // namespace OHOS diff --git a/services/bundlemgr/src/module_usage_data_storage.cpp b/services/bundlemgr/src/module_usage_data_storage.cpp new file mode 100644 index 0000000000..5044b12a8f --- /dev/null +++ b/services/bundlemgr/src/module_usage_data_storage.cpp @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2021 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 "module_usage_data_storage.h" + +#include +#include +#include "datetime_ex.h" +#include "permission/permission_kit.h" +#include "string_ex.h" + +#include "app_log_wrapper.h" +#include "bundle_util.h" +#include "kvstore_death_recipient_callback.h" +#include "nlohmann/json.hpp" + +using namespace OHOS::DistributedKv; + +namespace OHOS { +namespace AppExecFwk { +namespace { + +const int32_t MAX_TIMES = 6000; // tem min +const int32_t SLEEP_INTERVAL = 100 * 1000; // 100ms +const std::string POUND_KEY_SEPARATOR = "#"; +const std::string SCHEMA_DEFINE = "{\"SCHEMA_VERSION\":\"1.0\"," + "\"SCHEMA_MODE\":\"COMPATIBLE\"," + "\"SCHEMA_SKIPSIZE\":0," + "\"SCHEMA_DEFINE\":{" + "\"launchedCount\":\"INTEGER, NOT NULL\"," + "\"lastLaunchTime\":\"LONG, NOT NULL\"," + "\"isRemoved\":\"BOOL, NOT NULL\"" + "}," + "\"SCHEMA_INDEXES\":[\"$.lastLaunchTime\"]}"; +} // namespace + +ModuleUsageRecordStorage::ModuleUsageRecordStorage() +{ + APP_LOGI("usage instance is created"); + TryTwice([this] { return GetKvStore(); }); +} + +ModuleUsageRecordStorage::~ModuleUsageRecordStorage() +{ + APP_LOGI("usage instance is destroyed"); + dataManager_.CloseKvStore(appId_, std::move(kvStorePtr_)); +} + +void ModuleUsageRecordStorage::RegisterKvStoreDeathListener() +{} + +bool ModuleUsageRecordStorage::ParseKey(const std::string &key, ModuleUsageRecord &record) const +{ + std::vector splitKeys; + SplitStr(key, POUND_KEY_SEPARATOR, splitKeys); + if (splitKeys.size() != DATABASE_KEY_INDEX_MAX_LENGTH) { + APP_LOGE("error key, parsed failed!"); + return false; + } + + record.bundleName = (splitKeys[DATABASE_KEY_INDEX_BUNDLE_NAME]); + record.name = (splitKeys[DATABASE_KEY_INDEX_MODULE_NAME]); + APP_LOGD( + "parseKey::bundleName = %{public}s, moduleName = %{public}s", record.bundleName.c_str(), record.name.c_str()); + return true; +} + +void ModuleUsageRecordStorage::AbilityRecordToKey(const std::string &userId, const std::string &deviceId, + const std::string &bundleName, const std::string &moduleName, std::string &key) const +{ + // deviceId_bundleName_moduleName + key.append(userId); + key.append(POUND_KEY_SEPARATOR); + key.append(deviceId); + key.append(POUND_KEY_SEPARATOR); + key.append(bundleName); + key.append(POUND_KEY_SEPARATOR); + key.append(moduleName); + APP_LOGD("userId = %{public}s, bundleName = %{public}s, moduleName = %{public}s", + userId.c_str(), + bundleName.c_str(), + moduleName.c_str()); +} + +void ModuleUsageRecordStorage::UpdateUsageRecord(const std::string &jsonString, ModuleUsageRecord &data) +{ + nlohmann::json jsonObject; + jsonObject = nlohmann::json::parse(jsonString); + if (jsonObject.is_discarded()) { + APP_LOGE("failed to parse existing usage record: %{private}s.", jsonString.c_str()); + return; + } + uint32_t launchedCount = jsonObject.at(UsageRecordKey::LAUNCHED_COUNT).get(); + data.launchedCount = launchedCount + 1; + APP_LOGD("launchedCount = %{public}d", data.launchedCount); + return; +} + +bool ModuleUsageRecordStorage::AddOrUpdateRecord(ModuleUsageRecord &data, const std::string &deviceId, int32_t userId) +{ + APP_LOGI("add usage record data %{public}s", data.bundleName.c_str()); + { + std::lock_guard lock(kvStorePtrMutex_); + if (!CheckKvStore()) { + APP_LOGE("kvStore is nullptr"); + return false; + } + } + Status status; + bool isExist = false; + { + std::string keyOfData; + AbilityRecordToKey(std::to_string(userId), deviceId, data.bundleName, data.name, keyOfData); + Key key(keyOfData); + Value oldValue; + std::lock_guard lock(kvStorePtrMutex_); + status = kvStorePtr_->Get(key, oldValue); + if (status == Status::SUCCESS) { + APP_LOGD("get old value %{public}s", oldValue.ToString().c_str()); + // already isExist, update + UpdateUsageRecord(oldValue.ToString(), data); + isExist = true; + } + if (status == Status::KEY_NOT_FOUND || isExist) { + Value value(data.ToString()); + APP_LOGD("add to DB::value %{public}s", value.ToString().c_str()); + status = kvStorePtr_->Put(key, value); + APP_LOGW("add result = %{public}d", status); + if (status == Status::IPC_ERROR) { + status = kvStorePtr_->Put(key, value); + APP_LOGW("distribute database ipc error and try to call again, result = %{public}d", status); + } + } + } + + if (status != Status::SUCCESS) { + APP_LOGE("put value to kvStore error: %{public}d", status); + return false; + } + + APP_LOGD("update success"); + return true; +} + +bool ModuleUsageRecordStorage::DeleteRecordByKeys(const std::string &bundleName, std::vector &keys) +{ + if (keys.size() == 0) { + APP_LOGE("delete error: empty key"); + return false; + } + Status status; + { + std::lock_guard lock(kvStorePtrMutex_); + status = kvStorePtr_->DeleteBatch(keys); + if (status == Status::IPC_ERROR) { + status = kvStorePtr_->DeleteBatch(keys); + APP_LOGW("distribute database ipc error and try to call again, result = %{public}d", status); + } + } + + if (status != Status::SUCCESS) { + APP_LOGE("delete keys error: %{public}d", status); + return false; + } + APP_LOGD("delete success"); + return true; +} + +bool ModuleUsageRecordStorage::DeleteUsageRecord(const InnerBundleInfo &data, int32_t userId) +{ + APP_LOGD("delete usage data"); + { + std::lock_guard lock(kvStorePtrMutex_); + if (!CheckKvStore()) { + APP_LOGE("kvStore is nullptr"); + return false; + } + } + + std::vector keys; + InnerBundleInfoToKeys(data, userId, keys); + APP_LOGD("delete key %{public}zu", keys.size()); + return DeleteRecordByKeys(data.GetBundleName(), keys); +} + +bool ModuleUsageRecordStorage::MarkUsageRecordRemoved(const InnerBundleInfo &data, int32_t userId) +{ + { + std::lock_guard lock(kvStorePtrMutex_); + if (!CheckKvStore()) { + APP_LOGE("kvStore is nullptr"); + return false; + } + } + ModuleUsageRecord record; + Value value; + std::string jsonString; + std::vector keys; + InnerBundleInfoToKeys(data, userId, keys); + { + std::lock_guard lock(kvStorePtrMutex_); + for (const Key &key : keys) { + Status status = kvStorePtr_->Get(key, value); + if (status != Status::SUCCESS) { + APP_LOGD("database query by key error, result = %{public}d", status); + return false; + } + if (!record.FromJsonString(value.ToString())) { + APP_LOGW("database parse entry failed"); + return false; + } + if (!record.removed) { + record.removed = true; + jsonString = record.ToString(); + APP_LOGD("new value %{public}s", jsonString.c_str()); + value = jsonString; + status = kvStorePtr_->Put(key, value); + APP_LOGI("value update result: %{public}d", status); + } + } + } + return true; +} + +void ModuleUsageRecordStorage::InnerBundleInfoToKeys( + const InnerBundleInfo &data, int32_t userId, std::vector &keys) const +{ + std::vector mouduleNames; + data.GetModuleNames(mouduleNames); + const std::string &bundleName = data.GetBundleName(); + for (const auto &moduleName : mouduleNames) { + FillDataStorageKeys(std::to_string(userId), bundleName, moduleName, keys); + } +} + +void ModuleUsageRecordStorage::FillDataStorageKeys(const std::string &userId, const std::string &bundleName, + const std::string &moduleName, std::vector &keys) const +{ + std::string keyOfData; + AbilityRecordToKey(userId, Constants::CURRENT_DEVICE_ID, bundleName, moduleName, keyOfData); + Key key(keyOfData); + keys.push_back(key); +} + +void ModuleUsageRecordStorage::SaveEntries( + const std::vector &allEntries, std::vector &records) const +{ + APP_LOGD("SaveEntries %{public}zu", allEntries.size()); + for (const auto &item : allEntries) { + APP_LOGD("SaveEntries %{public}s", item.value.ToString().c_str()); + ModuleUsageRecord record; + if (!record.FromJsonString(item.value.ToString())) { + APP_LOGE("error entry: %{private}s", item.value.ToString().c_str()); + continue; + } + + if (!ParseKey(item.key.ToString(), record)) { + APP_LOGE("error key"); + continue; + } + records.emplace_back(record); + } +} + +bool ModuleUsageRecordStorage::QueryRecordByNum(int32_t maxNum, std::vector &records, int32_t userId) +{ + APP_LOGI("query record by num %{public}d userId %{public}d", maxNum, userId); + DataQuery query; + query.KeyPrefix(std::to_string(userId) + POUND_KEY_SEPARATOR + Constants::CURRENT_DEVICE_ID + POUND_KEY_SEPARATOR); + query.OrderByDesc(UsageRecordKey::SCHEMA_LAST_LAUNCH_TIME); + query.Limit(maxNum, 0); + std::vector allEntries; + bool queryResult = QueryRecordByCondition(query, allEntries); + if (!queryResult || static_cast(allEntries.size()) > maxNum) { + APP_LOGE("query record error"); + return queryResult; + } + APP_LOGD("query record success"); + SaveEntries(allEntries, records); + return true; +} + +bool ModuleUsageRecordStorage::QueryRecordByCondition(DataQuery &query, std::vector &records) +{ + Status status; + { + std::lock_guard lock(kvStorePtrMutex_); + if (!CheckKvStore()) { + APP_LOGE("kvStore is nullptr"); + return false; + } + } + + status = kvStorePtr_->GetEntriesWithQuery(query, records); + APP_LOGI("query record by condition %{public}d", status); + if (status == Status::IPC_ERROR) { + status = kvStorePtr_->GetEntriesWithQuery(query, records); + APP_LOGW("distribute database ipc error and try to call again, result = %{public}d", status); + } + + if (status != Status::SUCCESS) { + APP_LOGE("query key error: %{public}d", status); + return false; + } + return true; +} + +Status ModuleUsageRecordStorage::GetKvStore() +{ + Status status; + Options options = { + .createIfMissing = true, .encrypt = false, .autoSync = true, .kvStoreType = KvStoreType::SINGLE_VERSION}; + + options.schema = SCHEMA_DEFINE; + dataManager_.GetSingleKvStore( + options, appId_, storeId_, [this, &status](Status paramStatus, std::unique_ptr singleKvStore) { + status = paramStatus; + if (status != Status::SUCCESS) { + APP_LOGE("usage get kvStore error: %{public}d", status); + return; + } + { + kvStorePtr_ = std::move(singleKvStore); + } + APP_LOGI("usage get kvStore success"); + }); + + return status; +} + +void ModuleUsageRecordStorage::TryTwice(const std::function &func) const +{ + Status status = func(); + if (status == Status::IPC_ERROR) { + status = func(); + APP_LOGW("distribute database ipc error and try to call again, result = %{public}d", status); + } +} + +bool ModuleUsageRecordStorage::CheckKvStore() +{ + if (kvStorePtr_ != nullptr) { + return true; + } + int32_t tryTimes = MAX_TIMES; + while (tryTimes > 0) { + Status status = GetKvStore(); + if (status == Status::SUCCESS && kvStorePtr_ != nullptr) { + return true; + } + APP_LOGD("usage CheckKvStore, Times: %{public}d", tryTimes); + usleep(SLEEP_INTERVAL); + tryTimes--; + } + return kvStorePtr_ != nullptr; +} + +bool ModuleUsageRecordStorage::ResetKvStore() +{ + std::lock_guard lock(kvStorePtrMutex_); + kvStorePtr_ = nullptr; + Status status = GetKvStore(); + if (status == Status::SUCCESS && kvStorePtr_ != nullptr) { + return true; + } + APP_LOGW("usage reset failed"); + return false; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/bundlemgr/src/permission_changed_death_recipient.cpp b/services/bundlemgr/src/permission_changed_death_recipient.cpp new file mode 100644 index 0000000000..47eafa6227 --- /dev/null +++ b/services/bundlemgr/src/permission_changed_death_recipient.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2021 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 "permission_changed_death_recipient.h" + +#include "iremote_broker.h" + +#include "app_log_wrapper.h" +#include "bundle_mgr_service.h" + +namespace OHOS { +namespace AppExecFwk { + +void PermissionChangedDeathRecipient::OnRemoteDied(const wptr& object) +{ + APP_LOGI("permission changed callback died, remove the callback"); + sptr callback = iface_cast(object.promote()); + DelayedSingleton::GetInstance()->GetDataMgr()->UnregisterPermissionsChanged(callback); +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/bundlemgr/test/mock/include/mock_ability_mgr_host.h b/services/bundlemgr/test/mock/include/mock_ability_mgr_host.h index e702d4d634..df955fb472 100644 --- a/services/bundlemgr/test/mock/include/mock_ability_mgr_host.h +++ b/services/bundlemgr/test/mock/include/mock_ability_mgr_host.h @@ -190,6 +190,11 @@ public: return 0; } + int UpdateConfiguration(const DummyConfiguration &config) override + { + return 0; + } + virtual sptr GetWantSender( const WantSenderInfo &wantSenderInfo, const sptr &callerToken) override { @@ -239,6 +244,43 @@ public: { return 0; } + int MoveMissionToFloatingStack(const MissionOption &missionOption) override + { + return 0; + } + int MoveMissionToSplitScreenStack(const MissionOption &missionOption) override + { + return 0; + } + int MinimizeMultiWindow(int missionId) override + { + return 0; + } + int MaximizeMultiWindow(int missionId) override + { + return 0; + } + int GetFloatingMissions(std::vector &list) override + { + return 0; + } + int CloseMultiWindow(int missionId) override + { + return 0; + } + int SetMissionStackSetting(const StackSetting &stackSetting) override + { + return 0; + } + int StartAbility(const Want &want, const AbilityStartSetting &abilityStartSetting, + const sptr &callerToken, int requestCode = 0) override + { + return 0; + } + int ChangeFocusAbility(const sptr &lostFocusToken, const sptr &getFocusToken) override + { + return 0; + } }; } // namespace AppExecFwk diff --git a/services/bundlemgr/test/mock/include/mock_bundle_status.h b/services/bundlemgr/test/mock/include/mock_bundle_status.h index c68bdd27c7..fb7057b08b 100644 --- a/services/bundlemgr/test/mock/include/mock_bundle_status.h +++ b/services/bundlemgr/test/mock/include/mock_bundle_status.h @@ -32,6 +32,9 @@ public: virtual void OnBundleStateChanged(const uint8_t installType, const int32_t resultCode, const std::string &resultMsg, const std::string &bundleName) override; + virtual void OnBundleAdded(const std::string &bundleName, const int userId) override {}; + virtual void OnBundleUpdated(const std::string &bundleName, const int userId) override {}; + virtual void OnBundleRemoved(const std::string &bundleName, const int userId) override {}; virtual sptr AsObject() override; int32_t GetResultCode(); diff --git a/services/bundlemgr/test/unittest/bms_bundle_data_storage_test/bms_bundle_data_storage_database_test.cpp b/services/bundlemgr/test/unittest/bms_bundle_data_storage_test/bms_bundle_data_storage_database_test.cpp index c526bc7237..934053a40a 100644 --- a/services/bundlemgr/test/unittest/bms_bundle_data_storage_test/bms_bundle_data_storage_database_test.cpp +++ b/services/bundlemgr/test/unittest/bms_bundle_data_storage_test/bms_bundle_data_storage_database_test.cpp @@ -71,32 +71,35 @@ protected: "enabled": true, "readPermission": "readPermission", "writePermission": "writePermission", - "form": { - "formEntity": ["homeScreen", "searchbox"], - "minHeight": 0, - "defaultHeight": 100, - "minWidth": 0, - "defaultWidth": 200 - }, + "configChanges": [ + "locale" + ], + "formEnabled": true, + "formEntity": 1, + "minFormHeight": 0, + "defaultFormHeight": 100, + "minFormWidth": 0, + "defaultFormWidth": 200, "metaData": { "customizeData": [{ - ? "name" : "string", - ? "value" : "string", - ? "extra" : "$string:customizeData_description" + "name" : "string", + "value" : "string", + "extra" : "$string:customizeData_description" }], "parameters": [{ "name" : "string", - ? "type" : "Float", - ? "description" : "$string:parameters_description" + "type" : "Float", + "description" : "$string:parameters_description" }], "results": [{ - ? "name" : "string", - ? "type" : "Float", - ? "description" : "$string:results_description" + "name" : "string", + "type" : "Float", + "description" : "$string:results_description" }] }, "isLauncherAbility": true, "isNativeAbility": false, + "supportPipMode" : false, "kind": "page", "label": "Launcher", "launchMode": 0, @@ -111,7 +114,10 @@ protected: "targetAbility": "", "type": 1, "uri": "", - "visible": false + "visible": false, + "labelId": 1, + "descriptionId": 1, + "iconId": 1 } }, "baseApplicationInfo": { @@ -290,6 +296,25 @@ protected: } ] }, + "shortcutInfos": { + "com.example.myapplication1com.example.myapplication.h1id": { + "bundleName": "com.example.myapplication1", + "disableMessage": "", + "hostAbility": "", + "icon": "$string:mainability_description", + "id": "id", + "intents": [ + { + "targetBundle": "com.example.myapplication1", + "targetClass": "com.example.myapplication.MainAbility" + } + ], + "isEnables": false, + "isHomeShortcut": false, + "isStatic": false, + "label": "$string:mainability_description" + } + }, "uid": 10000, "userId_": 0 } @@ -347,14 +372,14 @@ void BmsBundleDataStorageDatabaseTest::CheckInvalidPropDeserialize( throwError = true; } - ASSERT_TRUE(throwError); + EXPECT_TRUE(throwError); if (!throwError) { GTEST_LOG_(ERROR) << "not catch any type_error"; } innerBundleInfoJson["baseBundleInfo"] = bundleInfoJson; InnerBundleInfo fromJsonInfo; - ASSERT_FALSE(fromJsonInfo.FromJson(innerBundleInfoJson)); + EXPECT_FALSE(fromJsonInfo.FromJson(innerBundleInfoJson)); } void BmsBundleDataStorageDatabaseTest::SetUpTestCase() @@ -383,7 +408,7 @@ HWTEST_F(BmsBundleDataStorageDatabaseTest, BundleInfoJsonSerializer_0100, Functi // serialize fromJsonInfo to json nlohmann::json toJsonObject = fromJsonInfo; - ASSERT_TRUE(toJsonObject.dump() == sourceInfoJson.dump()); + EXPECT_TRUE(toJsonObject.dump() == sourceInfoJson.dump()); } /** @@ -426,7 +451,7 @@ HWTEST_F(BmsBundleDataStorageDatabaseTest, AbilityInfoJsonSerializer_0100, Funct AbilityInfo fromJsonInfo = sourceInfoJson; // serialize fromJsonInfo to json nlohmann::json toJsonObject = fromJsonInfo; - ASSERT_TRUE(toJsonObject.dump() == sourceInfoJson.dump()); + EXPECT_TRUE(toJsonObject.dump() == sourceInfoJson.dump()); } /** @@ -479,7 +504,7 @@ HWTEST_F(BmsBundleDataStorageDatabaseTest, ApplicationInfoJsonSerializer_0100, F // serialize fromJsonInfo to json nlohmann::json toJsonObject = fromJsonInfo; - ASSERT_TRUE(toJsonObject.dump() == sourceInfoJson.dump()); + EXPECT_TRUE(toJsonObject.dump() == sourceInfoJson.dump()); } /** @@ -521,7 +546,7 @@ HWTEST_F(BmsBundleDataStorageDatabaseTest, ModuleInfoJsonSerializer_0100, Functi // serialize fromJsonInfo to json nlohmann::json toJsonObject = fromJsonInfo; - ASSERT_TRUE(toJsonObject.dump() == sourceInfoJson.dump()); + EXPECT_TRUE(toJsonObject.dump() == sourceInfoJson.dump()); } /** @@ -533,5 +558,5 @@ HWTEST_F(BmsBundleDataStorageDatabaseTest, ModuleInfoJsonSerializer_0100, Functi HWTEST_F(BmsBundleDataStorageDatabaseTest, SaveData_0100, Function | SmallTest | Level0) { InnerBundleInfo innerBundleInfo; - ASSERT_EQ(innerBundleInfo.FromJson(innerBundleInfoJson_), OHOS::ERR_OK); + EXPECT_EQ(innerBundleInfo.FromJson(innerBundleInfoJson_), OHOS::ERR_OK); } \ No newline at end of file diff --git a/services/bundlemgr/test/unittest/bms_bundle_data_storage_test/bms_bundle_data_storage_test.cpp b/services/bundlemgr/test/unittest/bms_bundle_data_storage_test/bms_bundle_data_storage_test.cpp index cd8daa5ba9..eaad3caca1 100755 --- a/services/bundlemgr/test/unittest/bms_bundle_data_storage_test/bms_bundle_data_storage_test.cpp +++ b/services/bundlemgr/test/unittest/bms_bundle_data_storage_test/bms_bundle_data_storage_test.cpp @@ -260,30 +260,30 @@ BmsBundleDataStorageTest::~BmsBundleDataStorageTest() void BmsBundleDataStorageTest::CheckBundleSaved(const InnerBundleInfo &innerBundleInfo) const { BundleDataStorage bundleDataStorage; - ASSERT_TRUE(bundleDataStorage.SaveStorageBundleInfo(Constants::CURRENT_DEVICE_ID, innerBundleInfo)); + EXPECT_TRUE(bundleDataStorage.SaveStorageBundleInfo(Constants::CURRENT_DEVICE_ID, innerBundleInfo)); std::map> bundleData; - ASSERT_TRUE(bundleDataStorage.LoadAllData(bundleData)); + EXPECT_TRUE(bundleDataStorage.LoadAllData(bundleData)); // search allDeviceInfos by bundle name std::string bundleName = innerBundleInfo.GetBundleName(); auto bundleDataIter = bundleData.find(bundleName); - ASSERT_TRUE(bundleDataIter != bundleData.end()); + EXPECT_TRUE(bundleDataIter != bundleData.end()); // search InnerBundleInfo by device id auto allDeviceInfos = bundleDataIter->second; auto devicesInfosIter = allDeviceInfos.find(deviceId_); - ASSERT_TRUE(devicesInfosIter != allDeviceInfos.end()); + EXPECT_TRUE(devicesInfosIter != allDeviceInfos.end()); InnerBundleInfo afterLoadInfo = devicesInfosIter->second; - ASSERT_TRUE(innerBundleInfo.ToString() == afterLoadInfo.ToString()); + EXPECT_TRUE(innerBundleInfo.ToString() == afterLoadInfo.ToString()); } void BmsBundleDataStorageTest::CheckBundleDeleted(const InnerBundleInfo &innerBundleInfo) const { BundleDataStorage bundleDataStorage; - ASSERT_TRUE(bundleDataStorage.DeleteStorageBundleInfo(Constants::CURRENT_DEVICE_ID, innerBundleInfo)); + EXPECT_TRUE(bundleDataStorage.DeleteStorageBundleInfo(Constants::CURRENT_DEVICE_ID, innerBundleInfo)); std::map> bundleDates; - ASSERT_TRUE(bundleDataStorage.LoadAllData(bundleDates)); + EXPECT_TRUE(bundleDataStorage.LoadAllData(bundleDates)); } void BmsBundleDataStorageTest::CheckInvalidPropDeserialize(const nlohmann::json infoJson, const InfoType infoType) const @@ -317,14 +317,14 @@ void BmsBundleDataStorageTest::CheckInvalidPropDeserialize(const nlohmann::json throwError = true; } - ASSERT_TRUE(throwError); + EXPECT_TRUE(throwError); if (!throwError) { GTEST_LOG_(ERROR) << "not catch any type_error"; } innerBundleInfoJson["baseBundleInfo"] = bundleInfoJson; InnerBundleInfo fromJsonInfo; - ASSERT_FALSE(fromJsonInfo.FromJson(innerBundleInfoJson)); + EXPECT_FALSE(fromJsonInfo.FromJson(innerBundleInfoJson)); } void BmsBundleDataStorageTest::SetUpTestCase() @@ -366,7 +366,7 @@ HWTEST_F(BmsBundleDataStorageTest, BundleInfoJsonSerializer_0100, Function | Sma // serialize fromJsonInfo to json nlohmann::json toJsonObject = fromJsonInfo; - ASSERT_TRUE(toJsonObject.dump() == sourceInfoJson.dump()); + EXPECT_TRUE(toJsonObject.dump() == sourceInfoJson.dump()); } /** @@ -409,7 +409,7 @@ HWTEST_F(BmsBundleDataStorageTest, AbilityInfoJsonSerializer_0100, Function | Sm AbilityInfo fromJsonInfo = sourceInfoJson; // serialize fromJsonInfo to json nlohmann::json toJsonObject = fromJsonInfo; - ASSERT_TRUE(toJsonObject.dump() == sourceInfoJson.dump()); + EXPECT_TRUE(toJsonObject.dump() == sourceInfoJson.dump()); } /** @@ -462,7 +462,7 @@ HWTEST_F(BmsBundleDataStorageTest, ApplicationInfoJsonSerializer_0100, Function // serialize fromJsonInfo to json nlohmann::json toJsonObject = fromJsonInfo; - ASSERT_TRUE(toJsonObject.dump() == sourceInfoJson.dump()); + EXPECT_TRUE(toJsonObject.dump() == sourceInfoJson.dump()); } /** @@ -504,7 +504,7 @@ HWTEST_F(BmsBundleDataStorageTest, ModuleInfoJsonSerializer_0100, Function | Sma // serialize fromJsonInfo to json nlohmann::json toJsonObject = fromJsonInfo; - ASSERT_TRUE(toJsonObject.dump() == sourceInfoJson.dump()); + EXPECT_TRUE(toJsonObject.dump() == sourceInfoJson.dump()); } /** @@ -571,8 +571,8 @@ HWTEST_F(BmsBundleDataStorageTest, SaveData_0400, Function | SmallTest | Level1) { nlohmann::json sourceInfoJson = innerBundleInfoJson_; InnerBundleInfo fromJsonInfo; - ASSERT_EQ(fromJsonInfo.FromJson(innerBundleInfoJson_), 0); - ASSERT_TRUE(fromJsonInfo.ToString() == sourceInfoJson.dump()); + EXPECT_EQ(fromJsonInfo.FromJson(innerBundleInfoJson_), 0); + EXPECT_TRUE(fromJsonInfo.ToString() == sourceInfoJson.dump()); } /** @@ -594,11 +594,11 @@ HWTEST_F(BmsBundleDataStorageTest, LoadAllData_0100, Function | SmallTest | Leve baseApp.name = NORMAL_BUNDLE_NAME + std::to_string(i); baseApp.bundleName = baseApp.name; innerBundleInfo.SetBaseApplicationInfo(baseApp); - ASSERT_TRUE(bundleDataStorage.SaveStorageBundleInfo(Constants::CURRENT_DEVICE_ID, innerBundleInfo)); + EXPECT_TRUE(bundleDataStorage.SaveStorageBundleInfo(Constants::CURRENT_DEVICE_ID, innerBundleInfo)); } std::map> bundleDates; - ASSERT_TRUE(bundleDataStorage.LoadAllData(bundleDates)); + EXPECT_TRUE(bundleDataStorage.LoadAllData(bundleDates)); for (int i = 0; i < count; i++) { std::string bundleName = NORMAL_BUNDLE_NAME + std::to_string(i); @@ -608,14 +608,14 @@ HWTEST_F(BmsBundleDataStorageTest, LoadAllData_0100, Function | SmallTest | Leve // search allDeviceInfos by bundle name auto bundleDatesIter = bundleDates.find(bundleName); - ASSERT_TRUE(bundleDatesIter != bundleDates.end()); + EXPECT_TRUE(bundleDatesIter != bundleDates.end()); // search InnerBundleInfo by device id auto allDeviceInfos = bundleDatesIter->second; auto devicesInfosIter = allDeviceInfos.find(deviceId_); - ASSERT_TRUE(devicesInfosIter != allDeviceInfos.end()); + EXPECT_TRUE(devicesInfosIter != allDeviceInfos.end()); InnerBundleInfo afterLoadInfo = devicesInfosIter->second; - ASSERT_TRUE(innerBundleInfo.ToString() == afterLoadInfo.ToString()); + EXPECT_TRUE(innerBundleInfo.ToString() == afterLoadInfo.ToString()); } } @@ -631,7 +631,7 @@ HWTEST_F(BmsBundleDataStorageTest, DeleteBundleData_0100, Function | SmallTest | innerBundleInfo.FromJson(innerBundleInfoJson_); BundleDataStorage bundleDataStorage; - ASSERT_TRUE(bundleDataStorage.SaveStorageBundleInfo(Constants::CURRENT_DEVICE_ID, innerBundleInfo)); + EXPECT_TRUE(bundleDataStorage.SaveStorageBundleInfo(Constants::CURRENT_DEVICE_ID, innerBundleInfo)); CheckBundleDeleted(innerBundleInfo); } @@ -647,7 +647,7 @@ HWTEST_F(BmsBundleDataStorageTest, DeleteBundleData_0200, Function | SmallTest | InnerBundleInfo innerBundleInfo; innerBundleInfo.FromJson(innerBundleInfoJson_); BundleDataStorage bundleDataStorage; - ASSERT_FALSE(bundleDataStorage.DeleteStorageBundleInfo(Constants::CURRENT_DEVICE_ID, innerBundleInfo)); + EXPECT_FALSE(bundleDataStorage.DeleteStorageBundleInfo(Constants::CURRENT_DEVICE_ID, innerBundleInfo)); } /** @@ -658,14 +658,14 @@ HWTEST_F(BmsBundleDataStorageTest, DeleteBundleData_0200, Function | SmallTest | */ HWTEST_F(BmsBundleDataStorageTest, DeleteBundleData_0300, Function | SmallTest | Level1) { - ASSERT_EQ(remove(Constants::BUNDLE_DATA_BASE_FILE.c_str()), 0); + EXPECT_EQ(remove(Constants::BUNDLE_DATA_BASE_FILE.c_str()), 0); InnerBundleInfo innerBundleInfo; innerBundleInfo.FromJson(innerBundleInfoJson_); BundleDataStorage bundleDataStorage; - ASSERT_FALSE(bundleDataStorage.DeleteStorageBundleInfo(Constants::CURRENT_DEVICE_ID, innerBundleInfo)); + EXPECT_FALSE(bundleDataStorage.DeleteStorageBundleInfo(Constants::CURRENT_DEVICE_ID, innerBundleInfo)); std::map> bundleDates; - ASSERT_FALSE(bundleDataStorage.SaveStorageBundleInfo(Constants::CURRENT_DEVICE_ID, innerBundleInfo)); - ASSERT_FALSE(bundleDataStorage.LoadAllData(bundleDates)); + EXPECT_FALSE(bundleDataStorage.SaveStorageBundleInfo(Constants::CURRENT_DEVICE_ID, innerBundleInfo)); + EXPECT_FALSE(bundleDataStorage.LoadAllData(bundleDates)); } \ No newline at end of file diff --git a/services/bundlemgr/test/unittest/bms_bundle_installer_test/BUILD.gn b/services/bundlemgr/test/unittest/bms_bundle_installer_test/BUILD.gn old mode 100644 new mode 100755 index d53bae1274..096d0b5862 --- a/services/bundlemgr/test/unittest/bms_bundle_installer_test/BUILD.gn +++ b/services/bundlemgr/test/unittest/bms_bundle_installer_test/BUILD.gn @@ -20,7 +20,7 @@ module_output_path = "appexecfwk_standard/bundlemgrservice" ohos_unittest("BmsBundleInstallerTest") { module_out_path = module_output_path - + include_dirs = [ "//third_party/jsoncpp/include" ] sources = [ "${services_path}/bundlemgr/src/bundle_data_mgr.cpp", "${services_path}/bundlemgr/src/bundle_data_storage_database.cpp", @@ -32,6 +32,9 @@ ohos_unittest("BmsBundleInstallerTest") { "${services_path}/bundlemgr/src/installd/installd_host_impl.cpp", "${services_path}/bundlemgr/src/installd/installd_operator.cpp", "${services_path}/bundlemgr/src/installd/installd_service.cpp", + "${services_path}/bundlemgr/src/kvstore_death_recipient_callback.cpp", + "${services_path}/bundlemgr/src/module_usage_data_storage.cpp", + "${services_path}/bundlemgr/src/permission_changed_death_recipient.cpp", ] sources += [ @@ -61,6 +64,7 @@ ohos_unittest("BmsBundleInstallerTest") { "//foundation/distributeddatamgr/distributeddatamgr/interfaces/innerkits/distributeddata:distributeddata_inner", "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", "//utils/native/base:utils", ] diff --git a/services/bundlemgr/test/unittest/bms_bundle_installer_test/bms_bundle_installer_test.cpp b/services/bundlemgr/test/unittest/bms_bundle_installer_test/bms_bundle_installer_test.cpp index 503b49c197..58cc1e42ef 100755 --- a/services/bundlemgr/test/unittest/bms_bundle_installer_test/bms_bundle_installer_test.cpp +++ b/services/bundlemgr/test/unittest/bms_bundle_installer_test/bms_bundle_installer_test.cpp @@ -140,13 +140,13 @@ void BmsBundleInstallerTest::SetUpTestCase() { if (access(ROOT_DIR.c_str(), F_OK) != 0) { bool result = OHOS::ForceCreateDirectory(ROOT_DIR); - ASSERT_TRUE(result) << "fail to create root dir"; + EXPECT_TRUE(result) << "fail to create root dir"; } if (chown(ROOT_DIR.c_str(), ROOT_UID, ROOT_UID) != 0) { - ASSERT_TRUE(false) << "fail to change root dir own ship"; + EXPECT_TRUE(false) << "fail to change root dir own ship"; } if (chmod(ROOT_DIR.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) { - ASSERT_TRUE(false) << "fail to change root dir mode"; + EXPECT_TRUE(false) << "fail to change root dir mode"; } } @@ -173,19 +173,19 @@ void BmsBundleInstallerTest::TearDown() void BmsBundleInstallerTest::CheckFileExist() const { int bundleCodeExist = access(BUNDLE_CODE_DIR.c_str(), F_OK); - ASSERT_EQ(bundleCodeExist, 0) << "the bundle code dir does not exists: " << BUNDLE_CODE_DIR; + EXPECT_EQ(bundleCodeExist, 0) << "the bundle code dir does not exists: " << BUNDLE_CODE_DIR; int bundleDataExist = access(BUNDLE_DATA_DIR.c_str(), F_OK); - ASSERT_EQ(bundleDataExist, 0) << "the bundle data dir does not exists: " << BUNDLE_DATA_DIR; + EXPECT_EQ(bundleDataExist, 0) << "the bundle data dir does not exists: " << BUNDLE_DATA_DIR; } void BmsBundleInstallerTest::CheckFileNonExist() const { int bundleCodeExist = access(BUNDLE_CODE_DIR.c_str(), F_OK); - ASSERT_NE(bundleCodeExist, 0) << "the bundle code dir exists: " << BUNDLE_CODE_DIR; + EXPECT_NE(bundleCodeExist, 0) << "the bundle code dir exists: " << BUNDLE_CODE_DIR; int bundleDataExist = access(BUNDLE_DATA_DIR.c_str(), F_OK); - ASSERT_NE(bundleDataExist, 0) << "the bundle data dir exists: " << BUNDLE_DATA_DIR; + EXPECT_NE(bundleDataExist, 0) << "the bundle data dir exists: " << BUNDLE_DATA_DIR; } const std::shared_ptr BmsBundleInstallerTest::GetBundleDataMgr() const @@ -210,7 +210,7 @@ void BmsBundleInstallerTest::StopBundleService() return; } auto dataMgr = bundleMgrService_->GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_START); dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_SUCCESS); bundleMgrService_->OnStop(); @@ -227,7 +227,7 @@ void BmsBundleInstallerTest::CreateInstallerManager() return; } manager_ = std::make_shared(installRunner); - ASSERT_NE(nullptr, manager_); + EXPECT_NE(nullptr, manager_); } void BmsBundleInstallerTest::ClearBundleInfoInDb() @@ -248,7 +248,7 @@ void BmsBundleInstallerTest::ClearBundleInfoInDb() applicationInfo.bundleName = BUNDLE_NAME; innerBundleInfo.SetBaseApplicationInfo(applicationInfo); bool result = dataStorage->DeleteStorageBundleInfo(Constants::CURRENT_DEVICE_ID, innerBundleInfo); - ASSERT_TRUE(result) << "the bundle info in db clear fail: " << BUNDLE_NAME; + EXPECT_TRUE(result) << "the bundle info in db clear fail: " << BUNDLE_NAME; } /** @@ -261,7 +261,7 @@ HWTEST_F(BmsBundleInstallerTest, SystemInstall_0100, Function | SmallTest | Leve { std::string bundleFile = RESOURCE_ROOT_PATH + RIGHT_BUNDLE; bool result = InstallSystemBundle(bundleFile); - ASSERT_TRUE(result) << "the bundle file install failed: " << bundleFile; + EXPECT_TRUE(result) << "the bundle file install failed: " << bundleFile; CheckFileExist(); ClearBundleInfoInDb(); } @@ -276,7 +276,7 @@ HWTEST_F(BmsBundleInstallerTest, SystemInstall_0200, Function | SmallTest | Leve { std::string nonExistFile = RESOURCE_ROOT_PATH + INVALID_BUNDLE; bool result = InstallSystemBundle(nonExistFile); - ASSERT_FALSE(result) << "the bundle file install success: " << nonExistFile; + EXPECT_FALSE(result) << "the bundle file install success: " << nonExistFile; CheckFileNonExist(); } @@ -289,7 +289,7 @@ HWTEST_F(BmsBundleInstallerTest, SystemInstall_0200, Function | SmallTest | Leve HWTEST_F(BmsBundleInstallerTest, SystemInstall_0300, Function | SmallTest | Level0) { bool result = InstallSystemBundle(""); - ASSERT_FALSE(result) << "the empty path install success"; + EXPECT_FALSE(result) << "the empty path install success"; CheckFileNonExist(); } @@ -303,7 +303,7 @@ HWTEST_F(BmsBundleInstallerTest, SystemInstall_0400, Function | SmallTest | Leve { std::string wrongBundleName = RESOURCE_ROOT_PATH + WRONG_BUNDLE_NAME; bool result = InstallSystemBundle(wrongBundleName); - ASSERT_FALSE(result) << "the wrong bundle file install success"; + EXPECT_FALSE(result) << "the wrong bundle file install success"; CheckFileNonExist(); } @@ -317,7 +317,7 @@ HWTEST_F(BmsBundleInstallerTest, SystemInstall_0500, Function | SmallTest | Leve { std::string errorFormat = RESOURCE_ROOT_PATH + FORMAT_ERROR_BUNDLE; bool result = InstallSystemBundle(errorFormat); - ASSERT_FALSE(result) << "the wrong format file install success"; + EXPECT_FALSE(result) << "the wrong format file install success"; CheckFileNonExist(); } @@ -331,7 +331,7 @@ HWTEST_F(BmsBundleInstallerTest, SystemInstall_0600, Function | SmallTest | Leve { std::string bundleFile = INVALID_PATH + RIGHT_BUNDLE; bool result = InstallSystemBundle(bundleFile); - ASSERT_FALSE(result) << "the invalid path install success"; + EXPECT_FALSE(result) << "the invalid path install success"; CheckFileNonExist(); } @@ -359,14 +359,14 @@ HWTEST_F(BmsBundleInstallerTest, SystemUpdateData_0100, Function | SmallTest | L { ApplicationInfo info; auto dataMgr = GetBundleDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool result = dataMgr->GetApplicationInfo(BUNDLE_NAME, ApplicationFlag::GET_BASIC_APPLICATION_INFO, USERID, info); - ASSERT_FALSE(result); + EXPECT_FALSE(result); std::string bundleFile = RESOURCE_ROOT_PATH + RIGHT_BUNDLE; bool installResult = InstallSystemBundle(bundleFile); - ASSERT_TRUE(installResult); + EXPECT_TRUE(installResult); result = dataMgr->GetApplicationInfo(BUNDLE_NAME, ApplicationFlag::GET_BASIC_APPLICATION_INFO, USERID, info); - ASSERT_TRUE(result); + EXPECT_TRUE(result); EXPECT_EQ(info.name, BUNDLE_NAME); ClearBundleInfoInDb(); } @@ -381,12 +381,12 @@ HWTEST_F(BmsBundleInstallerTest, SystemUpdateData_0200, Function | SmallTest | L { ApplicationInfo info; auto dataMgr = GetBundleDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool result = dataMgr->GetApplicationInfo(BUNDLE_NAME, ApplicationFlag::GET_BASIC_APPLICATION_INFO, USERID, info); - ASSERT_FALSE(result); + EXPECT_FALSE(result); std::string wrongBundleName = RESOURCE_ROOT_PATH + WRONG_BUNDLE_NAME; bool installResult = InstallSystemBundle(wrongBundleName); - ASSERT_FALSE(installResult); + EXPECT_FALSE(installResult); result = dataMgr->GetApplicationInfo(BUNDLE_NAME, ApplicationFlag::GET_BASIC_APPLICATION_INFO, USERID, info); EXPECT_FALSE(result); } @@ -400,15 +400,15 @@ HWTEST_F(BmsBundleInstallerTest, SystemUpdateData_0200, Function | SmallTest | L HWTEST_F(BmsBundleInstallerTest, SystemUpdateData_0300, Function | SmallTest | Level0) { auto dataMgr = GetBundleDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); // prepare already install information. std::string bundleFile = RESOURCE_ROOT_PATH + RIGHT_BUNDLE; bool firstInstall = InstallSystemBundle(bundleFile); - ASSERT_TRUE(firstInstall); + EXPECT_TRUE(firstInstall); ApplicationInfo info; auto result = dataMgr->GetApplicationInfo(BUNDLE_NAME, ApplicationFlag::GET_BASIC_APPLICATION_INFO, USERID, info); - ASSERT_TRUE(result); - ASSERT_EQ(info.name, BUNDLE_NAME); + EXPECT_TRUE(result); + EXPECT_EQ(info.name, BUNDLE_NAME); bool secondInstall = InstallSystemBundle(bundleFile); EXPECT_FALSE(secondInstall); ClearBundleInfoInDb(); @@ -424,7 +424,7 @@ HWTEST_F(BmsBundleInstallerTest, SystemUpdateData_0400, Function | SmallTest | L { // prepare already install information. auto dataMgr = GetBundleDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); // begin to reinstall package std::string bundleFile = RESOURCE_ROOT_PATH + RIGHT_BUNDLE; @@ -444,7 +444,7 @@ HWTEST_F(BmsBundleInstallerTest, CreateInstallTask_0100, Function | SmallTest | { CreateInstallerManager(); sptr receiver = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver, nullptr); + EXPECT_NE(receiver, nullptr); InstallParam installParam; std::string bundleFile = RESOURCE_ROOT_PATH + RIGHT_BUNDLE; GetBundleInstallerManager()->CreateInstallTask(bundleFile, installParam, receiver); @@ -463,7 +463,7 @@ HWTEST_F(BmsBundleInstallerTest, CreateInstallTask_0200, Function | SmallTest | { CreateInstallerManager(); sptr receiver = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver, nullptr); + EXPECT_NE(receiver, nullptr); InstallParam installParam; std::string bundleFile = RESOURCE_ROOT_PATH + INVALID_BUNDLE; GetBundleInstallerManager()->CreateInstallTask(bundleFile, installParam, receiver); @@ -481,7 +481,7 @@ HWTEST_F(BmsBundleInstallerTest, CreateUninstallTask_0100, Function | SmallTest { CreateInstallerManager(); sptr receiver = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver, nullptr); + EXPECT_NE(receiver, nullptr); InstallParam installParam; std::string bundleFile = RESOURCE_ROOT_PATH + RIGHT_BUNDLE; GetBundleInstallerManager()->CreateInstallTask(bundleFile, installParam, receiver); @@ -504,7 +504,7 @@ HWTEST_F(BmsBundleInstallerTest, CreateUninstallTask_0200, Function | SmallTest { CreateInstallerManager(); sptr receiver = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver, nullptr); + EXPECT_NE(receiver, nullptr); InstallParam installParam; std::string bundleFile = RESOURCE_ROOT_PATH + INVALID_BUNDLE; GetBundleInstallerManager()->CreateUninstallTask(bundleFile, installParam, receiver); @@ -522,7 +522,7 @@ HWTEST_F(BmsBundleInstallerTest, ThirdPartyInstall_0100, Function | SmallTest | { std::string bundleFile = RESOURCE_ROOT_PATH + RIGHT_BUNDLE; ErrCode result = InstallThirdPartyBundle(bundleFile); - ASSERT_EQ(result, ERR_OK); + EXPECT_EQ(result, ERR_OK); CheckFileExist(); ClearBundleInfoInDb(); } @@ -537,7 +537,7 @@ HWTEST_F(BmsBundleInstallerTest, ThirdPartyInstall_0200, Function | SmallTest | { std::string nonExistFile = RESOURCE_ROOT_PATH + INVALID_BUNDLE; ErrCode result = InstallThirdPartyBundle(nonExistFile); - ASSERT_EQ(result, ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID); + EXPECT_EQ(result, ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID); CheckFileNonExist(); } @@ -550,7 +550,7 @@ HWTEST_F(BmsBundleInstallerTest, ThirdPartyInstall_0200, Function | SmallTest | HWTEST_F(BmsBundleInstallerTest, ThirdPartyInstall_0300, Function | SmallTest | Level0) { ErrCode result = InstallThirdPartyBundle(""); - ASSERT_EQ(result, ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID); + EXPECT_EQ(result, ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID); CheckFileNonExist(); } @@ -564,7 +564,7 @@ HWTEST_F(BmsBundleInstallerTest, ThirdPartyInstall_0400, Function | SmallTest | { std::string wrongBundleName = RESOURCE_ROOT_PATH + WRONG_BUNDLE_NAME; ErrCode result = InstallThirdPartyBundle(wrongBundleName); - ASSERT_EQ(result, ERR_APPEXECFWK_INSTALL_INVALID_HAP_NAME); + EXPECT_EQ(result, ERR_APPEXECFWK_INSTALL_INVALID_HAP_NAME); CheckFileNonExist(); } @@ -578,7 +578,7 @@ HWTEST_F(BmsBundleInstallerTest, ThirdPartyInstall_0500, Function | SmallTest | { std::string errorFormat = RESOURCE_ROOT_PATH + FORMAT_ERROR_BUNDLE; ErrCode result = InstallThirdPartyBundle(errorFormat); - ASSERT_EQ(result, ERR_APPEXECFWK_PARSE_NO_PROFILE); + EXPECT_EQ(result, ERR_APPEXECFWK_PARSE_NO_PROFILE); CheckFileNonExist(); } @@ -592,7 +592,7 @@ HWTEST_F(BmsBundleInstallerTest, ThirdPartyInstall_0600, Function | SmallTest | { std::string bundleFile = INVALID_PATH + RIGHT_BUNDLE; ErrCode result = InstallThirdPartyBundle(bundleFile); - ASSERT_EQ(result, ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID); + EXPECT_EQ(result, ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID); CheckFileNonExist(); } @@ -607,7 +607,7 @@ HWTEST_F(BmsBundleInstallerTest, ThirdPartyInstall_0700, Function | SmallTest | StopInstalldService(); std::string bundleFile = RESOURCE_ROOT_PATH + RIGHT_BUNDLE; ErrCode result = InstallThirdPartyBundle(bundleFile); - ASSERT_EQ(result, ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR); + EXPECT_EQ(result, ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR); } /** @@ -620,14 +620,14 @@ HWTEST_F(BmsBundleInstallerTest, ThirdPartyUpdateData_0100, Function | SmallTest { ApplicationInfo info; auto dataMgr = GetBundleDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool result = dataMgr->GetApplicationInfo(BUNDLE_NAME, ApplicationFlag::GET_BASIC_APPLICATION_INFO, USERID, info); - ASSERT_FALSE(result); + EXPECT_FALSE(result); std::string bundleFile = RESOURCE_ROOT_PATH + RIGHT_BUNDLE; ErrCode installResult = InstallThirdPartyBundle(bundleFile); - ASSERT_EQ(installResult, ERR_OK); + EXPECT_EQ(installResult, ERR_OK); result = dataMgr->GetApplicationInfo(BUNDLE_NAME, ApplicationFlag::GET_BASIC_APPLICATION_INFO, USERID, info); - ASSERT_TRUE(result); + EXPECT_TRUE(result); EXPECT_EQ(info.name, BUNDLE_NAME); ClearBundleInfoInDb(); } @@ -642,12 +642,12 @@ HWTEST_F(BmsBundleInstallerTest, ThirdPartyUpdateData_0200, Function | SmallTest { ApplicationInfo info; auto dataMgr = GetBundleDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool result = dataMgr->GetApplicationInfo(BUNDLE_NAME, ApplicationFlag::GET_BASIC_APPLICATION_INFO, USERID, info); - ASSERT_FALSE(result); + EXPECT_FALSE(result); std::string wrongBundleName = RESOURCE_ROOT_PATH + WRONG_BUNDLE_NAME; ErrCode installResult = InstallThirdPartyBundle(wrongBundleName); - ASSERT_EQ(installResult, ERR_APPEXECFWK_INSTALL_INVALID_HAP_NAME); + EXPECT_EQ(installResult, ERR_APPEXECFWK_INSTALL_INVALID_HAP_NAME); result = dataMgr->GetApplicationInfo(BUNDLE_NAME, ApplicationFlag::GET_BASIC_APPLICATION_INFO, USERID, info); EXPECT_FALSE(result); } @@ -661,15 +661,15 @@ HWTEST_F(BmsBundleInstallerTest, ThirdPartyUpdateData_0200, Function | SmallTest HWTEST_F(BmsBundleInstallerTest, ThirdPartyUpdateData_0300, Function | SmallTest | Level0) { auto dataMgr = GetBundleDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); // prepare already install information. std::string bundleFile = RESOURCE_ROOT_PATH + RIGHT_BUNDLE; ErrCode firstInstall = InstallThirdPartyBundle(bundleFile); - ASSERT_EQ(firstInstall, ERR_OK); + EXPECT_EQ(firstInstall, ERR_OK); ApplicationInfo info; auto result = dataMgr->GetApplicationInfo(BUNDLE_NAME, ApplicationFlag::GET_BASIC_APPLICATION_INFO, USERID, info); - ASSERT_TRUE(result); - ASSERT_EQ(info.name, BUNDLE_NAME); + EXPECT_TRUE(result); + EXPECT_EQ(info.name, BUNDLE_NAME); ErrCode secondInstall = InstallThirdPartyBundle(bundleFile); EXPECT_EQ(secondInstall, ERR_APPEXECFWK_INSTALL_ALREADY_EXIST); ClearBundleInfoInDb(); @@ -684,15 +684,15 @@ HWTEST_F(BmsBundleInstallerTest, ThirdPartyUpdateData_0300, Function | SmallTest HWTEST_F(BmsBundleInstallerTest, ThirdPartyUpdateData_0400, Function | SmallTest | Level0) { auto dataMgr = GetBundleDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); // prepare already install information. std::string bundleFile = RESOURCE_ROOT_PATH + RIGHT_BUNDLE; ErrCode firstInstall = InstallThirdPartyBundle(bundleFile); - ASSERT_EQ(firstInstall, ERR_OK); + EXPECT_EQ(firstInstall, ERR_OK); ApplicationInfo info; auto result = dataMgr->GetApplicationInfo(BUNDLE_NAME, ApplicationFlag::GET_BASIC_APPLICATION_INFO, USERID, info); - ASSERT_TRUE(result); - ASSERT_EQ(info.name, BUNDLE_NAME); + EXPECT_TRUE(result); + EXPECT_EQ(info.name, BUNDLE_NAME); ErrCode secondInstall = UpdateThirdPartyBundle(bundleFile); EXPECT_EQ(secondInstall, ERR_OK); ClearBundleInfoInDb(); @@ -708,7 +708,7 @@ HWTEST_F(BmsBundleInstallerTest, ThirdPartyUpdateData_0500, Function | SmallTest { // prepare already install information. auto dataMgr = GetBundleDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); // begin to reinstall package std::string bundleFile = RESOURCE_ROOT_PATH + RIGHT_BUNDLE; diff --git a/services/bundlemgr/test/unittest/bms_bundle_kit_service_test/BUILD.gn b/services/bundlemgr/test/unittest/bms_bundle_kit_service_test/BUILD.gn old mode 100644 new mode 100755 index 455cd359a6..f5277266f4 --- a/services/bundlemgr/test/unittest/bms_bundle_kit_service_test/BUILD.gn +++ b/services/bundlemgr/test/unittest/bms_bundle_kit_service_test/BUILD.gn @@ -20,7 +20,7 @@ module_output_path = "appexecfwk_standard/bundlemgrservice" ohos_unittest("BmsBundleKitServiceTest") { module_out_path = module_output_path - + include_dirs = [ "//third_party/jsoncpp/include" ] sources = [ "${innerkits_path}/appexecfwk_base/src/ability_info.cpp", "${innerkits_path}/appexecfwk_base/src/application_info.cpp", @@ -37,6 +37,9 @@ ohos_unittest("BmsBundleKitServiceTest") { "${services_path}/bundlemgr/src/installd/installd_host_impl.cpp", "${services_path}/bundlemgr/src/installd/installd_operator.cpp", "${services_path}/bundlemgr/src/installd/installd_service.cpp", + "${services_path}/bundlemgr/src/kvstore_death_recipient_callback.cpp", + "${services_path}/bundlemgr/src/module_usage_data_storage.cpp", + "${services_path}/bundlemgr/src/permission_changed_death_recipient.cpp", ] sources += [ @@ -63,12 +66,14 @@ ohos_unittest("BmsBundleKitServiceTest") { "${libs_path}/libeventhandler:libeventhandler_target", "//base/security/appverify/interfaces/innerkits/appverify:libhapverify", "//base/security/permission/interfaces/innerkits/permission_standard/permissionsdk:libpermissionsdk_standard", + "//foundation/aafwk/standard/interfaces/innerkits/ability_manager:ability_manager", "//foundation/aafwk/standard/interfaces/innerkits/base:base", "//foundation/aafwk/standard/interfaces/innerkits/want:want", "//foundation/distributeddatamgr/distributeddatamgr/interfaces/innerkits/distributeddata:distributeddata_inner", "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", ] deps += bundle_install_deps diff --git a/services/bundlemgr/test/unittest/bms_bundle_kit_service_test/bms_bundle_kit_service_test.cpp b/services/bundlemgr/test/unittest/bms_bundle_kit_service_test/bms_bundle_kit_service_test.cpp index f22f17d43a..a6a48a3a7b 100755 --- a/services/bundlemgr/test/unittest/bms_bundle_kit_service_test/bms_bundle_kit_service_test.cpp +++ b/services/bundlemgr/test/unittest/bms_bundle_kit_service_test/bms_bundle_kit_service_test.cpp @@ -15,7 +15,8 @@ #include #include - +#include "ability_manager_client.h" +#include #include "directory_ex.h" #include "bundle_data_mgr.h" #include "install_param.h" @@ -27,6 +28,8 @@ #include "inner_bundle_info.h" #include "mock_clean_cache.h" #include "mock_bundle_status.h" +#include "ohos/aafwk/content/want.h" +#include "module_usage_data_storage.h" using namespace testing::ext; using namespace OHOS; @@ -37,6 +40,7 @@ namespace { const std::string BUNDLE_NAME_TEST = "com.example.bundlekit.test"; const std::string MODULE_NAME_TEST = "com.example.bundlekit.test.entry"; +const std::string ABILITY_NAME_TEST1 = ".Reading1"; const std::string ABILITY_NAME_TEST = ".Reading"; const int TEST_UID = 1001; const std::string BUNDLE_LABEL = "Hello, OHOS"; @@ -48,6 +52,7 @@ const int32_t BUNDLE_MAX_SDK_VERSION = 0; const int32_t BUNDLE_MIN_SDK_VERSION = 0; const std::string BUNDLE_JOINT_USERID = "3"; const uint32_t BUNDLE_VERSION_CODE = 1001; +const std::string BUNDLE_NAME_TEST1 = "com.example.bundlekit.test1"; const std::string BUNDLE_NAME_DEMO = "com.example.bundlekit.demo"; const std::string MODULE_NAME_DEMO = "com.example.bundlekit.demo.entry"; const std::string ABILITY_NAME_DEMO = ".Writing"; @@ -56,7 +61,7 @@ const std::string PACKAGE_NAME = "com.example.bundlekit.test.entry"; const std::string PROCESS_TEST = "test.process"; const std::string DEVICE_ID = "PHONE-001"; const int APPLICATION_INFO_FLAGS = 1; -const int DEFAULT_USER_ID = 0; +const int DEFAULT_USER_ID_TEST = 0; const std::string LABEL = "hello"; const std::string DESCRIPTION = "mainEntry"; const std::string THEME = "mytheme"; @@ -71,6 +76,7 @@ const AbilityType ABILITY_TYPE = AbilityType::PAGE; const DisplayOrientation ORIENTATION = DisplayOrientation::PORTRAIT; const LaunchMode LAUNCH_MODE = LaunchMode::SINGLETON; const uint32_t FORM_ENTITY = 1; +const std::vector CONFIG_CHANGES = {"locale"}; const int DEFAULT_FORM_HEIGHT = 100; const int DEFAULT_FORM_WIDTH = 200; const std::string META_DATA_DESCRIPTION = "description"; @@ -92,6 +98,7 @@ const uint32_t BUNDLE_NAMES_SIZE_ZERO = 0; const uint32_t BUNDLE_NAMES_SIZE_ONE = 1; const std::string EMPTY_STRING = ""; const int INVALID_UID = -1; +const std::string ABILITY_URI = "dataability:///com.example.hiworld.himusic.UserADataAbility/person/10"; const std::string URI = "dataability://com.example.hiworld.himusic.UserADataAbility"; const std::string ERROR_URI = "dataability://"; const std::string HAP_FILE_PATH = "/data/test/resource/bms/bundle_kit/test.hap"; @@ -125,7 +132,6 @@ const std::string SHORTCUT_LABEL = "shortcutLabel"; const std::string SHORTCUT_DISABLE_MESSAGE = "shortcutDisableMessage"; const std::string SHORTCUT_INTENTS_TARGET_BUNDLE = "targetBundle"; const std::string SHORTCUT_INTENTS_TARGET_CLASS = "targetClass"; -const int FORMINFO_DESCRIPTIONID = 123; } // namespace @@ -137,6 +143,8 @@ public: void SetUp(); void TearDown(); std::shared_ptr GetBundleDataMgr() const; + void MockInnerBundleInfo(const std::string &bundleName, const std::string &moduleName, + const std::string &abilityName, InnerBundleInfo &innerBundleInfo) const; void MockInstallBundle( const std::string &bundleName, const std::string &moduleName, const std::string &abilityName) const; void MockUninstallBundle(const std::string &bundleName) const; @@ -233,7 +241,7 @@ void BmsBundleKitServiceTest::MockInstallBundle( ReqPermission reqPermission2 = {.name = "permission1"}; moduleInfo.reqPermissions = {reqPermission1, reqPermission2}; moduleInfo.modulePackage = PACKAGE_NAME; - moduleInfo.moduleName = PACKAGE_NAME; + moduleInfo.moduleName = moduleName; moduleInfo.description = BUNDLE_DESCRIPTION; moduleInfo.colorMode = COLOR_MODE; @@ -262,26 +270,25 @@ void BmsBundleKitServiceTest::MockInstallBundle( } std::vector formInfos; formInfos.emplace_back(form); - if(bundleName == BUNDLE_NAME_TEST) { + if (bundleName == BUNDLE_NAME_TEST) { ShortcutInfo shortcut = MockShortcutInfo(bundleName, SHORTCUT_TEST_ID); std::string shortcutKey = bundleName + moduleName + SHORTCUT_TEST_ID; innerBundleInfo.InsertShortcutInfos(shortcutKey, shortcut); - } - else { + } else { ShortcutInfo shortcut = MockShortcutInfo(bundleName, SHORTCUT_DEMO_ID); std::string shortcutKey = bundleName + moduleName + SHORTCUT_DEMO_ID; innerBundleInfo.InsertShortcutInfos(shortcutKey, shortcut); } innerBundleInfo.InsertFormInfos(keyName, formInfos); auto dataMgr = GetBundleDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool startRet = dataMgr->UpdateBundleInstallState(bundleName, InstallState::INSTALL_START); bool finishRet = dataMgr->UpdateBundleInstallState(bundleName, InstallState::INSTALL_SUCCESS); bool addRet = dataMgr->AddInnerBundleInfo(bundleName, innerBundleInfo); - ASSERT_TRUE(startRet); - ASSERT_TRUE(finishRet); - ASSERT_TRUE(addRet); + EXPECT_TRUE(startRet); + EXPECT_TRUE(finishRet); + EXPECT_TRUE(addRet); } FormInfo BmsBundleKitServiceTest::MockFormInfo( @@ -293,7 +300,7 @@ FormInfo BmsBundleKitServiceTest::MockFormInfo( formInfo.abilityName = abilityName; formInfo.moduleName = moduleName; formInfo.package = PACKAGE_NAME; - formInfo.descriptionId = FORMINFO_DESCRIPTIONID; + formInfo.descriptionId = 123; formInfo.formConfigAbility = FORM_PATH; formInfo.description = FORM_DESCRIPTION; formInfo.defaultFlag = false; @@ -316,7 +323,8 @@ FormInfo BmsBundleKitServiceTest::MockFormInfo( return formInfo; } -ShortcutInfo BmsBundleKitServiceTest::MockShortcutInfo(const std::string &bundleName, const std::string &shortcutId) const +ShortcutInfo BmsBundleKitServiceTest::MockShortcutInfo( + const std::string &bundleName, const std::string &shortcutId) const { ShortcutInfo shortcutInfos; shortcutInfos.id = shortcutId; @@ -338,12 +346,12 @@ ShortcutInfo BmsBundleKitServiceTest::MockShortcutInfo(const std::string &bundle void BmsBundleKitServiceTest::MockUninstallBundle(const std::string &bundleName) const { auto dataMgr = GetBundleDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool startRet = dataMgr->UpdateBundleInstallState(bundleName, InstallState::UNINSTALL_START); bool finishRet = dataMgr->UpdateBundleInstallState(bundleName, InstallState::UNINSTALL_SUCCESS); - ASSERT_TRUE(startRet); - ASSERT_TRUE(finishRet); + EXPECT_TRUE(startRet); + EXPECT_TRUE(finishRet); } AbilityInfo BmsBundleKitServiceTest::MockAbilityInfo( @@ -364,6 +372,7 @@ AbilityInfo BmsBundleKitServiceTest::MockAbilityInfo( abilityInfo.type = ABILITY_TYPE; abilityInfo.orientation = ORIENTATION; abilityInfo.launchMode = LAUNCH_MODE; + abilityInfo.configChanges = {"locale"}; abilityInfo.formEntity = 1; abilityInfo.defaultFormHeight = DEFAULT_FORM_HEIGHT; abilityInfo.defaultFormWidth = DEFAULT_FORM_WIDTH; @@ -372,6 +381,7 @@ AbilityInfo BmsBundleKitServiceTest::MockAbilityInfo( abilityInfo.libPath = LIB_PATH; abilityInfo.uri = URI; abilityInfo.enabled = true; + abilityInfo.supportPipMode = false; abilityInfo.targetAbility = TARGET_ABILITY; AppExecFwk::Parameters parameters{"description", "name", "type"}; AppExecFwk::Results results{"description", "name", "type"}; @@ -381,6 +391,25 @@ AbilityInfo BmsBundleKitServiceTest::MockAbilityInfo( return abilityInfo; } +void BmsBundleKitServiceTest::MockInnerBundleInfo(const std::string &bundleName, const std::string &moduleName, + const std::string &abilityName, InnerBundleInfo &innerBundleInfo) const +{ + ApplicationInfo appInfo; + appInfo.bundleName = bundleName; + BundleInfo bundleInfo; + bundleInfo.name = bundleName; + innerBundleInfo.SetBaseBundleInfo(bundleInfo); + InnerModuleInfo moduleInfo; + moduleInfo.modulePackage = moduleName; + moduleInfo.moduleName = moduleName; + moduleInfo.description = BUNDLE_DESCRIPTION; + innerBundleInfo.InsertInnerModuleInfo(moduleName, moduleInfo); + AbilityInfo abilityInfo = MockAbilityInfo(bundleName, moduleName, abilityName); + std::string keyName = bundleName + moduleName + abilityName; + innerBundleInfo.InsertAbilitiesInfo(keyName, abilityInfo); + innerBundleInfo.SetBaseApplicationInfo(appInfo); +} + void BmsBundleKitServiceTest::CheckBundleInfo(const std::string &bundleName, const std::string &moduleName, const uint32_t abilitySize, const BundleInfo &bundleInfo) const { @@ -451,25 +480,27 @@ void BmsBundleKitServiceTest::CheckAbilityInfo( EXPECT_EQ(ORIENTATION, abilityInfo.orientation); EXPECT_EQ(LAUNCH_MODE, abilityInfo.launchMode); EXPECT_EQ(URI, abilityInfo.uri); + EXPECT_EQ(false, abilityInfo.supportPipMode); EXPECT_EQ(TARGET_ABILITY, abilityInfo.targetAbility); + EXPECT_EQ(CONFIG_CHANGES, abilityInfo.configChanges); EXPECT_EQ(FORM_ENTITY, abilityInfo.formEntity); EXPECT_EQ(DEFAULT_FORM_HEIGHT, abilityInfo.defaultFormHeight); EXPECT_EQ(DEFAULT_FORM_WIDTH, abilityInfo.defaultFormWidth); for (auto &info : abilityInfo.metaData.customizeData) { - EXPECT_EQ(info.name, META_DATA_NAME); - EXPECT_EQ(info.value, META_DATA_VALUE); - EXPECT_EQ(info.extra, META_DATA_EXTRA); - } + EXPECT_EQ(info.name, META_DATA_NAME); + EXPECT_EQ(info.value, META_DATA_VALUE); + EXPECT_EQ(info.extra, META_DATA_EXTRA); + } for (auto &info : abilityInfo.metaData.parameters) { - EXPECT_EQ(info.description, META_DATA_DESCRIPTION); - EXPECT_EQ(info.name, META_DATA_NAME); - EXPECT_EQ(info.type, META_DATA_TYPE); - } + EXPECT_EQ(info.description, META_DATA_DESCRIPTION); + EXPECT_EQ(info.name, META_DATA_NAME); + EXPECT_EQ(info.type, META_DATA_TYPE); + } for (auto &info : abilityInfo.metaData.results) { - EXPECT_EQ(info.description, META_DATA_DESCRIPTION); - EXPECT_EQ(info.name, META_DATA_NAME); - EXPECT_EQ(info.type, META_DATA_TYPE); - } + EXPECT_EQ(info.description, META_DATA_DESCRIPTION); + EXPECT_EQ(info.name, META_DATA_NAME); + EXPECT_EQ(info.type, META_DATA_TYPE); + } } void BmsBundleKitServiceTest::CheckCompatibleAbilityInfo( @@ -489,7 +520,6 @@ void BmsBundleKitServiceTest::CheckCompatibleAbilityInfo( EXPECT_EQ(FORM_ENTITY, abilityInfo.formEntity); EXPECT_EQ(DEFAULT_FORM_HEIGHT, abilityInfo.defaultFormHeight); EXPECT_EQ(DEFAULT_FORM_WIDTH, abilityInfo.defaultFormWidth); - } void BmsBundleKitServiceTest::CheckCompatibleApplicationInfo( const std::string &bundleName, const uint32_t permissionSize, const CompatibleApplicationInfo &appInfo) const @@ -581,12 +611,12 @@ void BmsBundleKitServiceTest::CreateFileDir() const if (access(TEST_FILE_DIR.c_str(), F_OK) != 0) { bool result = OHOS::ForceCreateDirectory(TEST_FILE_DIR); - ASSERT_TRUE(result) << "fail to create file dir"; + EXPECT_TRUE(result) << "fail to create file dir"; } if (access(TEST_CACHE_DIR.c_str(), F_OK) != 0) { bool result = OHOS::ForceCreateDirectory(TEST_CACHE_DIR); - ASSERT_TRUE(result) << "fail to create cache dir"; + EXPECT_TRUE(result) << "fail to create cache dir"; } } @@ -601,25 +631,25 @@ void BmsBundleKitServiceTest::CleanFileDir() const void BmsBundleKitServiceTest::CheckFileExist() const { int dataExist = access(TEST_FILE_DIR.c_str(), F_OK); - ASSERT_EQ(dataExist, 0); + EXPECT_EQ(dataExist, 0); } void BmsBundleKitServiceTest::CheckFileNonExist() const { int dataExist = access(TEST_FILE_DIR.c_str(), F_OK); - ASSERT_NE(dataExist, 0); + EXPECT_NE(dataExist, 0); } void BmsBundleKitServiceTest::CheckCacheExist() const { int dataExist = access(TEST_CACHE_DIR.c_str(), F_OK); - ASSERT_EQ(dataExist, 0); + EXPECT_EQ(dataExist, 0); } void BmsBundleKitServiceTest::CheckCacheNonExist() const { int dataExist = access(TEST_CACHE_DIR.c_str(), F_OK); - ASSERT_NE(dataExist, 0); + EXPECT_NE(dataExist, 0); } void BmsBundleKitServiceTest::CheckFormInfoTest(const std::vector &formInfos) const @@ -634,7 +664,7 @@ void BmsBundleKitServiceTest::CheckFormInfoTest(const std::vector &for EXPECT_EQ(formInfo.defaultFlag, false); EXPECT_EQ(formInfo.type, FormType::JS); EXPECT_EQ(formInfo.colorMode, FormsColorMode::LIGHT_MODE); - EXPECT_EQ(formInfo.descriptionId, FORMINFO_DESCRIPTIONID); + EXPECT_EQ(formInfo.descriptionId, 123); EXPECT_EQ(formInfo.deepLink, FORM_PATH); EXPECT_EQ(formInfo.package, PACKAGE_NAME); EXPECT_EQ(formInfo.formVisibleNotify, true); @@ -664,7 +694,7 @@ void BmsBundleKitServiceTest::CheckFormInfoDemo(const std::vector &for EXPECT_EQ(formInfo.defaultFlag, false); EXPECT_EQ(formInfo.type, FormType::JS); EXPECT_EQ(formInfo.colorMode, FormsColorMode::LIGHT_MODE); - EXPECT_EQ(formInfo.descriptionId, FORMINFO_DESCRIPTIONID); + EXPECT_EQ(formInfo.descriptionId, 123); EXPECT_EQ(formInfo.deepLink, FORM_PATH); EXPECT_EQ(formInfo.package, PACKAGE_NAME); EXPECT_EQ(formInfo.formVisibleNotify, true); @@ -790,7 +820,7 @@ HWTEST_F(BmsBundleKitServiceTest, GetBundleInfo_0400, Function | SmallTest | Lev { BundleInfo bundleInfo; bool ret = GetBundleDataMgr()->GetBundleInfo(BUNDLE_NAME_TEST, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); - ASSERT_FALSE(ret); + EXPECT_FALSE(ret); EXPECT_EQ(EMPTY_STRING, bundleInfo.name); EXPECT_EQ(EMPTY_STRING, bundleInfo.label); } @@ -831,7 +861,7 @@ HWTEST_F(BmsBundleKitServiceTest, GetBundleInfos_0100, Function | SmallTest | Le std::vector bundleInfos; bool ret = GetBundleDataMgr()->GetBundleInfos(BundleFlag::GET_BUNDLE_DEFAULT, bundleInfos); - ASSERT_TRUE(ret); + EXPECT_TRUE(ret); CheckInstalledBundleInfos(ABILITY_SIZE_ZERO, bundleInfos); MockUninstallBundle(BUNDLE_NAME_TEST); @@ -851,7 +881,7 @@ HWTEST_F(BmsBundleKitServiceTest, GetBundleInfos_0200, Function | SmallTest | Le std::vector bundleInfos; bool ret = GetBundleDataMgr()->GetBundleInfos(BundleFlag::GET_BUNDLE_WITH_ABILITIES, bundleInfos); - ASSERT_TRUE(ret); + EXPECT_TRUE(ret); CheckInstalledBundleInfos(ABILITY_SIZE_ONE, bundleInfos); MockUninstallBundle(BUNDLE_NAME_TEST); @@ -868,7 +898,7 @@ HWTEST_F(BmsBundleKitServiceTest, GetBundleInfos_0300, Function | SmallTest | Le { std::vector bundleInfos; bool ret = GetBundleDataMgr()->GetBundleInfos(BundleFlag::GET_BUNDLE_WITH_ABILITIES, bundleInfos); - ASSERT_FALSE(ret); + EXPECT_FALSE(ret); } /** @@ -884,13 +914,13 @@ HWTEST_F(BmsBundleKitServiceTest, GetApplicationInfo_0100, Function | SmallTest ApplicationInfo testResult; bool testRet = GetBundleDataMgr()->GetApplicationInfo( - BUNDLE_NAME_TEST, ApplicationFlag::GET_BASIC_APPLICATION_INFO, DEFAULT_USER_ID, testResult); + BUNDLE_NAME_TEST, ApplicationFlag::GET_BASIC_APPLICATION_INFO, DEFAULT_USER_ID_TEST, testResult); EXPECT_TRUE(testRet); CheckApplicationInfo(BUNDLE_NAME_TEST, PERMISSION_SIZE_ZERO, testResult); ApplicationInfo demoResult; bool demoRet = GetBundleDataMgr()->GetApplicationInfo( - BUNDLE_NAME_DEMO, ApplicationFlag::GET_APPLICATION_INFO_WITH_PERMS, DEFAULT_USER_ID, demoResult); + BUNDLE_NAME_DEMO, ApplicationFlag::GET_APPLICATION_INFO_WITH_PERMS, DEFAULT_USER_ID_TEST, demoResult); EXPECT_TRUE(demoRet); CheckApplicationInfo(BUNDLE_NAME_DEMO, PERMISSION_SIZE_TWO, demoResult); @@ -910,7 +940,7 @@ HWTEST_F(BmsBundleKitServiceTest, GetApplicationInfo_0200, Function | SmallTest ApplicationInfo result; bool ret = GetBundleDataMgr()->GetApplicationInfo( - BUNDLE_NAME_DEMO, ApplicationFlag::GET_BASIC_APPLICATION_INFO, DEFAULT_USER_ID, result); + BUNDLE_NAME_DEMO, ApplicationFlag::GET_BASIC_APPLICATION_INFO, DEFAULT_USER_ID_TEST, result); EXPECT_FALSE(ret); EXPECT_EQ(EMPTY_STRING, result.name); @@ -929,7 +959,7 @@ HWTEST_F(BmsBundleKitServiceTest, GetApplicationInfo_0300, Function | SmallTest ApplicationInfo result; bool ret = GetBundleDataMgr()->GetApplicationInfo( - EMPTY_STRING, ApplicationFlag::GET_BASIC_APPLICATION_INFO, DEFAULT_USER_ID, result); + EMPTY_STRING, ApplicationFlag::GET_BASIC_APPLICATION_INFO, DEFAULT_USER_ID_TEST, result); EXPECT_FALSE(ret); EXPECT_EQ(EMPTY_STRING, result.name); @@ -946,8 +976,8 @@ HWTEST_F(BmsBundleKitServiceTest, GetApplicationInfo_0400, Function | SmallTest { ApplicationInfo result; bool ret = GetBundleDataMgr()->GetApplicationInfo( - BUNDLE_NAME_TEST, ApplicationFlag::GET_BASIC_APPLICATION_INFO, DEFAULT_USER_ID, result); - ASSERT_FALSE(ret); + BUNDLE_NAME_TEST, ApplicationFlag::GET_BASIC_APPLICATION_INFO, DEFAULT_USER_ID_TEST, result); + EXPECT_FALSE(ret); EXPECT_EQ(EMPTY_STRING, result.name); EXPECT_EQ(EMPTY_STRING, result.label); } @@ -964,7 +994,7 @@ HWTEST_F(BmsBundleKitServiceTest, GetApplicationInfo_0500, Function | SmallTest ApplicationInfo result; bool ret = GetBundleDataMgr()->GetApplicationInfo( - BUNDLE_NAME_TEST, ApplicationFlag::GET_BASIC_APPLICATION_INFO, DEFAULT_USER_ID, result); + BUNDLE_NAME_TEST, ApplicationFlag::GET_BASIC_APPLICATION_INFO, DEFAULT_USER_ID_TEST, result); EXPECT_TRUE(ret); Parcel parcel; parcel.WriteParcelable(&result); @@ -988,9 +1018,9 @@ HWTEST_F(BmsBundleKitServiceTest, GetApplicationInfos_0100, Function | SmallTest MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); std::vector appInfos; - bool ret = - GetBundleDataMgr()->GetApplicationInfos(ApplicationFlag::GET_BASIC_APPLICATION_INFO, DEFAULT_USER_ID, appInfos); - ASSERT_TRUE(ret); + bool ret = GetBundleDataMgr()->GetApplicationInfos( + ApplicationFlag::GET_BASIC_APPLICATION_INFO, DEFAULT_USER_ID_TEST, appInfos); + EXPECT_TRUE(ret); CheckInstalledApplicationInfos(PERMISSION_SIZE_ZERO, appInfos); MockUninstallBundle(BUNDLE_NAME_TEST); @@ -1010,8 +1040,8 @@ HWTEST_F(BmsBundleKitServiceTest, GetApplicationInfos_0200, Function | SmallTest std::vector appInfos; bool ret = GetBundleDataMgr()->GetApplicationInfos( - ApplicationFlag::GET_APPLICATION_INFO_WITH_PERMS, DEFAULT_USER_ID, appInfos); - ASSERT_TRUE(ret); + ApplicationFlag::GET_APPLICATION_INFO_WITH_PERMS, DEFAULT_USER_ID_TEST, appInfos); + EXPECT_TRUE(ret); CheckInstalledApplicationInfos(PERMISSION_SIZE_TWO, appInfos); MockUninstallBundle(BUNDLE_NAME_TEST); @@ -1028,8 +1058,8 @@ HWTEST_F(BmsBundleKitServiceTest, GetApplicationInfos_0300, Function | SmallTest { std::vector appInfos; bool ret = GetBundleDataMgr()->GetApplicationInfos( - ApplicationFlag::GET_APPLICATION_INFO_WITH_PERMS, DEFAULT_USER_ID, appInfos); - ASSERT_FALSE(ret); + ApplicationFlag::GET_APPLICATION_INFO_WITH_PERMS, DEFAULT_USER_ID_TEST, appInfos); + EXPECT_FALSE(ret); } /** @@ -1501,7 +1531,7 @@ HWTEST_F(BmsBundleKitServiceTest, QueryAbilityInfoByUri_0100, Function | SmallTe MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); AbilityInfo result; - bool testRet = GetBundleDataMgr()->QueryAbilityInfoByUri(URI, result); + bool testRet = GetBundleDataMgr()->QueryAbilityInfoByUri(ABILITY_URI, result); EXPECT_EQ(true, testRet); EXPECT_EQ(ABILITY_NAME_TEST, result.name); EXPECT_NE(ABILITY_NAME_DEMO, result.name); @@ -1521,7 +1551,7 @@ HWTEST_F(BmsBundleKitServiceTest, QueryAbilityInfoByUri_0200, Function | SmallTe MockInstallBundle(BUNDLE_NAME_DEMO, MODULE_NAME_TEST, ABILITY_NAME_TEST); AbilityInfo result; - bool testRet = GetBundleDataMgr()->QueryAbilityInfoByUri(URI, result); + bool testRet = GetBundleDataMgr()->QueryAbilityInfoByUri(ABILITY_URI, result); EXPECT_EQ(true, testRet); EXPECT_EQ(ABILITY_NAME_TEST, result.name); EXPECT_NE(ABILITY_NAME_DEMO, result.name); @@ -1540,7 +1570,7 @@ HWTEST_F(BmsBundleKitServiceTest, QueryAbilityInfoByUri_0200, Function | SmallTe HWTEST_F(BmsBundleKitServiceTest, QueryAbilityInfoByUri_0300, Function | SmallTest | Level1) { AbilityInfo result; - bool testRet = GetBundleDataMgr()->QueryAbilityInfoByUri(URI, result); + bool testRet = GetBundleDataMgr()->QueryAbilityInfoByUri(ABILITY_URI, result); EXPECT_EQ(false, testRet); } @@ -2051,7 +2081,7 @@ HWTEST_F(BmsBundleKitServiceTest, RegisterBundleStatus_0100, Function | SmallTes EXPECT_TRUE(result); bool resultNotify = GetBundleDataMgr()->NotifyBundleStatus( - HAP_FILE_PATH, HAP_FILE_PATH, ABILITY_NAME_DEMO, ERR_OK, NotifyType::INSTALL); + HAP_FILE_PATH, HAP_FILE_PATH, ABILITY_NAME_DEMO, ERR_OK, NotifyType::INSTALL, Constants::INVALID_UID); EXPECT_TRUE(resultNotify); int32_t callbackResult = bundleStatusCallback->GetResultCode(); @@ -2071,8 +2101,8 @@ HWTEST_F(BmsBundleKitServiceTest, RegisterBundleStatus_0200, Function | SmallTes bool result = GetBundleDataMgr()->RegisterBundleStatusCallback(bundleStatusCallback); EXPECT_TRUE(result); - bool resultNotify = - GetBundleDataMgr()->NotifyBundleStatus("", HAP_FILE_PATH, ABILITY_NAME_DEMO, ERR_OK, NotifyType::INSTALL); + bool resultNotify = GetBundleDataMgr()->NotifyBundleStatus( + "", HAP_FILE_PATH, ABILITY_NAME_DEMO, ERR_OK, NotifyType::INSTALL, Constants::INVALID_UID); EXPECT_TRUE(resultNotify); int32_t callbackResult = bundleStatusCallback->GetResultCode(); @@ -2093,7 +2123,7 @@ HWTEST_F(BmsBundleKitServiceTest, RegisterBundleStatus_0300, Function | SmallTes EXPECT_TRUE(result); bool resultNotify = GetBundleDataMgr()->NotifyBundleStatus( - ERROR_HAP_FILE_PATH, HAP_FILE_PATH, ABILITY_NAME_DEMO, ERR_OK, NotifyType::INSTALL); + ERROR_HAP_FILE_PATH, HAP_FILE_PATH, ABILITY_NAME_DEMO, ERR_OK, NotifyType::INSTALL, Constants::INVALID_UID); EXPECT_TRUE(resultNotify); int32_t callbackResult = bundleStatusCallback->GetResultCode(); @@ -2122,14 +2152,14 @@ HWTEST_F(BmsBundleKitServiceTest, ClearBundleStatus_0100, Function | SmallTest | EXPECT_TRUE(result); bool resultNotify = GetBundleDataMgr()->NotifyBundleStatus( - HAP_FILE_PATH, HAP_FILE_PATH, ABILITY_NAME_DEMO, ERR_OK, NotifyType::INSTALL); + HAP_FILE_PATH, HAP_FILE_PATH, ABILITY_NAME_DEMO, ERR_OK, NotifyType::INSTALL, Constants::INVALID_UID); EXPECT_TRUE(resultNotify); int32_t callbackResult = bundleStatusCallback->GetResultCode(); EXPECT_EQ(callbackResult, ERR_OK); bool resultNotify1 = GetBundleDataMgr()->NotifyBundleStatus( - HAP_FILE_PATH1, HAP_FILE_PATH, ABILITY_NAME_DEMO, ERR_OK, NotifyType::INSTALL); + HAP_FILE_PATH1, HAP_FILE_PATH, ABILITY_NAME_DEMO, ERR_OK, NotifyType::INSTALL, Constants::INVALID_UID); EXPECT_TRUE(resultNotify1); int32_t callbackResult1 = bundleStatusCallback1->GetResultCode(); @@ -2158,14 +2188,14 @@ HWTEST_F(BmsBundleKitServiceTest, UnregisterBundleStatus_0100, Function | SmallT EXPECT_TRUE(result2); bool resultNotify = GetBundleDataMgr()->NotifyBundleStatus( - HAP_FILE_PATH, HAP_FILE_PATH, ABILITY_NAME_DEMO, ERR_OK, NotifyType::INSTALL); + HAP_FILE_PATH, HAP_FILE_PATH, ABILITY_NAME_DEMO, ERR_OK, NotifyType::INSTALL, Constants::INVALID_UID); EXPECT_TRUE(resultNotify); int32_t callbackResult = bundleStatusCallback->GetResultCode(); EXPECT_EQ(callbackResult, ERR_TIMED_OUT); bool resultNotify1 = GetBundleDataMgr()->NotifyBundleStatus( - HAP_FILE_PATH1, HAP_FILE_PATH, ABILITY_NAME_DEMO, ERR_OK, NotifyType::INSTALL); + HAP_FILE_PATH1, HAP_FILE_PATH, ABILITY_NAME_DEMO, ERR_OK, NotifyType::INSTALL, Constants::INVALID_UID); EXPECT_TRUE(resultNotify1); int32_t callbackResult1 = bundleStatusCallback1->GetResultCode(); @@ -2789,6 +2819,186 @@ HWTEST_F(BmsBundleKitServiceTest, GetShortcutInfos_0500, Function | SmallTest | EXPECT_TRUE(shortcutInfos.empty()); } +/** + * @tc.number: GetUsageRecords_0100 + * @tc.name: test can get usage records by notify activity life status + * @tc.desc: 1.can get usage records + */ +HWTEST_F(BmsBundleKitServiceTest, GetUsageRecords_0100, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + auto ret = GetBundleDataMgr()->NotifyActivityLifeStatus(BUNDLE_NAME_TEST, ABILITY_NAME_TEST, 1629094922); + EXPECT_TRUE(ret); + std::vector records; + auto result = GetBundleDataMgr()->GetUsageRecords(100, records); + EXPECT_TRUE(result); + auto iter = std::find_if(records.begin(), records.end(), [](const auto &item) { + return (item.bundleName == BUNDLE_NAME_TEST && item.name == MODULE_NAME_TEST && + item.abilityName == ABILITY_NAME_TEST); + }); + EXPECT_NE(iter, records.end()); + uint32_t count = 1; + EXPECT_EQ(iter->launchedCount, count); + InnerBundleInfo innerBundleInfo; + MockInnerBundleInfo(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST, innerBundleInfo); + ModuleUsageRecordStorage moduleUsageRecordStorage; + moduleUsageRecordStorage.DeleteUsageRecord(innerBundleInfo, 0); + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: GetUsageRecords_0200 + * @tc.name: test can get usage records by notify activity life status + * @tc.desc: 1.no other ability have been activitied + * 2.can get two bundle usage records + */ +HWTEST_F(BmsBundleKitServiceTest, GetUsageRecords_0200, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + MockInstallBundle(BUNDLE_NAME_DEMO, MODULE_NAME_DEMO, ABILITY_NAME_DEMO); + int64_t time = + std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + auto ret = GetBundleDataMgr()->NotifyActivityLifeStatus(BUNDLE_NAME_TEST, ABILITY_NAME_TEST, time); + auto ret1 = GetBundleDataMgr()->NotifyActivityLifeStatus(BUNDLE_NAME_DEMO, ABILITY_NAME_DEMO, time); + EXPECT_TRUE(ret); + EXPECT_TRUE(ret1); + std::vector records; + auto result = GetBundleDataMgr()->GetUsageRecords(100, records); + EXPECT_TRUE(result); + size_t size = 2; + EXPECT_EQ(records.size(), size); + auto iter = std::find_if(records.begin(), records.end(), [](const auto &item) { + return (item.bundleName == BUNDLE_NAME_TEST && item.name == MODULE_NAME_TEST && + item.abilityName == ABILITY_NAME_TEST); + }); + EXPECT_NE(iter, records.end()); + uint32_t count = 1; + EXPECT_EQ(iter->launchedCount, count); + InnerBundleInfo innerBundleInfo1; + InnerBundleInfo innerBundleInfo2; + MockInnerBundleInfo(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST, innerBundleInfo1); + MockInnerBundleInfo(BUNDLE_NAME_DEMO, ABILITY_NAME_DEMO, ABILITY_NAME_DEMO, innerBundleInfo2); + ModuleUsageRecordStorage moduleUsageRecordStorage; + moduleUsageRecordStorage.DeleteUsageRecord(innerBundleInfo1, 0); + moduleUsageRecordStorage.DeleteUsageRecord(innerBundleInfo2, 0); + MockUninstallBundle(BUNDLE_NAME_TEST); + MockUninstallBundle(BUNDLE_NAME_DEMO); +} + +/** + * @tc.number: GetUsageRecords_0300 + * @tc.name: test can get usage records by notify activity life status + * @tc.desc: 1.can get usage records called two notify activity + */ +HWTEST_F(BmsBundleKitServiceTest, GetUsageRecords_0300, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + int64_t time = + std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + auto ret = GetBundleDataMgr()->NotifyActivityLifeStatus(BUNDLE_NAME_TEST, ABILITY_NAME_TEST, time); + auto ret1 = GetBundleDataMgr()->NotifyActivityLifeStatus(BUNDLE_NAME_TEST, ABILITY_NAME_TEST, time); + EXPECT_TRUE(ret); + EXPECT_TRUE(ret1); + std::vector records; + auto result = GetBundleDataMgr()->GetUsageRecords(100, records); + EXPECT_TRUE(result); + auto iter = std::find_if(records.begin(), records.end(), [](const auto &item) { + return (item.bundleName == BUNDLE_NAME_TEST && item.name == MODULE_NAME_TEST && + item.abilityName == ABILITY_NAME_TEST); + }); + EXPECT_NE(iter, records.end()); + uint32_t count = 2; + EXPECT_EQ(iter->launchedCount, count); + InnerBundleInfo innerBundleInfo1; + MockInnerBundleInfo(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST, innerBundleInfo1); + ModuleUsageRecordStorage moduleUsageRecordStorage; + moduleUsageRecordStorage.DeleteUsageRecord(innerBundleInfo1, 0); + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: NotifyActivityLifeStatus_0100 + * @tc.name: test can called notify activity life status + * @tc.desc: 1. have called notify activity life status + * 2. called notify activity life + */ +HWTEST_F(BmsBundleKitServiceTest, NotifyActivityLifeStatus_0100, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_DEMO, ABILITY_NAME_TEST); + int64_t time = + std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + auto ret = GetBundleDataMgr()->NotifyActivityLifeStatus(BUNDLE_NAME_TEST, ABILITY_NAME_TEST, time); + EXPECT_TRUE(ret); + InnerBundleInfo innerBundleInfo; + MockInnerBundleInfo(BUNDLE_NAME_TEST, MODULE_NAME_DEMO, ABILITY_NAME_TEST, innerBundleInfo); + ModuleUsageRecordStorage moduleUsageRecordStorage; + moduleUsageRecordStorage.DeleteUsageRecord(innerBundleInfo, 0); + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: NotifyActivityLifeStatus_0200 + * @tc.name: test can called notify activity life status + * @tc.desc: 1. have two bundle to called notify activity life status + * 2. notify activity life + */ +HWTEST_F(BmsBundleKitServiceTest, NotifyActivityLifeStatus_0200, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + MockInstallBundle(BUNDLE_NAME_DEMO, MODULE_NAME_DEMO, ABILITY_NAME_DEMO); + int64_t time = + std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + auto ret = GetBundleDataMgr()->NotifyActivityLifeStatus(BUNDLE_NAME_DEMO, ABILITY_NAME_DEMO, time); + auto ret1 = GetBundleDataMgr()->NotifyActivityLifeStatus(BUNDLE_NAME_TEST, ABILITY_NAME_TEST, time); + EXPECT_TRUE(ret); + EXPECT_TRUE(ret1); + InnerBundleInfo innerBundleInfo1; + InnerBundleInfo innerBundleInfo2; + MockInnerBundleInfo(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST, innerBundleInfo1); + MockInnerBundleInfo(BUNDLE_NAME_DEMO, MODULE_NAME_DEMO, ABILITY_NAME_DEMO, innerBundleInfo2); + ModuleUsageRecordStorage moduleUsageRecordStorage; + moduleUsageRecordStorage.DeleteUsageRecord(innerBundleInfo1, 0); + moduleUsageRecordStorage.DeleteUsageRecord(innerBundleInfo2, 0); + MockUninstallBundle(BUNDLE_NAME_DEMO); + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: NotifyActivityLifeStatus_0300 + * @tc.name: test can't called notify activity life status by error bundleName + * @tc.desc: 1. can't to called notify activity life status + */ +HWTEST_F(BmsBundleKitServiceTest, NotifyActivityLifeStatus_0300, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + int64_t time = + std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + auto ret = GetBundleDataMgr()->NotifyActivityLifeStatus(BUNDLE_NAME_DEMO, ABILITY_NAME_DEMO, time); + EXPECT_FALSE(ret); + InnerBundleInfo innerBundleInfo; + MockInnerBundleInfo(BUNDLE_NAME_DEMO, MODULE_NAME_TEST, ABILITY_NAME_DEMO, innerBundleInfo); + ModuleUsageRecordStorage moduleUsageRecordStorage; + moduleUsageRecordStorage.DeleteUsageRecord(innerBundleInfo, 0); + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: NotifyActivityLifeStatus_0400 + * @tc.name: test can't called notify activity life status by null bundleName + * @tc.desc: 1. can't to called notify activity life status + */ +HWTEST_F(BmsBundleKitServiceTest, NotifyActivityLifeStatus_0400, Function | SmallTest | Level1) +{ + int64_t time = + std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + auto ret = GetBundleDataMgr()->NotifyActivityLifeStatus(BUNDLE_NAME_DEMO, ABILITY_NAME_DEMO, time); + InnerBundleInfo innerBundleInfo; + MockInnerBundleInfo(BUNDLE_NAME_DEMO, MODULE_NAME_TEST, ABILITY_NAME_DEMO, innerBundleInfo); + ModuleUsageRecordStorage moduleUsageRecordStorage; + moduleUsageRecordStorage.DeleteUsageRecord(innerBundleInfo, 0); + EXPECT_FALSE(ret); +} + /** * @tc.number: Ability_0100 * @tc.name: test can get the compatibleAbilityInfo by one bundle @@ -2848,7 +3058,7 @@ HWTEST_F(BmsBundleKitServiceTest, Application_0100, Function | SmallTest | Level ApplicationInfo testResult; bool testRet = GetBundleDataMgr()->GetApplicationInfo( - BUNDLE_NAME_TEST, ApplicationFlag::GET_BASIC_APPLICATION_INFO, DEFAULT_USER_ID, testResult); + BUNDLE_NAME_TEST, ApplicationFlag::GET_BASIC_APPLICATION_INFO, DEFAULT_USER_ID_TEST, testResult); EXPECT_TRUE(testRet); CompatibleApplicationInfo appInfo; testResult.ConvertToCompatibleApplicationInfo(appInfo); @@ -2869,7 +3079,7 @@ HWTEST_F(BmsBundleKitServiceTest, Application_0200, Function | SmallTest | Level ApplicationInfo testResult1; bool testRet1 = GetBundleDataMgr()->GetApplicationInfo( - BUNDLE_NAME_TEST, ApplicationFlag::GET_BASIC_APPLICATION_INFO, DEFAULT_USER_ID, testResult1); + BUNDLE_NAME_TEST, ApplicationFlag::GET_BASIC_APPLICATION_INFO, DEFAULT_USER_ID_TEST, testResult1); EXPECT_TRUE(testRet1); CompatibleApplicationInfo appInfo1; testResult1.ConvertToCompatibleApplicationInfo(appInfo1); @@ -2877,11 +3087,11 @@ HWTEST_F(BmsBundleKitServiceTest, Application_0200, Function | SmallTest | Level ApplicationInfo testResult2; bool testRet2 = GetBundleDataMgr()->GetApplicationInfo( - BUNDLE_NAME_DEMO, ApplicationFlag::GET_BASIC_APPLICATION_INFO, DEFAULT_USER_ID, testResult2); + BUNDLE_NAME_DEMO, ApplicationFlag::GET_BASIC_APPLICATION_INFO, DEFAULT_USER_ID_TEST, testResult2); EXPECT_TRUE(testRet2); CompatibleApplicationInfo appInfo2; testResult2.ConvertToCompatibleApplicationInfo(appInfo2); CheckCompatibleApplicationInfo(BUNDLE_NAME_DEMO, PERMISSION_SIZE_ZERO, appInfo2); MockUninstallBundle(BUNDLE_NAME_TEST); MockUninstallBundle(BUNDLE_NAME_DEMO); -} +} \ No newline at end of file diff --git a/services/bundlemgr/test/unittest/bms_bundle_parser_test/bms_bundle_parser_test.cpp b/services/bundlemgr/test/unittest/bms_bundle_parser_test/bms_bundle_parser_test.cpp index c2c1923a49..8f1aa7514c 100755 --- a/services/bundlemgr/test/unittest/bms_bundle_parser_test/bms_bundle_parser_test.cpp +++ b/services/bundlemgr/test/unittest/bms_bundle_parser_test/bms_bundle_parser_test.cpp @@ -104,6 +104,7 @@ const nlohmann::json CONFIG_JSON = R"( "type": "JS", "colorMode": "auto", "isDefault": false, + "jsComponentName": "card4x4", "updateEnabled": true, "scheduledUpdateTime": "21:05", "updateDuration": 1, @@ -117,6 +118,7 @@ const nlohmann::json CONFIG_JSON = R"( "portraitLayouts": [ "$layout:ability_form" ], + "formVisibleNotify": true, "deepLink": "ability://com.example.myapplication.fa/.MainAbility", "formConfigAbility": "ability://com.example.myapplication.fa/.MainAbility", "metaData": { @@ -893,7 +895,7 @@ HWTEST_F(BmsBundleParserTest, TestParse_2400, Function | SmallTest | Level1) { nlohmann::json errorFormsJson = CONFIG_JSON; errorFormsJson[BUNDLE_PROFILE_KEY_MODULE][BUNDLE_MODULE_PROFILE_KEY_ABILITIES]= R"( - [{ + [{ "skills": [ { "entities": [ @@ -938,7 +940,7 @@ HWTEST_F(BmsBundleParserTest, TestParse_2400, Function | SmallTest | Level1) "type": "page", "launchType": "standard" }] - + )"_json; CheckProfileForms(errorFormsJson); } @@ -1006,7 +1008,6 @@ HWTEST_F(BmsBundleParserTest, TestParse_2700, Function | SmallTest | Level1) nlohmann::json errorShortcutJson = CONFIG_JSON; errorShortcutJson[BUNDLE_PROFILE_KEY_MODULE][BUNDLE_MODULE_PROFILE_KEY_SHORTCUTS] = R"( [{ - "shortcutId": "~!@#$%^&*(){}[]:;'?<>,.|`/./+_-", "label": "~!@#$%^&*(){}[]:;'?<>,.|`/./+_-", "icon": "~!@#$%^&*(){}[]:;'?<>,.|`/./+_-", "intents": [ @@ -1033,7 +1034,7 @@ HWTEST_F(BmsBundleParserTest, TestExtractByName_0100, Function | SmallTest | Lev BundleExtractor bundleExtractor(pathStream_.str()); bool result = bundleExtractor.ExtractByName(fileInBundle, fileBuffer); - ASSERT_FALSE(result); + EXPECT_FALSE(result); } /** @@ -1050,7 +1051,7 @@ HWTEST_F(BmsBundleParserTest, TestExtractByName_0200, Function | SmallTest | Lev BundleExtractor bundleExtractor(pathStream_.str()); bool result = bundleExtractor.ExtractByName(fileInBundle, fileBuffer); - ASSERT_FALSE(result); + EXPECT_FALSE(result); } /** @@ -1073,7 +1074,7 @@ HWTEST_F(BmsBundleParserTest, TestExtractByName_0300, Function | SmallTest | Lev BundleExtractor bundleExtractor(pathStream_.str()); bool result = bundleExtractor.ExtractByName(fileInBundle, fileBuffer); - ASSERT_FALSE(result); + EXPECT_FALSE(result); } /** @@ -1096,7 +1097,7 @@ HWTEST_F(BmsBundleParserTest, TestExtractByName_0400, Function | SmallTest | Lev BundleExtractor bundleExtractor(pathStream_.str()); bool result = bundleExtractor.ExtractByName(fileInBundle, fileBuffer); - ASSERT_FALSE(result); + EXPECT_FALSE(result); } /** @@ -1116,5 +1117,5 @@ HWTEST_F(BmsBundleParserTest, TestExtractByName_0500, Function | SmallTest | Lev BundleExtractor bundleExtractor(pathStream_.str()); bool result = bundleExtractor.ExtractByName(fileInBundle, fileBuffer); - ASSERT_FALSE(result); + EXPECT_FALSE(result); } \ No newline at end of file diff --git a/services/bundlemgr/test/unittest/bms_bundle_permission_test/BUILD.gn b/services/bundlemgr/test/unittest/bms_bundle_permission_test/BUILD.gn old mode 100644 new mode 100755 index 864e9a68c2..2d77307ed0 --- a/services/bundlemgr/test/unittest/bms_bundle_permission_test/BUILD.gn +++ b/services/bundlemgr/test/unittest/bms_bundle_permission_test/BUILD.gn @@ -19,7 +19,7 @@ module_output_path = "appexecfwk_standard/bundlemgrservice" ohos_unittest("BmsBundlePermissionTest") { module_out_path = module_output_path - + include_dirs = [ "//third_party/jsoncpp/include" ] sources = [ "${innerkits_path}/appexecfwk_base/src/ability_info.cpp", "${innerkits_path}/appexecfwk_base/src/application_info.cpp", @@ -34,6 +34,9 @@ ohos_unittest("BmsBundlePermissionTest") { "${services_path}/bundlemgr/src/installd/installd_host_impl.cpp", "${services_path}/bundlemgr/src/installd/installd_operator.cpp", "${services_path}/bundlemgr/src/installd/installd_service.cpp", + "${services_path}/bundlemgr/src/kvstore_death_recipient_callback.cpp", + "${services_path}/bundlemgr/src/module_usage_data_storage.cpp", + "${services_path}/bundlemgr/src/permission_changed_death_recipient.cpp", ] sources += [ @@ -66,6 +69,7 @@ ohos_unittest("BmsBundlePermissionTest") { "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", ] deps += bundle_install_deps diff --git a/services/bundlemgr/test/unittest/bms_bundle_permission_test/bms_bundle_permission_test.cpp b/services/bundlemgr/test/unittest/bms_bundle_permission_test/bms_bundle_permission_test.cpp index ccd86ee3e7..a0046249e0 100644 --- a/services/bundlemgr/test/unittest/bms_bundle_permission_test/bms_bundle_permission_test.cpp +++ b/services/bundlemgr/test/unittest/bms_bundle_permission_test/bms_bundle_permission_test.cpp @@ -843,7 +843,7 @@ bool BmsBundlePermissionTest::ConvertPermissionDef( return Permission::GrantMode::USER_GRANT; }(); permDef.availableScope = [&defPermission]() -> int { - int flag = 0; + uint flag = 0; if (std::find(defPermission.availableScope.begin(), defPermission.availableScope.end(), ProfileReader::BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_AVAILABLESCOPE_SIGNATURE) != @@ -873,14 +873,14 @@ void BmsBundlePermissionTest::CheckPermissionDef( { Permission::PermissionDef permDef; ConvertPermissionDef(permDef, defPermission, bundlename); - ASSERT_EQ(permissionDef.permissionName, permDef.permissionName); - ASSERT_EQ(permissionDef.bundleName, bundlename); - ASSERT_EQ(permissionDef.availableScope, permDef.availableScope); - ASSERT_EQ(permissionDef.grantMode, permDef.grantMode); - ASSERT_EQ(permissionDef.labelId, permDef.labelId); - ASSERT_EQ(permissionDef.label, permDef.label); - ASSERT_EQ(permissionDef.description, permDef.description); - ASSERT_EQ(permissionDef.descriptionId, permDef.descriptionId); + EXPECT_EQ(permissionDef.permissionName, permDef.permissionName); + EXPECT_EQ(permissionDef.bundleName, bundlename); + EXPECT_EQ(permissionDef.availableScope, permDef.availableScope); + EXPECT_EQ(permissionDef.grantMode, permDef.grantMode); + EXPECT_EQ(permissionDef.labelId, permDef.labelId); + EXPECT_EQ(permissionDef.label, permDef.label); + EXPECT_EQ(permissionDef.description, permDef.description); + EXPECT_EQ(permissionDef.descriptionId, permDef.descriptionId); } void BmsBundlePermissionTest::CheckErrPermissionDef( @@ -888,14 +888,14 @@ void BmsBundlePermissionTest::CheckErrPermissionDef( { Permission::PermissionDef permDef; ConvertPermissionDef(permDef, defPermission, bundlename); - ASSERT_NE(permissionDef.permissionName, permDef.permissionName); - ASSERT_NE(permissionDef.bundleName, bundlename); - ASSERT_NE(permissionDef.availableScope, permDef.availableScope); - ASSERT_NE(permissionDef.grantMode, permDef.grantMode); - ASSERT_NE(permissionDef.labelId, permDef.labelId); - ASSERT_NE(permissionDef.label, permDef.label); - ASSERT_NE(permissionDef.description, permDef.description); - ASSERT_NE(permissionDef.descriptionId, permDef.descriptionId); + EXPECT_NE(permissionDef.permissionName, permDef.permissionName); + EXPECT_NE(permissionDef.bundleName, bundlename); + EXPECT_NE(permissionDef.availableScope, permDef.availableScope); + EXPECT_NE(permissionDef.grantMode, permDef.grantMode); + EXPECT_NE(permissionDef.labelId, permDef.labelId); + EXPECT_NE(permissionDef.label, permDef.label); + EXPECT_NE(permissionDef.description, permDef.description); + EXPECT_NE(permissionDef.descriptionId, permDef.descriptionId); } /** @@ -910,7 +910,7 @@ HWTEST_F(BmsBundlePermissionTest, HapVerify_0100, Function | SmallTest | Level0) Verify::HapVerifyResult hapVerifyResult; bool result = BundleVerifyMgr::HapVerify(HAP_FILE_PATH, hapVerifyResult); - ASSERT_EQ(result, true); + EXPECT_EQ(result, true); } /** @@ -924,7 +924,7 @@ HWTEST_F(BmsBundlePermissionTest, HapVerify_0200, Function | SmallTest | Level0) { Verify::HapVerifyResult hapVerifyResult; bool result = BundleVerifyMgr::HapVerify(HAP_FILE_PATH1, hapVerifyResult); - ASSERT_EQ(result, false); + EXPECT_EQ(result, false); } /** @@ -1011,7 +1011,7 @@ HWTEST_F(BmsBundlePermissionTest, InstallPermissions_0300, Function | SmallTest MockReqPermissionBundle(innerbundleinfo2); BundlePermissionMgr::InstallPermissions(innerbundleinfo2); auto result = BundlePermissionMgr::VerifyPermission(MOCK_REQPERMISSION_NAME, DEFPERMISSION_NAME_WECHAT, 1); - ASSERT_EQ(result, Permission::TypePermissionState::PERMISSION_GRANTED); + EXPECT_EQ(result, Permission::TypePermissionState::PERMISSION_GRANTED); BundlePermissionMgr::UninstallPermissions(innerbundleinfo1); BundlePermissionMgr::UninstallPermissions(innerbundleinfo2); } @@ -1043,15 +1043,15 @@ HWTEST_F(BmsBundlePermissionTest, InstallPermissions_0400, Function | SmallTest BundlePermissionMgr::InstallPermissions(innerbundleinfo2); auto result1 = BundlePermissionMgr::VerifyPermission(MOCK_REQPERMISSION_NAME, DEFPERMISSION_NAME_WECHAT, 1); auto result2 = BundlePermissionMgr::VerifyPermission(MOCK_REQPERMISSION_NAME, DEFPERMISSION_NAME_EMAIL, 1); - ASSERT_EQ(result1, Permission::TypePermissionState::PERMISSION_GRANTED); - ASSERT_EQ(result2, Permission::TypePermissionState::PERMISSION_GRANTED); + EXPECT_EQ(result1, Permission::TypePermissionState::PERMISSION_GRANTED); + EXPECT_EQ(result2, Permission::TypePermissionState::PERMISSION_GRANTED); InnerBundleInfo innerbundleinfo3; MockOtherReqPermissionBundle(innerbundleinfo3); BundlePermissionMgr::InstallPermissions(innerbundleinfo3); auto result3 = BundlePermissionMgr::VerifyPermission(MOCK_REQPERMISSION_NAME_1, DEFPERMISSION_NAME_MUSIC, 1); auto result4 = BundlePermissionMgr::VerifyPermission(MOCK_REQPERMISSION_NAME_1, DEFPERMISSION_NAME_APP, 1); - ASSERT_EQ(result3, Permission::TypePermissionState::PERMISSION_GRANTED); - ASSERT_EQ(result4, Permission::TypePermissionState::PERMISSION_GRANTED); + EXPECT_EQ(result3, Permission::TypePermissionState::PERMISSION_GRANTED); + EXPECT_EQ(result4, Permission::TypePermissionState::PERMISSION_GRANTED); BundlePermissionMgr::UninstallPermissions(innerbundleinfo1); BundlePermissionMgr::UninstallPermissions(innerbundleinfo2); BundlePermissionMgr::UninstallPermissions(innerbundleinfo3); @@ -1095,7 +1095,7 @@ HWTEST_F(BmsBundlePermissionTest, InstallPermissions_0700, Function | SmallTest MockReqPermissionBundle(innerbundleinfo2); BundlePermissionMgr::InstallPermissions(innerbundleinfo2); auto result = BundlePermissionMgr::VerifyPermission(MOCK_REQPERMISSION_NAME, DEFPERMISSION_NAME1, 1); - ASSERT_EQ(result, Permission::TypePermissionState::PERMISSION_NOT_GRANTED); + EXPECT_EQ(result, Permission::TypePermissionState::PERMISSION_NOT_GRANTED); BundlePermissionMgr::UninstallPermissions(innerbundleinfo1); BundlePermissionMgr::UninstallPermissions(innerbundleinfo2); } @@ -1123,11 +1123,11 @@ HWTEST_F(BmsBundlePermissionTest, InstallPermissions_0800, Function | SmallTest MockDefPermissionBundleUserGrant(innerbundleinfo2); BundlePermissionMgr::InstallPermissions(innerbundleinfo2); BundlePermissionMgr::GetPermissionDef(DEFPERMISSION_NAME10, permissionDef2); - ASSERT_NE(permissionDef2.label, DEF_LABEL2); - ASSERT_NE(permissionDef2.grantMode, Permission::GrantMode::USER_GRANT); + EXPECT_NE(permissionDef2.label, DEF_LABEL2); + EXPECT_NE(permissionDef2.grantMode, Permission::GrantMode::USER_GRANT); BundlePermissionMgr::GetPermissionDef(DEFPERMISSION_NAME11, permissionDef2); - ASSERT_NE(permissionDef2.label, DEF_LABEL2); - ASSERT_NE(permissionDef2.grantMode, Permission::GrantMode::USER_GRANT); + EXPECT_NE(permissionDef2.label, DEF_LABEL2); + EXPECT_NE(permissionDef2.grantMode, Permission::GrantMode::USER_GRANT); auto bundlename1 = innerbundleinfo2.GetBundleName(); BundlePermissionMgr::GetPermissionDef(DEFPERMISSION_NAME12, permissionDef2); CheckPermissionDef(DEFPERMISSION_USERGRANT3, bundlename1, permissionDef2); @@ -1199,14 +1199,14 @@ HWTEST_F(BmsBundlePermissionTest, UninstallPermissions_0200, Function | SmallTes MockReqPermissionBundle(innerbundleinfo1); BundlePermissionMgr::InstallPermissions(innerbundleinfo1); auto result = BundlePermissionMgr::VerifyPermission(MOCK_REQPERMISSION_NAME, DEFPERMISSION_NAME_EMAIL, 1); - ASSERT_EQ(result, Permission::TypePermissionState::PERMISSION_GRANTED); + EXPECT_EQ(result, Permission::TypePermissionState::PERMISSION_GRANTED); auto result1 = BundlePermissionMgr::VerifyPermission(MOCK_REQPERMISSION_NAME, DEFPERMISSION_NAME_WECHAT, 1); - ASSERT_EQ(result1, Permission::TypePermissionState::PERMISSION_GRANTED); + EXPECT_EQ(result1, Permission::TypePermissionState::PERMISSION_GRANTED); BundlePermissionMgr::UninstallPermissions(innerbundleinfo1); auto result2 = BundlePermissionMgr::VerifyPermission(MOCK_REQPERMISSION_NAME, DEFPERMISSION_NAME_EMAIL, 1); - ASSERT_EQ(result2, Permission::TypePermissionState::PERMISSION_NOT_GRANTED); + EXPECT_EQ(result2, Permission::TypePermissionState::PERMISSION_NOT_GRANTED); auto result3 = BundlePermissionMgr::VerifyPermission(MOCK_REQPERMISSION_NAME, DEFPERMISSION_NAME_WECHAT, 1); - ASSERT_EQ(result3, Permission::TypePermissionState::PERMISSION_NOT_GRANTED); + EXPECT_EQ(result3, Permission::TypePermissionState::PERMISSION_NOT_GRANTED); BundlePermissionMgr::UninstallPermissions(innerbundleinfo); BundlePermissionMgr::UninstallPermissions(innerbundleinfo1); } @@ -1289,25 +1289,25 @@ HWTEST_F(BmsBundlePermissionTest, UninstallPermissions_0400, Function | SmallTes BundlePermissionMgr::InstallPermissions(innerbundleinfo2); auto result1 = BundlePermissionMgr::VerifyPermission(MOCK_REQPERMISSION_NAME, DEFPERMISSION_NAME_EMAIL, 1); auto result2 = BundlePermissionMgr::VerifyPermission(MOCK_REQPERMISSION_NAME, DEFPERMISSION_NAME_WECHAT, 1); - ASSERT_EQ(result1, Permission::TypePermissionState::PERMISSION_GRANTED); - ASSERT_EQ(result2, Permission::TypePermissionState::PERMISSION_GRANTED); + EXPECT_EQ(result1, Permission::TypePermissionState::PERMISSION_GRANTED); + EXPECT_EQ(result2, Permission::TypePermissionState::PERMISSION_GRANTED); InnerBundleInfo innerbundleinfo3; PermissionDef permissionDef3; MockOtherReqPermissionBundle(innerbundleinfo3); BundlePermissionMgr::InstallPermissions(innerbundleinfo3); auto result3 = BundlePermissionMgr::VerifyPermission(MOCK_REQPERMISSION_NAME_1, DEFPERMISSION_NAME_APP, 1); auto result4 = BundlePermissionMgr::VerifyPermission(MOCK_REQPERMISSION_NAME_1, DEFPERMISSION_NAME_MUSIC, 1); - ASSERT_EQ(result3, Permission::TypePermissionState::PERMISSION_GRANTED); - ASSERT_EQ(result4, Permission::TypePermissionState::PERMISSION_GRANTED); + EXPECT_EQ(result3, Permission::TypePermissionState::PERMISSION_GRANTED); + EXPECT_EQ(result4, Permission::TypePermissionState::PERMISSION_GRANTED); BundlePermissionMgr::UninstallPermissions(innerbundleinfo2); auto result5 = BundlePermissionMgr::VerifyPermission(MOCK_REQPERMISSION_NAME, DEFPERMISSION_NAME_EMAIL, 1); auto result6 = BundlePermissionMgr::VerifyPermission(MOCK_REQPERMISSION_NAME, DEFPERMISSION_NAME_WECHAT, 1); auto result7 = BundlePermissionMgr::VerifyPermission(MOCK_REQPERMISSION_NAME_1, DEFPERMISSION_NAME_APP, 1); auto result8 = BundlePermissionMgr::VerifyPermission(MOCK_REQPERMISSION_NAME_1, DEFPERMISSION_NAME_MUSIC, 1); - ASSERT_EQ(result5, Permission::TypePermissionState::PERMISSION_NOT_GRANTED); - ASSERT_EQ(result6, Permission::TypePermissionState::PERMISSION_NOT_GRANTED); - ASSERT_EQ(result7, Permission::TypePermissionState::PERMISSION_GRANTED); - ASSERT_EQ(result8, Permission::TypePermissionState::PERMISSION_GRANTED); + EXPECT_EQ(result5, Permission::TypePermissionState::PERMISSION_NOT_GRANTED); + EXPECT_EQ(result6, Permission::TypePermissionState::PERMISSION_NOT_GRANTED); + EXPECT_EQ(result7, Permission::TypePermissionState::PERMISSION_GRANTED); + EXPECT_EQ(result8, Permission::TypePermissionState::PERMISSION_GRANTED); BundlePermissionMgr::UninstallPermissions(innerbundleinfo1); BundlePermissionMgr::UninstallPermissions(innerbundleinfo2); BundlePermissionMgr::UninstallPermissions(innerbundleinfo3); @@ -1378,9 +1378,9 @@ HWTEST_F(BmsBundlePermissionTest, UninstallPermissions_0600, Function | SmallTes MockReqPermissionBundle(innerbundleinfo2); BundlePermissionMgr::InstallPermissions(innerbundleinfo2); auto result1 = BundlePermissionMgr::VerifyPermission(MOCK_REQPERMISSION_NAME, DEFPERMISSION_NAME_WECHAT, 1); - ASSERT_EQ(result1, Permission::TypePermissionState::PERMISSION_GRANTED); + EXPECT_EQ(result1, Permission::TypePermissionState::PERMISSION_GRANTED); auto result2 = BundlePermissionMgr::VerifyPermission(MOCK_REQPERMISSION_NAME, DEFPERMISSION_NAME_EMAIL, 1); - ASSERT_EQ(result2, Permission::TypePermissionState::PERMISSION_GRANTED); + EXPECT_EQ(result2, Permission::TypePermissionState::PERMISSION_GRANTED); InnerBundleInfo innerbundleinfo3; PermissionDef permissionDef1; MockNoDefPermissionBundle(innerbundleinfo3); @@ -1394,9 +1394,9 @@ HWTEST_F(BmsBundlePermissionTest, UninstallPermissions_0600, Function | SmallTes CheckErrPermissionDef(DEFPERMISSION_SYSTEM3, bundlename1, permissionDef1); BundlePermissionMgr::UninstallPermissions(innerbundleinfo3); auto result3 = BundlePermissionMgr::VerifyPermission(MOCK_REQPERMISSION_NAME, DEFPERMISSION_NAME_EMAIL, 1); - ASSERT_EQ(result3, Permission::TypePermissionState::PERMISSION_GRANTED); + EXPECT_EQ(result3, Permission::TypePermissionState::PERMISSION_GRANTED); auto result4 = BundlePermissionMgr::VerifyPermission(MOCK_REQPERMISSION_NAME, DEFPERMISSION_NAME_WECHAT, 1); - ASSERT_EQ(result4, Permission::TypePermissionState::PERMISSION_GRANTED); + EXPECT_EQ(result4, Permission::TypePermissionState::PERMISSION_GRANTED); BundlePermissionMgr::UninstallPermissions(innerbundleinfo); BundlePermissionMgr::UninstallPermissions(innerbundleinfo2); BundlePermissionMgr::UninstallPermissions(innerbundleinfo3); @@ -1433,7 +1433,7 @@ HWTEST_F(BmsBundlePermissionTest, UpdatePermissions_0100, Function | SmallTest | CheckPermissionDef(DEFPERMISSION_SAME2, bundlename1, permissionDef2); BundlePermissionMgr::GetPermissionDef(DEFPERMISSION_NAME18, permissionDef2); CheckPermissionDef(DEFPERMISSION_SAME3, bundlename1, permissionDef2); - ASSERT_EQ(result, true); + EXPECT_EQ(result, true); } /** @@ -1449,7 +1449,7 @@ HWTEST_F(BmsBundlePermissionTest, CheckCallingPermission_0100, Function | SmallT MockDefPermissionBundleSystemGrant(innerbundleinfo); std::string permissionName = DEFPERMISSION_NAME1; ErrCode result = BundlePermissionMgr::CheckCallingPermission(permissionName); - ASSERT_EQ(result, true); + EXPECT_EQ(result, true); } /** @@ -1479,8 +1479,8 @@ HWTEST_F(BmsBundlePermissionTest, VerifyPermission_0100, Function | SmallTest | BundlePermissionMgr::InstallPermissions(innerbundleinfo2); auto result = BundlePermissionMgr::VerifyPermission(MOCK_REQPERMISSION_NAME, DEFPERMISSION_NAME_EMAIL, 1); auto result1 = BundlePermissionMgr::VerifyPermission(MOCK_REQPERMISSION_NAME, DEFPERMISSION_NAME_WECHAT, 1); - ASSERT_EQ(result, Permission::TypePermissionState::PERMISSION_GRANTED); - ASSERT_EQ(result1, Permission::TypePermissionState::PERMISSION_GRANTED); + EXPECT_EQ(result, Permission::TypePermissionState::PERMISSION_GRANTED); + EXPECT_EQ(result1, Permission::TypePermissionState::PERMISSION_GRANTED); } /** @@ -1509,7 +1509,7 @@ HWTEST_F(BmsBundlePermissionTest, VerifyPermission_0200, Function | SmallTest | MockReqPermissionBundle(innerbundleinfo2); BundlePermissionMgr::InstallPermissions(innerbundleinfo2); auto result = BundlePermissionMgr::VerifyPermission(MOCK_REQPERMISSION_NAME, "error", 1); - ASSERT_EQ(result, Permission::TypePermissionState::PERMISSION_NOT_GRANTED); + EXPECT_EQ(result, Permission::TypePermissionState::PERMISSION_NOT_GRANTED); } /** @@ -1528,7 +1528,7 @@ HWTEST_F(BmsBundlePermissionTest, GetPermissionDef_0100, Function | SmallTest | std::string permissionName = DEFPERMISSION_NAME1; ErrCode result = BundlePermissionMgr::GetPermissionDef(permissionName, permdef); CheckPermissionDef(DEFPERMISSION_SYSTEM1, bundlename, permdef); - ASSERT_EQ(result, true); + EXPECT_EQ(result, true); } /** @@ -1547,12 +1547,12 @@ HWTEST_F(BmsBundlePermissionTest, GetPermissionDef_0200, Function | SmallTest | std::string permissionName1 = DEFPERMISSION_NAME1; ErrCode result1 = BundlePermissionMgr::GetPermissionDef(permissionName1, permdef1); CheckPermissionDef(DEFPERMISSION_SYSTEM1, bundlename, permdef1); - ASSERT_EQ(result1, true); + EXPECT_EQ(result1, true); PermissionDef permdef2; std::string permissionName2 = DEFPERMISSION_NAME2; ErrCode result2 = BundlePermissionMgr::GetPermissionDef(permissionName2, permdef2); CheckPermissionDef(DEFPERMISSION_SYSTEM2, bundlename, permdef2); - ASSERT_EQ(result2, true); + EXPECT_EQ(result2, true); } /** @@ -1574,32 +1574,32 @@ HWTEST_F(BmsBundlePermissionTest, GetPermissionDef_0300, Function | SmallTest | std::string permissionName1 = DEFPERMISSION_NAME1; ErrCode result1 = BundlePermissionMgr::GetPermissionDef(permissionName1, permdef); CheckPermissionDef(DEFPERMISSION_SYSTEM1, bundlename, permdef); - ASSERT_EQ(result1, true); + EXPECT_EQ(result1, true); PermissionDef permdef1; std::string permissionName2 = DEFPERMISSION_NAME2; ErrCode result2 = BundlePermissionMgr::GetPermissionDef(permissionName2, permdef1); CheckPermissionDef(DEFPERMISSION_SYSTEM2, bundlename, permdef1); - ASSERT_EQ(result2, true); + EXPECT_EQ(result2, true); PermissionDef permdef2; std::string permissionName3 = DEFPERMISSION_NAME3; ErrCode result3 = BundlePermissionMgr::GetPermissionDef(permissionName3, permdef2); CheckPermissionDef(DEFPERMISSION_SYSTEM3, bundlename, permdef2); - ASSERT_EQ(result3, true); + EXPECT_EQ(result3, true); PermissionDef permdef3; std::string permissionName4 = DEFPERMISSION_NAME16; ErrCode result4 = BundlePermissionMgr::GetPermissionDef(permissionName4, permdef3); CheckPermissionDef(DEFPERMISSION_SAME1, bundlename1, permdef3); - ASSERT_EQ(result4, true); + EXPECT_EQ(result4, true); PermissionDef permdef4; std::string permissionName5 = DEFPERMISSION_NAME17; ErrCode result5 = BundlePermissionMgr::GetPermissionDef(permissionName5, permdef4); CheckPermissionDef(DEFPERMISSION_SAME2, bundlename1, permdef4); - ASSERT_EQ(result5, true); + EXPECT_EQ(result5, true); PermissionDef permdef5; std::string permissionName6 = DEFPERMISSION_NAME18; ErrCode result6 = BundlePermissionMgr::GetPermissionDef(permissionName6, permdef5); CheckPermissionDef(DEFPERMISSION_SAME3, bundlename1, permdef5); - ASSERT_EQ(result6, true); + EXPECT_EQ(result6, true); } /** @@ -1618,10 +1618,10 @@ HWTEST_F(BmsBundlePermissionTest, GetPermissionDef_0400, Function | SmallTest | std::string permissionName = "1"; ErrCode result = BundlePermissionMgr::GetPermissionDef(permissionName, permdef); CheckErrPermissionDef(DEFPERMISSION_SYSTEM1, bundlename, permdef); - ASSERT_NE(permdef.permissionName, DEFPERMISSION_NAME1); - ASSERT_NE(permdef.permissionName, DEFPERMISSION_NAME2); - ASSERT_NE(permdef.permissionName, DEFPERMISSION_NAME3); - ASSERT_EQ(result, false); + EXPECT_NE(permdef.permissionName, DEFPERMISSION_NAME1); + EXPECT_NE(permdef.permissionName, DEFPERMISSION_NAME2); + EXPECT_NE(permdef.permissionName, DEFPERMISSION_NAME3); + EXPECT_NE(result, true); } /** @@ -1640,10 +1640,10 @@ HWTEST_F(BmsBundlePermissionTest, GetPermissionDef_0500, Function | SmallTest | std::string permissionName = ""; ErrCode result = BundlePermissionMgr::GetPermissionDef(permissionName, permdef); CheckErrPermissionDef(DEFPERMISSION_SYSTEM1, bundlename, permdef); - ASSERT_NE(permdef.permissionName, DEFPERMISSION_NAME1); - ASSERT_NE(permdef.permissionName, DEFPERMISSION_NAME2); - ASSERT_NE(permdef.permissionName, DEFPERMISSION_NAME3); - ASSERT_EQ(result, false); + EXPECT_NE(permdef.permissionName, DEFPERMISSION_NAME1); + EXPECT_NE(permdef.permissionName, DEFPERMISSION_NAME2); + EXPECT_NE(permdef.permissionName, DEFPERMISSION_NAME3); + EXPECT_EQ(result, false); } /** @@ -1660,7 +1660,7 @@ HWTEST_F(BmsBundlePermissionTest, CanRequestPermission_0100, Function | SmallTes std::string permissionName = DEFPERMISSION_NAME3; int userId = '1'; ErrCode result = BundlePermissionMgr::CanRequestPermission(innerbundleinfo.GetBundleName(), permissionName, userId); - ASSERT_EQ(result, 0); + EXPECT_EQ(result, 0); } /** @@ -1678,5 +1678,5 @@ HWTEST_F(BmsBundlePermissionTest, RequestPermissionFromUser_0100, Function | Sma int userId = '1'; ErrCode result = BundlePermissionMgr::RequestPermissionFromUser(innerbundleinfo.GetBundleName(), permissionName, userId); - ASSERT_EQ(result, true); + EXPECT_EQ(result, true); } diff --git a/services/bundlemgr/test/unittest/bms_bundle_uninstaller_test/BUILD.gn b/services/bundlemgr/test/unittest/bms_bundle_uninstaller_test/BUILD.gn old mode 100644 new mode 100755 index 93467df52c..2e1a6d40b7 --- a/services/bundlemgr/test/unittest/bms_bundle_uninstaller_test/BUILD.gn +++ b/services/bundlemgr/test/unittest/bms_bundle_uninstaller_test/BUILD.gn @@ -24,7 +24,7 @@ module_output_path = "appexecfwk_standard/bundlemgrservice" ohos_unittest("BmsBundleUninstallerTest") { module_out_path = module_output_path - + include_dirs = [ "//third_party/jsoncpp/include" ] sources = [ "${services_path}/bundlemgr/src/bundle_data_mgr.cpp", "${services_path}/bundlemgr/src/bundle_data_storage_database.cpp", @@ -36,6 +36,9 @@ ohos_unittest("BmsBundleUninstallerTest") { "${services_path}/bundlemgr/src/installd/installd_host_impl.cpp", "${services_path}/bundlemgr/src/installd/installd_operator.cpp", "${services_path}/bundlemgr/src/installd/installd_service.cpp", + "${services_path}/bundlemgr/src/kvstore_death_recipient_callback.cpp", + "${services_path}/bundlemgr/src/module_usage_data_storage.cpp", + "${services_path}/bundlemgr/src/permission_changed_death_recipient.cpp", ] sources += [ @@ -66,6 +69,7 @@ ohos_unittest("BmsBundleUninstallerTest") { "//foundation/distributeddatamgr/distributeddatamgr/interfaces/innerkits/distributeddata:distributeddata_inner", "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", "//utils/native/base:utils", ] diff --git a/services/bundlemgr/test/unittest/bms_bundle_uninstaller_test/bms_bundle_uninstaller_test.cpp b/services/bundlemgr/test/unittest/bms_bundle_uninstaller_test/bms_bundle_uninstaller_test.cpp index 56d6dedee8..4de4e6cd59 100755 --- a/services/bundlemgr/test/unittest/bms_bundle_uninstaller_test/bms_bundle_uninstaller_test.cpp +++ b/services/bundlemgr/test/unittest/bms_bundle_uninstaller_test/bms_bundle_uninstaller_test.cpp @@ -100,13 +100,13 @@ void BmsBundleUninstallerTest::SetUpTestCase() { if (access(ROOT_DIR.c_str(), F_OK) != 0) { bool result = OHOS::ForceCreateDirectory(ROOT_DIR); - ASSERT_TRUE(result); + EXPECT_TRUE(result); } if (chown(ROOT_DIR.c_str(), ROOT_UID, ROOT_UID) != 0) { - ASSERT_TRUE(false); + EXPECT_TRUE(false); } if (chmod(ROOT_DIR.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) { - ASSERT_TRUE(false); + EXPECT_TRUE(false); } } @@ -194,46 +194,46 @@ ErrCode BmsBundleUninstallerTest::UninstallModule(const std::string &bundleName, void BmsBundleUninstallerTest::CheckFileExist() const { int bundleDataExist = access(BUNDLE_DATA_DIR.c_str(), F_OK); - ASSERT_EQ(bundleDataExist, 0); + EXPECT_EQ(bundleDataExist, 0); int bundleCodeExist = access(BUNDLE_CODE_DIR.c_str(), F_OK); - ASSERT_EQ(bundleCodeExist, 0); + EXPECT_EQ(bundleCodeExist, 0); } void BmsBundleUninstallerTest::CheckModuleFileExist() const { int moduleDataExist = access(MODULE_DATA_DIR.c_str(), F_OK); - ASSERT_EQ(moduleDataExist, 0); + EXPECT_EQ(moduleDataExist, 0); int moduleCodeExist = access(MODULE_CODE_DIR.c_str(), F_OK); - ASSERT_EQ(moduleCodeExist, 0); + EXPECT_EQ(moduleCodeExist, 0); } void BmsBundleUninstallerTest::CheckModuleFileExist1() const { int moduleDataExist1 = access(MODULE_DATA_DIR1.c_str(), F_OK); - ASSERT_EQ(moduleDataExist1, 0); + EXPECT_EQ(moduleDataExist1, 0); int moduleCodeExist1 = access(MODULE_CODE_DIR1.c_str(), F_OK); - ASSERT_EQ(moduleCodeExist1, 0); + EXPECT_EQ(moduleCodeExist1, 0); } void BmsBundleUninstallerTest::CheckFileNonExist() const { int bundleDataExist = access(BUNDLE_DATA_DIR.c_str(), F_OK); - ASSERT_NE(bundleDataExist, 0); + EXPECT_NE(bundleDataExist, 0); int bundleCodeExist = access(BUNDLE_CODE_DIR.c_str(), F_OK); - ASSERT_NE(bundleCodeExist, 0); + EXPECT_NE(bundleCodeExist, 0); } void BmsBundleUninstallerTest::CheckModuleFileNonExist() const { int moduleDataExist = access(MODULE_DATA_DIR.c_str(), F_OK); - ASSERT_NE(moduleDataExist, 0); + EXPECT_NE(moduleDataExist, 0); int moduleCodeExist = access(MODULE_CODE_DIR.c_str(), F_OK); - ASSERT_NE(moduleCodeExist, 0); + EXPECT_NE(moduleCodeExist, 0); } void BmsBundleUninstallerTest::StopInstalldService() const @@ -267,22 +267,22 @@ void BmsBundleUninstallerTest::StopBundleService() void BmsBundleUninstallerTest::CheckBundleInfoExist() const { - ASSERT_NE(bundleMgrService_, nullptr); + EXPECT_NE(bundleMgrService_, nullptr); auto dataMgr = bundleMgrService_->GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); BundleInfo info; bool isBundleExist = dataMgr->GetBundleInfo(BUNDLE_NAME, BundleFlag::GET_BUNDLE_DEFAULT, info); - ASSERT_TRUE(isBundleExist); + EXPECT_TRUE(isBundleExist); } void BmsBundleUninstallerTest::CheckBundleInfoNonExist() const { - ASSERT_NE(bundleMgrService_, nullptr); + EXPECT_NE(bundleMgrService_, nullptr); auto dataMgr = bundleMgrService_->GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); BundleInfo info; bool isBundleExist = dataMgr->GetBundleInfo(BUNDLE_NAME, BundleFlag::GET_BUNDLE_DEFAULT, info); - ASSERT_FALSE(isBundleExist); + EXPECT_FALSE(isBundleExist); } const std::shared_ptr BmsBundleUninstallerTest::GetBundleMgrService() const @@ -308,7 +308,7 @@ void BmsBundleUninstallerTest::ClearBundleInfoInDb() applicationInfo.bundleName = BUNDLE_NAME; innerBundleInfo.SetBaseApplicationInfo(applicationInfo); bool result = dataStorage->DeleteStorageBundleInfo(Constants::CURRENT_DEVICE_ID, innerBundleInfo); - ASSERT_TRUE(result) << "the bundle info in db clear fail: " << BUNDLE_NAME; + EXPECT_TRUE(result) << "the bundle info in db clear fail: " << BUNDLE_NAME; } void BmsBundleUninstallerTest::DeleteInstallFiles() @@ -329,12 +329,12 @@ void BmsBundleUninstallerTest::DeleteInstallFiles() HWTEST_F(BmsBundleUninstallerTest, Bundle_Uninstall_0100, Function | SmallTest | Level0) { ErrCode installResult = InstallBundle(BUNDLE_FILE_PATH); - ASSERT_EQ(installResult, ERR_OK); + EXPECT_EQ(installResult, ERR_OK); CheckBundleInfoExist(); CheckFileExist(); ErrCode uninstallResult = UninstallBundle(BUNDLE_NAME); - ASSERT_EQ(uninstallResult, ERR_OK); + EXPECT_EQ(uninstallResult, ERR_OK); CheckFileNonExist(); CheckBundleInfoNonExist(); } @@ -373,19 +373,19 @@ HWTEST_F(BmsBundleUninstallerTest, Bundle_Uninstall_0300, Function | SmallTest | HWTEST_F(BmsBundleUninstallerTest, Bundle_Uninstall_0400, Function | SmallTest | Level0) { ErrCode installResult = InstallBundle(BUNDLE_FILE_PATH); - ASSERT_EQ(installResult, ERR_OK); + EXPECT_EQ(installResult, ERR_OK); CheckFileExist(); CheckBundleInfoExist(); StopBundleService(); ErrCode secondResult = UninstallBundle(BUNDLE_NAME); - ASSERT_EQ(secondResult, ERR_APPEXECFWK_UNINSTALL_BUNDLE_MGR_SERVICE_ERROR); + EXPECT_EQ(secondResult, ERR_APPEXECFWK_UNINSTALL_BUNDLE_MGR_SERVICE_ERROR); CheckFileExist(); StartBundleService(); CheckBundleInfoExist(); ErrCode thirdResult = UninstallBundle(BUNDLE_NAME); - ASSERT_EQ(thirdResult, ERR_OK); + EXPECT_EQ(thirdResult, ERR_OK); CheckFileNonExist(); CheckBundleInfoNonExist(); } @@ -399,13 +399,13 @@ HWTEST_F(BmsBundleUninstallerTest, Bundle_Uninstall_0400, Function | SmallTest | HWTEST_F(BmsBundleUninstallerTest, Bundle_Uninstall_0500, Function | SmallTest | Level0) { ErrCode installResult = InstallBundle(BUNDLE_FILE_PATH); - ASSERT_EQ(installResult, ERR_OK); + EXPECT_EQ(installResult, ERR_OK); CheckFileExist(); CheckBundleInfoExist(); StopInstalldService(); ErrCode uninstallResult = UninstallBundle(BUNDLE_NAME); - ASSERT_EQ(uninstallResult, ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR); + EXPECT_EQ(uninstallResult, ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR); CheckFileExist(); StartInstalldService(); @@ -422,16 +422,16 @@ HWTEST_F(BmsBundleUninstallerTest, Bundle_Uninstall_0500, Function | SmallTest | HWTEST_F(BmsBundleUninstallerTest, Bundle_Uninstall_0600, Function | SmallTest | Level1) { ErrCode installResult = InstallBundle(BUNDLE_FILE_PATH); - ASSERT_EQ(installResult, ERR_OK); + EXPECT_EQ(installResult, ERR_OK); CheckFileExist(); CheckBundleInfoExist(); InstallParam installParam; installParam.installFlag = InstallFlag::NORMAL; auto bms = GetBundleMgrService(); - ASSERT_NE(bms, nullptr); + EXPECT_NE(bms, nullptr); auto installer = bms->GetBundleInstaller(); - ASSERT_NE(installer, nullptr); + EXPECT_NE(installer, nullptr); bool result = installer->Uninstall(BUNDLE_NAME, installParam, nullptr); EXPECT_FALSE(result); @@ -450,14 +450,14 @@ HWTEST_F(BmsBundleUninstallerTest, Bundle_Uninstall_0600, Function | SmallTest | HWTEST_F(BmsBundleUninstallerTest, Bundle_Uninstall_0700, Function | SmallTest | Level0) { auto installer = std::make_unique(BUNDLE_FILE_PATH); - ASSERT_NE(installer, nullptr); + EXPECT_NE(installer, nullptr); bool installResult = installer->InstallSystemBundle(Constants::AppType::SYSTEM_APP); - ASSERT_EQ(installResult, true); + EXPECT_EQ(installResult, true); CheckFileExist(); CheckBundleInfoExist(); ErrCode uninstallResult = UninstallBundle(BUNDLE_NAME); - ASSERT_EQ(uninstallResult, ERR_APPEXECFWK_UNINSTALL_SYSTEM_APP_ERROR); + EXPECT_EQ(uninstallResult, ERR_APPEXECFWK_UNINSTALL_SYSTEM_APP_ERROR); CheckFileExist(); CheckBundleInfoExist(); DeleteInstallFiles(); @@ -472,12 +472,12 @@ HWTEST_F(BmsBundleUninstallerTest, Bundle_Uninstall_0700, Function | SmallTest | HWTEST_F(BmsBundleUninstallerTest, Module_Uninstall_0100, Function | SmallTest | Level0) { ErrCode installResult = InstallBundle(BUNDLE_FILE_PATH); - ASSERT_EQ(installResult, ERR_OK); + EXPECT_EQ(installResult, ERR_OK); CheckBundleInfoExist(); CheckFileExist(); ErrCode uninstallResult = UninstallModule(BUNDLE_NAME, MODULE_PACKAGE); - ASSERT_EQ(uninstallResult, ERR_OK); + EXPECT_EQ(uninstallResult, ERR_OK); CheckFileNonExist(); CheckBundleInfoNonExist(); } @@ -516,19 +516,19 @@ HWTEST_F(BmsBundleUninstallerTest, Module_Uninstall_0300, Function | SmallTest | HWTEST_F(BmsBundleUninstallerTest, Module_Uninstall_0400, Function | SmallTest | Level0) { ErrCode installResult = InstallBundle(BUNDLE_FILE_PATH); - ASSERT_EQ(installResult, ERR_OK); + EXPECT_EQ(installResult, ERR_OK); CheckFileExist(); CheckBundleInfoExist(); StopBundleService(); ErrCode secondResult = UninstallModule(BUNDLE_NAME, MODULE_PACKAGE); - ASSERT_EQ(secondResult, ERR_APPEXECFWK_UNINSTALL_BUNDLE_MGR_SERVICE_ERROR); + EXPECT_EQ(secondResult, ERR_APPEXECFWK_UNINSTALL_BUNDLE_MGR_SERVICE_ERROR); CheckFileExist(); StartBundleService(); CheckBundleInfoExist(); ErrCode thirdResult = UninstallModule(BUNDLE_NAME, MODULE_PACKAGE); - ASSERT_EQ(thirdResult, ERR_OK); + EXPECT_EQ(thirdResult, ERR_OK); CheckFileNonExist(); CheckBundleInfoNonExist(); } @@ -542,13 +542,13 @@ HWTEST_F(BmsBundleUninstallerTest, Module_Uninstall_0400, Function | SmallTest | HWTEST_F(BmsBundleUninstallerTest, Module_Uninstall_0500, Function | SmallTest | Level0) { ErrCode installResult = InstallBundle(BUNDLE_FILE_PATH); - ASSERT_EQ(installResult, ERR_OK); + EXPECT_EQ(installResult, ERR_OK); CheckFileExist(); CheckBundleInfoExist(); StopInstalldService(); ErrCode uninstallResult = UninstallModule(BUNDLE_NAME, MODULE_PACKAGE); - ASSERT_EQ(uninstallResult, ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR); + EXPECT_EQ(uninstallResult, ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR); CheckFileExist(); StartInstalldService(); @@ -565,16 +565,16 @@ HWTEST_F(BmsBundleUninstallerTest, Module_Uninstall_0500, Function | SmallTest | HWTEST_F(BmsBundleUninstallerTest, Module_Uninstall_0600, Function | SmallTest | Level1) { ErrCode installResult = InstallBundle(BUNDLE_FILE_PATH); - ASSERT_EQ(installResult, ERR_OK); + EXPECT_EQ(installResult, ERR_OK); CheckFileExist(); CheckBundleInfoExist(); InstallParam installParam; installParam.installFlag = InstallFlag::NORMAL; auto bms = GetBundleMgrService(); - ASSERT_NE(bms, nullptr); + EXPECT_NE(bms, nullptr); auto installer = bms->GetBundleInstaller(); - ASSERT_NE(installer, nullptr); + EXPECT_NE(installer, nullptr); bool result = installer->Uninstall(BUNDLE_NAME, MODULE_PACKAGE, installParam, nullptr); EXPECT_FALSE(result); @@ -593,14 +593,14 @@ HWTEST_F(BmsBundleUninstallerTest, Module_Uninstall_0600, Function | SmallTest | HWTEST_F(BmsBundleUninstallerTest, Module_Uninstall_0700, Function | SmallTest | Level0) { auto installer = std::make_unique(BUNDLE_FILE_PATH); - ASSERT_NE(installer, nullptr); + EXPECT_NE(installer, nullptr); bool installResult = installer->InstallSystemBundle(Constants::AppType::SYSTEM_APP); - ASSERT_EQ(installResult, true); + EXPECT_EQ(installResult, true); CheckFileExist(); CheckBundleInfoExist(); ErrCode uninstallResult = UninstallModule(BUNDLE_NAME, MODULE_PACKAGE); - ASSERT_EQ(uninstallResult, ERR_APPEXECFWK_UNINSTALL_SYSTEM_APP_ERROR); + EXPECT_EQ(uninstallResult, ERR_APPEXECFWK_UNINSTALL_SYSTEM_APP_ERROR); CheckFileExist(); CheckBundleInfoExist(); DeleteInstallFiles(); @@ -615,16 +615,16 @@ HWTEST_F(BmsBundleUninstallerTest, Module_Uninstall_0700, Function | SmallTest | HWTEST_F(BmsBundleUninstallerTest, Module_Uninstall_0800, Function | SmallTest | Level0) { ErrCode installResult = InstallBundle(BUNDLE_FILE_PATH); - ASSERT_EQ(installResult, ERR_OK); + EXPECT_EQ(installResult, ERR_OK); ErrCode installResult1 = InstallBundle(BUNDLE_FILE_PATH1); - ASSERT_EQ(installResult1, ERR_OK); + EXPECT_EQ(installResult1, ERR_OK); CheckBundleInfoExist(); CheckFileExist(); CheckModuleFileExist(); CheckModuleFileExist1(); ErrCode uninstallResult = UninstallModule(BUNDLE_NAME, MODULE_PACKAGE); - ASSERT_EQ(uninstallResult, ERR_OK); + EXPECT_EQ(uninstallResult, ERR_OK); CheckModuleFileNonExist(); CheckModuleFileExist1(); CheckBundleInfoExist(); @@ -640,18 +640,18 @@ HWTEST_F(BmsBundleUninstallerTest, Module_Uninstall_0800, Function | SmallTest | HWTEST_F(BmsBundleUninstallerTest, Module_Uninstall_0900, Function | SmallTest | Level0) { ErrCode installResult = InstallBundle(BUNDLE_FILE_PATH); - ASSERT_EQ(installResult, ERR_OK); + EXPECT_EQ(installResult, ERR_OK); ErrCode installResult1 = InstallBundle(BUNDLE_FILE_PATH1); - ASSERT_EQ(installResult1, ERR_OK); + EXPECT_EQ(installResult1, ERR_OK); CheckBundleInfoExist(); CheckFileExist(); CheckModuleFileExist(); CheckModuleFileExist1(); ErrCode uninstallResult = UninstallModule(BUNDLE_NAME, MODULE_PACKAGE); - ASSERT_EQ(uninstallResult, ERR_OK); + EXPECT_EQ(uninstallResult, ERR_OK); ErrCode uninstallResult1 = UninstallModule(BUNDLE_NAME, MODULE_PACKAGE1); - ASSERT_EQ(uninstallResult1, ERR_OK); + EXPECT_EQ(uninstallResult1, ERR_OK); CheckFileNonExist(); CheckBundleInfoNonExist(); DeleteInstallFiles(); diff --git a/services/bundlemgr/test/unittest/bms_bundle_updater_test/BUILD.gn b/services/bundlemgr/test/unittest/bms_bundle_updater_test/BUILD.gn old mode 100644 new mode 100755 index 3b86be9ea7..88c04eceb2 --- a/services/bundlemgr/test/unittest/bms_bundle_updater_test/BUILD.gn +++ b/services/bundlemgr/test/unittest/bms_bundle_updater_test/BUILD.gn @@ -27,7 +27,7 @@ module_output_path = "appexecfwk_standard/bundlemgrservice" ohos_unittest("BmsBundleUpdaterTest") { module_out_path = module_output_path - + include_dirs = [ "//third_party/jsoncpp/include" ] sources = [ "${services_path}/bundlemgr/src/bundle_data_mgr.cpp", "${services_path}/bundlemgr/src/bundle_data_storage_database.cpp", @@ -39,6 +39,9 @@ ohos_unittest("BmsBundleUpdaterTest") { "${services_path}/bundlemgr/src/installd/installd_host_impl.cpp", "${services_path}/bundlemgr/src/installd/installd_operator.cpp", "${services_path}/bundlemgr/src/installd/installd_service.cpp", + "${services_path}/bundlemgr/src/kvstore_death_recipient_callback.cpp", + "${services_path}/bundlemgr/src/module_usage_data_storage.cpp", + "${services_path}/bundlemgr/src/permission_changed_death_recipient.cpp", ] sources += [ @@ -70,6 +73,7 @@ ohos_unittest("BmsBundleUpdaterTest") { "//foundation/distributeddatamgr/distributeddatamgr/interfaces/innerkits/distributeddata:distributeddata_inner", "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", "//utils/native/base:utils", ] diff --git a/services/bundlemgr/test/unittest/bms_bundle_updater_test/bms_bundle_updater_test.cpp b/services/bundlemgr/test/unittest/bms_bundle_updater_test/bms_bundle_updater_test.cpp index b66b206385..c305f3712c 100755 --- a/services/bundlemgr/test/unittest/bms_bundle_updater_test/bms_bundle_updater_test.cpp +++ b/services/bundlemgr/test/unittest/bms_bundle_updater_test/bms_bundle_updater_test.cpp @@ -89,13 +89,13 @@ void BmsBundleUpdaterTest::SetUpTestCase() { if (access(ROOT_DIR.c_str(), F_OK) != 0) { bool result = OHOS::ForceCreateDirectory(ROOT_DIR); - ASSERT_TRUE(result) << "fail to create root dir"; + EXPECT_TRUE(result) << "fail to create root dir"; } if (chown(ROOT_DIR.c_str(), ROOT_UID, ROOT_UID) != 0) { - ASSERT_TRUE(false) << "fail to change root dir own ship"; + EXPECT_TRUE(false) << "fail to change root dir own ship"; } if (chmod(ROOT_DIR.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) { - ASSERT_TRUE(false) << "fail to change root dir mode"; + EXPECT_TRUE(false) << "fail to change root dir mode"; } } @@ -289,7 +289,7 @@ bool BmsBundleUpdaterTest::CheckApplicationInfo() const HWTEST_F(BmsBundleUpdaterTest, Update_0100, Function | SmallTest | Level2) { ErrCode installResult = InstallBundle(BUNDLE_FILE_DIR + V1_BUNDLE); - ASSERT_EQ(installResult, ERR_OK); + EXPECT_EQ(installResult, ERR_OK); CommonTool tool; long codeDirFirstCreateTime = tool.GetFileBuildTime(BUNDLE_CODE_DIR.c_str()); long dataDirFirstCreateTime = tool.GetFileBuildTime(BUNDLE_DATA_DIR.c_str()); @@ -298,12 +298,12 @@ HWTEST_F(BmsBundleUpdaterTest, Update_0100, Function | SmallTest | Level2) std::this_thread::sleep_for(SLEEP_TIME); ErrCode updateResult = UpdateBundle(BUNDLE_FILE_DIR + V2_BUNDLE, true); - ASSERT_EQ(updateResult, ERR_OK); + EXPECT_EQ(updateResult, ERR_OK); long codeDirSecondCreateTime = tool.GetFileBuildTime(BUNDLE_CODE_DIR.c_str()); long dataDirSecondCreateTime = tool.GetFileBuildTime(BUNDLE_DATA_DIR.c_str()); - ASSERT_EQ(dataDirFirstCreateTime, dataDirSecondCreateTime); - ASSERT_NE(codeDirFirstCreateTime, codeDirSecondCreateTime); + EXPECT_EQ(dataDirFirstCreateTime, dataDirSecondCreateTime); + EXPECT_NE(codeDirFirstCreateTime, codeDirSecondCreateTime); bool isExist = CheckBundleInfo(VERSION_2, true); EXPECT_TRUE(isExist); @@ -318,10 +318,10 @@ HWTEST_F(BmsBundleUpdaterTest, Update_0100, Function | SmallTest | Level2) HWTEST_F(BmsBundleUpdaterTest, Update_0200, Function | SmallTest | Level1) { ErrCode installResult = InstallBundle(BUNDLE_FILE_DIR + V2_BUNDLE); - ASSERT_EQ(installResult, ERR_OK); + EXPECT_EQ(installResult, ERR_OK); ErrCode updateResult = UpdateBundle(BUNDLE_FILE_DIR + V3_BUNDLE); - ASSERT_EQ(updateResult, ERR_OK); + EXPECT_EQ(updateResult, ERR_OK); CheckFileExist(); bool result = CheckBundleInfo(VERSION_3, true); @@ -337,7 +337,7 @@ HWTEST_F(BmsBundleUpdaterTest, Update_0200, Function | SmallTest | Level1) HWTEST_F(BmsBundleUpdaterTest, Update_0300, Function | SmallTest | Level0) { ErrCode installResult = InstallBundle(BUNDLE_FILE_DIR + V1_BUNDLE); - ASSERT_EQ(installResult, ERR_OK); + EXPECT_EQ(installResult, ERR_OK); ErrCode updateResult = UpdateBundle(""); EXPECT_EQ(updateResult, ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID); @@ -352,7 +352,7 @@ HWTEST_F(BmsBundleUpdaterTest, Update_0300, Function | SmallTest | Level0) HWTEST_F(BmsBundleUpdaterTest, Update_0400, Function | SmallTest | Level0) { ErrCode installResult = InstallBundle(BUNDLE_FILE_DIR + V1_BUNDLE); - ASSERT_EQ(installResult, ERR_OK); + EXPECT_EQ(installResult, ERR_OK); ErrCode updateResult = UpdateBundle(BUNDLE_FILE_DIR + ERROR_BUNDLE_NAME); EXPECT_EQ(updateResult, ERR_APPEXECFWK_INSTALL_INVALID_HAP_NAME); @@ -367,7 +367,7 @@ HWTEST_F(BmsBundleUpdaterTest, Update_0400, Function | SmallTest | Level0) HWTEST_F(BmsBundleUpdaterTest, Update_0500, Function | SmallTest | Level0) { ErrCode installResult = InstallBundle(BUNDLE_FILE_DIR + V1_BUNDLE); - ASSERT_EQ(installResult, ERR_OK); + EXPECT_EQ(installResult, ERR_OK); ErrCode updateResult = UpdateBundle(BUNDLE_FILE_DIR + ERROR_FORMART_BUNDLE); EXPECT_EQ(updateResult, ERR_APPEXECFWK_PARSE_NO_PROFILE); @@ -382,7 +382,7 @@ HWTEST_F(BmsBundleUpdaterTest, Update_0500, Function | SmallTest | Level0) HWTEST_F(BmsBundleUpdaterTest, Update_0600, Function | SmallTest | Level0) { ErrCode installResult = InstallBundle(BUNDLE_FILE_DIR + V2_BUNDLE); - ASSERT_EQ(installResult, ERR_OK); + EXPECT_EQ(installResult, ERR_OK); ErrCode updateResult = UpdateBundle(BUNDLE_FILE_DIR + V1_BUNDLE); EXPECT_EQ(updateResult, ERR_APPEXECFWK_INSTALL_VERSION_DOWNGRADE); @@ -398,23 +398,23 @@ HWTEST_F(BmsBundleUpdaterTest, Update_0600, Function | SmallTest | Level0) HWTEST_F(BmsBundleUpdaterTest, Update_0700, Function | SmallTest | Level1) { ErrCode installResult = InstallBundle(BUNDLE_FILE_DIR + V1_BUNDLE); - ASSERT_EQ(installResult, ERR_OK); + EXPECT_EQ(installResult, ERR_OK); StopInstalldService(); ErrCode updateResult = UpdateBundle(BUNDLE_FILE_DIR + V3_BUNDLE); - ASSERT_EQ(updateResult, ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR); + EXPECT_EQ(updateResult, ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR); BundleInfo info; auto dataMgr = GetBundleDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool isInfoExist = dataMgr->GetBundleInfo(BUNDLE_NAME, BundleFlag::GET_BUNDLE_DEFAULT, info); - ASSERT_TRUE(isInfoExist); - ASSERT_EQ(info.versionCode, VERSION_1); + EXPECT_TRUE(isInfoExist); + EXPECT_EQ(info.versionCode, VERSION_1); StartInstalldService(); updateResult = UpdateBundle(BUNDLE_FILE_DIR + V3_BUNDLE); - ASSERT_EQ(updateResult, ERR_OK); - ASSERT_EQ(info.versionCode, VERSION_1); + EXPECT_EQ(updateResult, ERR_OK); + EXPECT_EQ(info.versionCode, VERSION_1); CheckFileExist(); } @@ -428,32 +428,32 @@ HWTEST_F(BmsBundleUpdaterTest, Update_0700, Function | SmallTest | Level1) HWTEST_F(BmsBundleUpdaterTest, Update_0800, Function | SmallTest | Level1) { ErrCode installResult = InstallBundle(BUNDLE_FILE_DIR + V1_BUNDLE); - ASSERT_EQ(installResult, ERR_OK); + EXPECT_EQ(installResult, ERR_OK); StopBundleService(); DelayedSingleton::DestroyInstance(); sptr installer = new (std::nothrow) BundleInstallerHost(); - ASSERT_NE(installer, nullptr); + EXPECT_NE(installer, nullptr); installer->Init(); sptr receiver = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver, nullptr); + EXPECT_NE(receiver, nullptr); InstallParam installParam; installParam.installFlag = InstallFlag::REPLACE_EXISTING; installer->Install(BUNDLE_FILE_DIR + V3_BUNDLE, installParam, receiver); ErrCode result = receiver->GetResultCode(); - ASSERT_EQ(result, ERR_APPEXECFWK_INSTALL_BUNDLE_MGR_SERVICE_ERROR); + EXPECT_EQ(result, ERR_APPEXECFWK_INSTALL_BUNDLE_MGR_SERVICE_ERROR); DelayedSingleton::GetInstance()->OnStart(); BundleInfo info; auto dataMgr = GetBundleDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool isInfoExist = dataMgr->GetBundleInfo(BUNDLE_NAME, BundleFlag::GET_BUNDLE_DEFAULT, info); - ASSERT_TRUE(isInfoExist); - ASSERT_EQ(info.versionCode, VERSION_1); + EXPECT_TRUE(isInfoExist); + EXPECT_EQ(info.versionCode, VERSION_1); ErrCode updateResult = UpdateBundle(BUNDLE_FILE_DIR + V3_BUNDLE); - ASSERT_EQ(updateResult, ERR_OK); + EXPECT_EQ(updateResult, ERR_OK); CheckFileExist(); } @@ -466,13 +466,13 @@ HWTEST_F(BmsBundleUpdaterTest, Update_0800, Function | SmallTest | Level1) HWTEST_F(BmsBundleUpdaterTest, Update_0900, Function | SmallTest | Level2) { ErrCode installResult = InstallBundle(BUNDLE_FILE_DIR + V1_BUNDLE); - ASSERT_EQ(installResult, ERR_OK); + EXPECT_EQ(installResult, ERR_OK); CommonTool tool; long codeDirFirstCreateTime = tool.GetFileBuildTime(BUNDLE_CODE_DIR.c_str()); long dataDirFirstCreateTime = tool.GetFileBuildTime(BUNDLE_DATA_DIR.c_str()); auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); - ASSERT_FALSE(!installer); + EXPECT_FALSE(!installer); InstallParam installParam; installParam.installFlag = InstallFlag::REPLACE_EXISTING; installer->Install(BUNDLE_FILE_DIR + V2_BUNDLE, installParam, nullptr); @@ -482,8 +482,8 @@ HWTEST_F(BmsBundleUpdaterTest, Update_0900, Function | SmallTest | Level2) long codeDirSecondCreateTime = tool.GetFileBuildTime(BUNDLE_CODE_DIR.c_str()); long dataDirSecondCreateTime = tool.GetFileBuildTime(BUNDLE_DATA_DIR.c_str()); - ASSERT_EQ(dataDirFirstCreateTime, dataDirSecondCreateTime); - ASSERT_EQ(codeDirFirstCreateTime, codeDirSecondCreateTime); + EXPECT_EQ(dataDirFirstCreateTime, dataDirSecondCreateTime); + EXPECT_EQ(codeDirFirstCreateTime, codeDirSecondCreateTime); bool isExist = CheckBundleInfo(VERSION_1, true); EXPECT_TRUE(isExist); @@ -498,7 +498,7 @@ HWTEST_F(BmsBundleUpdaterTest, Update_0900, Function | SmallTest | Level2) HWTEST_F(BmsBundleUpdaterTest, Update_1000, Function | SmallTest | Level2) { ErrCode installResult = InstallBundle(BUNDLE_FILE_DIR + V1_BUNDLE); - ASSERT_EQ(installResult, ERR_OK); + EXPECT_EQ(installResult, ERR_OK); CommonTool tool; long codeDirFirstCreateTime = tool.GetFileBuildTime(BUNDLE_CODE_DIR.c_str()); long dataDirFirstCreateTime = tool.GetFileBuildTime(BUNDLE_DATA_DIR.c_str()); @@ -507,12 +507,12 @@ HWTEST_F(BmsBundleUpdaterTest, Update_1000, Function | SmallTest | Level2) std::this_thread::sleep_for(SLEEP_TIME); ErrCode updateResult = UpdateBundle(BUNDLE_FILE_DIR + V2_BUNDLE); - ASSERT_EQ(updateResult, ERR_OK); + EXPECT_EQ(updateResult, ERR_OK); long codeDirSecondCreateTime = tool.GetFileBuildTime(BUNDLE_CODE_DIR.c_str()); long dataDirSecondCreateTime = tool.GetFileBuildTime(BUNDLE_DATA_DIR.c_str()); - ASSERT_EQ(dataDirFirstCreateTime, dataDirSecondCreateTime); - ASSERT_NE(codeDirFirstCreateTime, codeDirSecondCreateTime); + EXPECT_EQ(dataDirFirstCreateTime, dataDirSecondCreateTime); + EXPECT_NE(codeDirFirstCreateTime, codeDirSecondCreateTime); bool isExist = CheckBundleInfo(VERSION_2, true); EXPECT_TRUE(isExist); @@ -520,12 +520,12 @@ HWTEST_F(BmsBundleUpdaterTest, Update_1000, Function | SmallTest | Level2) std::this_thread::sleep_for(SLEEP_TIME); updateResult = UpdateBundle(BUNDLE_FILE_DIR + V3_BUNDLE); - ASSERT_EQ(updateResult, ERR_OK); + EXPECT_EQ(updateResult, ERR_OK); long codeDirThirdCreateTime = tool.GetFileBuildTime(BUNDLE_CODE_DIR.c_str()); long dataDirThirdCreateTime = tool.GetFileBuildTime(BUNDLE_DATA_DIR.c_str()); - ASSERT_EQ(dataDirSecondCreateTime, dataDirThirdCreateTime); - ASSERT_NE(codeDirSecondCreateTime, codeDirThirdCreateTime); + EXPECT_EQ(dataDirSecondCreateTime, dataDirThirdCreateTime); + EXPECT_NE(codeDirSecondCreateTime, codeDirThirdCreateTime); isExist = CheckBundleInfo(VERSION_3, true); EXPECT_TRUE(isExist); diff --git a/services/bundlemgr/test/unittest/bms_data_mgr_test/BUILD.gn b/services/bundlemgr/test/unittest/bms_data_mgr_test/BUILD.gn old mode 100644 new mode 100755 index d8f52fbec5..52e14c4888 --- a/services/bundlemgr/test/unittest/bms_data_mgr_test/BUILD.gn +++ b/services/bundlemgr/test/unittest/bms_data_mgr_test/BUILD.gn @@ -16,11 +16,15 @@ import("//foundation/appexecfwk/standard/appexecfwk.gni") import( "//foundation/appexecfwk/standard/services/bundlemgr/appexecfwk_bundlemgr.gni") +config("private_config") { + include_dirs = [ "${services_path}/bundlemgr/test/mock/include" ] +} + module_output_path = "appexecfwk_standard/bundlemgrservice" ohos_unittest("BmsDataMgrTest") { module_out_path = module_output_path - + include_dirs = [ "//third_party/jsoncpp/include" ] sources = [ "${innerkits_path}/appexecfwk_base/src/ability_info.cpp", "${innerkits_path}/appexecfwk_base/src/application_info.cpp", @@ -28,7 +32,19 @@ ohos_unittest("BmsDataMgrTest") { "${innerkits_path}/appexecfwk_base/src/element_name.cpp", "${services_path}/bundlemgr/src/bundle_data_mgr.cpp", "${services_path}/bundlemgr/src/bundle_data_storage_database.cpp", + "${services_path}/bundlemgr/src/bundle_mgr_host_impl.cpp", + "${services_path}/bundlemgr/src/bundle_mgr_service.cpp", + "${services_path}/bundlemgr/src/bundle_mgr_service_event_handler.cpp", + "${services_path}/bundlemgr/src/bundle_scanner.cpp", "${services_path}/bundlemgr/src/bundle_status_callback_death_recipient.cpp", + "${services_path}/bundlemgr/src/kvstore_death_recipient_callback.cpp", + "${services_path}/bundlemgr/src/module_usage_data_storage.cpp", + "${services_path}/bundlemgr/src/permission_changed_death_recipient.cpp", + ] + + sources += [ + "${services_path}/bundlemgr/test/mock/src/mock_status_receiver.cpp", + "${services_path}/bundlemgr/test/mock/src/system_ability_helper.cpp", ] sources += bundle_install_sources @@ -50,16 +66,21 @@ ohos_unittest("BmsDataMgrTest") { "${libs_path}/libeventhandler:libeventhandler_target", "${services_path}/bundlemgr:bundle_parser", "${services_path}/bundlemgr:parser_common", + "//base/security/appverify/interfaces/innerkits/appverify:libhapverify", + "//base/security/permission/interfaces/innerkits/permission_standard/permissionsdk:libpermissionsdk_standard", "//foundation/aafwk/standard/interfaces/innerkits/base:base", "//foundation/aafwk/standard/interfaces/innerkits/want:want", "//foundation/distributeddatamgr/distributeddatamgr/interfaces/innerkits/distributeddata:distributeddata_inner", "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", + "//utils/native/base:utils", ] deps += bundle_install_deps external_deps = [ + "ces_standard:cesfwk_innerkits", "hiviewdfx_hilog_native:libhilog", "ipc:ipc_core", ] diff --git a/services/bundlemgr/test/unittest/bms_data_mgr_test/bms_data_mgr_test.cpp b/services/bundlemgr/test/unittest/bms_data_mgr_test/bms_data_mgr_test.cpp index f22beefdb4..f276ed52dc 100755 --- a/services/bundlemgr/test/unittest/bms_data_mgr_test/bms_data_mgr_test.cpp +++ b/services/bundlemgr/test/unittest/bms_data_mgr_test/bms_data_mgr_test.cpp @@ -122,7 +122,7 @@ const std::shared_ptr BmsDataMgrTest::GetDataMgr() const HWTEST_F(BmsDataMgrTest, UpdateInstallState_0100, Function | SmallTest | Level0) { auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_FAIL); EXPECT_TRUE(ret1); @@ -138,7 +138,7 @@ HWTEST_F(BmsDataMgrTest, UpdateInstallState_0100, Function | SmallTest | Level0) HWTEST_F(BmsDataMgrTest, UpdateInstallState_0200, Function | SmallTest | Level0) { auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_SUCCESS); bool ret3 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UPDATING_START); @@ -158,7 +158,7 @@ HWTEST_F(BmsDataMgrTest, UpdateInstallState_0200, Function | SmallTest | Level0) HWTEST_F(BmsDataMgrTest, UpdateInstallState_0300, Function | SmallTest | Level0) { auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_SUCCESS); bool ret3 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UPDATING_START); @@ -180,7 +180,7 @@ HWTEST_F(BmsDataMgrTest, UpdateInstallState_0300, Function | SmallTest | Level0) HWTEST_F(BmsDataMgrTest, UpdateInstallState_0400, Function | SmallTest | Level0) { auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_SUCCESS); bool ret3 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_START); @@ -200,7 +200,7 @@ HWTEST_F(BmsDataMgrTest, UpdateInstallState_0400, Function | SmallTest | Level0) HWTEST_F(BmsDataMgrTest, UpdateInstallState_0500, Function | SmallTest | Level0) { auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_SUCCESS); bool ret3 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_START); @@ -220,7 +220,7 @@ HWTEST_F(BmsDataMgrTest, UpdateInstallState_0500, Function | SmallTest | Level0) HWTEST_F(BmsDataMgrTest, UpdateInstallState_0600, Function | SmallTest | Level0) { auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); EXPECT_TRUE(ret1); @@ -237,7 +237,7 @@ HWTEST_F(BmsDataMgrTest, UpdateInstallState_0600, Function | SmallTest | Level0) HWTEST_F(BmsDataMgrTest, UpdateInstallState_0700, Function | SmallTest | Level0) { auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_START); EXPECT_TRUE(ret1); @@ -254,7 +254,7 @@ HWTEST_F(BmsDataMgrTest, UpdateInstallState_0700, Function | SmallTest | Level0) HWTEST_F(BmsDataMgrTest, UpdateInstallState_0800, Function | SmallTest | Level0) { auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_SUCCESS); EXPECT_TRUE(ret1); @@ -271,7 +271,7 @@ HWTEST_F(BmsDataMgrTest, UpdateInstallState_0800, Function | SmallTest | Level0) HWTEST_F(BmsDataMgrTest, UpdateInstallState_0900, Function | SmallTest | Level0) { auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_FAIL); EXPECT_TRUE(ret1); @@ -288,7 +288,7 @@ HWTEST_F(BmsDataMgrTest, UpdateInstallState_0900, Function | SmallTest | Level0) HWTEST_F(BmsDataMgrTest, UpdateInstallState_1000, Function | SmallTest | Level0) { auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UPDATING_START); EXPECT_TRUE(ret1); @@ -305,7 +305,7 @@ HWTEST_F(BmsDataMgrTest, UpdateInstallState_1000, Function | SmallTest | Level0) HWTEST_F(BmsDataMgrTest, UpdateInstallState_1100, Function | SmallTest | Level0) { auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UPDATING_SUCCESS); EXPECT_TRUE(ret1); @@ -322,7 +322,7 @@ HWTEST_F(BmsDataMgrTest, UpdateInstallState_1100, Function | SmallTest | Level0) HWTEST_F(BmsDataMgrTest, UpdateInstallState_1200, Function | SmallTest | Level0) { auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UPDATING_FAIL); EXPECT_TRUE(ret1); @@ -339,7 +339,7 @@ HWTEST_F(BmsDataMgrTest, UpdateInstallState_1200, Function | SmallTest | Level0) HWTEST_F(BmsDataMgrTest, UpdateInstallState_1300, Function | SmallTest | Level0) { auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_SUCCESS); bool ret3 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_SUCCESS); @@ -359,7 +359,7 @@ HWTEST_F(BmsDataMgrTest, UpdateInstallState_1300, Function | SmallTest | Level0) HWTEST_F(BmsDataMgrTest, UpdateInstallState_1400, Function | SmallTest | Level0) { auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_SUCCESS); bool ret3 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); @@ -379,7 +379,7 @@ HWTEST_F(BmsDataMgrTest, UpdateInstallState_1400, Function | SmallTest | Level0) HWTEST_F(BmsDataMgrTest, UpdateInstallState_1500, Function | SmallTest | Level0) { auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_SUCCESS); bool ret3 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_FAIL); @@ -399,7 +399,7 @@ HWTEST_F(BmsDataMgrTest, UpdateInstallState_1500, Function | SmallTest | Level0) HWTEST_F(BmsDataMgrTest, UpdateInstallState_1600, Function | SmallTest | Level0) { auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_SUCCESS); bool ret3 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_SUCCESS); @@ -419,7 +419,7 @@ HWTEST_F(BmsDataMgrTest, UpdateInstallState_1600, Function | SmallTest | Level0) HWTEST_F(BmsDataMgrTest, UpdateInstallState_1700, Function | SmallTest | Level0) { auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_SUCCESS); bool ret3 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_FAIL); @@ -439,7 +439,7 @@ HWTEST_F(BmsDataMgrTest, UpdateInstallState_1700, Function | SmallTest | Level0) HWTEST_F(BmsDataMgrTest, UpdateInstallState_1800, Function | SmallTest | Level0) { auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_SUCCESS); bool ret3 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UPDATING_FAIL); @@ -459,7 +459,7 @@ HWTEST_F(BmsDataMgrTest, UpdateInstallState_1800, Function | SmallTest | Level0) HWTEST_F(BmsDataMgrTest, UpdateInstallState_1900, Function | SmallTest | Level0) { auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_SUCCESS); bool ret3 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UPDATING_SUCCESS); @@ -479,7 +479,7 @@ HWTEST_F(BmsDataMgrTest, UpdateInstallState_1900, Function | SmallTest | Level0) HWTEST_F(BmsDataMgrTest, UpdateInstallState_2000, Function | SmallTest | Level0) { auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool ret1 = dataMgr->UpdateBundleInstallState("", InstallState::INSTALL_START); EXPECT_FALSE(ret1); } @@ -493,7 +493,7 @@ HWTEST_F(BmsDataMgrTest, UpdateInstallState_2000, Function | SmallTest | Level0) HWTEST_F(BmsDataMgrTest, LoadDataFromPersistentStorage_0100, Function | SmallTest | Level0) { auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool ret1 = dataMgr->LoadDataFromPersistentStorage(); EXPECT_FALSE(ret1); @@ -532,7 +532,7 @@ HWTEST_F(BmsDataMgrTest, AddBundleInfo_0100, Function | SmallTest | Level0) info.SetBaseBundleInfo(bundleInfo); info.SetBaseApplicationInfo(applicationInfo); auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); InnerBundleInfo info1; bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_SUCCESS); @@ -577,7 +577,7 @@ HWTEST_F(BmsDataMgrTest, AddBundleInfo_0200, Function | SmallTest | Level0) info2.SetBaseBundleInfo(bundleInfo2); info2.SetBaseApplicationInfo(applicationInfo2); auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_SUCCESS); bool ret3 = dataMgr->AddInnerBundleInfo(BUNDLE_NAME, info1); @@ -610,7 +610,7 @@ HWTEST_F(BmsDataMgrTest, AddBundleInfo_0200, Function | SmallTest | Level0) HWTEST_F(BmsDataMgrTest, AddBundleInfo_0300, Function | SmallTest | Level0) { auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); InnerBundleInfo info; bool ret = dataMgr->AddInnerBundleInfo("", info); EXPECT_FALSE(ret); @@ -634,7 +634,7 @@ HWTEST_F(BmsDataMgrTest, AddBundleInfo_0400, Function | SmallTest | Level0) info.SetBaseBundleInfo(bundleInfo); info.SetBaseApplicationInfo(applicationInfo); auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_SUCCESS); bool ret3 = dataMgr->AddInnerBundleInfo(BUNDLE_NAME, info); @@ -687,7 +687,7 @@ HWTEST_F(BmsDataMgrTest, AddBundleInfo_0500, Function | SmallTest | Level0) InnerBundleInfo info3; InnerBundleInfo info4; auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_SUCCESS); bool ret3 = dataMgr->AddInnerBundleInfo(BUNDLE_NAME, info1); @@ -734,7 +734,7 @@ HWTEST_F(BmsDataMgrTest, GenerateUidAndGid_0100, Function | SmallTest | Level0) info.SetBaseApplicationInfo(applicationInfo); info.SetAppType(Constants::AppType::SYSTEM_APP); auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_SUCCESS); bool ret3 = dataMgr->AddInnerBundleInfo(BUNDLE_NAME, info); @@ -767,7 +767,7 @@ HWTEST_F(BmsDataMgrTest, GenerateUidAndGid_0200, Function | SmallTest | Level0) info.SetBaseApplicationInfo(applicationInfo); info.SetAppType(Constants::AppType::THIRD_SYSTEM_APP); auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_SUCCESS); bool ret3 = dataMgr->AddInnerBundleInfo(BUNDLE_NAME, info); @@ -800,7 +800,7 @@ HWTEST_F(BmsDataMgrTest, GenerateUidAndGid_0300, Function | SmallTest | Level0) info.SetBaseApplicationInfo(applicationInfo); info.SetAppType(Constants::AppType::THIRD_PARTY_APP); auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_SUCCESS); bool ret3 = dataMgr->AddInnerBundleInfo(BUNDLE_NAME, info); @@ -836,7 +836,7 @@ HWTEST_F(BmsDataMgrTest, QueryAbilityInfo_0100, Function | SmallTest | Level0) info1.SetBaseApplicationInfo(applicationInfo1); info1.InsertAbilitiesInfo(BUNDLE_NAME + PACKAGE_NAME + ABILITY_NAME, abilityInfo); auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); EXPECT_TRUE(ret1); bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_SUCCESS); @@ -893,7 +893,7 @@ HWTEST_F(BmsDataMgrTest, QueryAbilityInfo_0200, Function | SmallTest | Level0) name.SetAbilityName(ABILITY_NAME); want.SetElement(name); auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); AbilityInfo abilityInfo; bool ret = dataMgr->QueryAbilityInfo(want, abilityInfo); EXPECT_FALSE(ret); @@ -937,7 +937,7 @@ HWTEST_F(BmsDataMgrTest, QueryAbilityInfo_0300, Function | SmallTest | Level0) want.SetElement(element1); auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); AbilityInfo abilityInfo; bool ret = dataMgr->QueryAbilityInfo(want, abilityInfo); EXPECT_FALSE(ret); @@ -961,7 +961,7 @@ HWTEST_F(BmsDataMgrTest, GetApplicationInfo_0100, Function | SmallTest | Level0) info1.SetBaseBundleInfo(bundleInfo1); info1.SetBaseApplicationInfo(applicationInfo1); auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_SUCCESS); bool ret3 = dataMgr->AddInnerBundleInfo(BUNDLE_NAME, info1); @@ -999,7 +999,7 @@ HWTEST_F(BmsDataMgrTest, GetApplicationInfo_0200, Function | SmallTest | Level0) EXPECT_EQ(appInfo.bundleName, appInfo2->bundleName); EXPECT_EQ(appInfo.deviceId, appInfo2->deviceId); auto dataMgr = GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); ApplicationInfo appInfo3; bool ret = dataMgr->GetApplicationInfo(BUNDLE_NAME, ApplicationFlag::GET_BASIC_APPLICATION_INFO, USERID, appInfo3); EXPECT_FALSE(ret); diff --git a/services/bundlemgr/test/unittest/bms_install_daemon_test/BUILD.gn b/services/bundlemgr/test/unittest/bms_install_daemon_test/BUILD.gn old mode 100644 new mode 100755 index f36436d032..977f83f9bc --- a/services/bundlemgr/test/unittest/bms_install_daemon_test/BUILD.gn +++ b/services/bundlemgr/test/unittest/bms_install_daemon_test/BUILD.gn @@ -20,7 +20,7 @@ module_output_path = "appexecfwk_standard/bundlemgrservice" ohos_unittest("BmsInstallDaemonTest") { module_out_path = module_output_path - + include_dirs = [ "//third_party/jsoncpp/include" ] sources = [ "${services_path}/bundlemgr/src/installd_death_recipient.cpp", "${services_path}/bundlemgr/test/mock/src/system_ability_helper.cpp", @@ -41,6 +41,7 @@ ohos_unittest("BmsInstallDaemonTest") { "${services_path}/bundlemgr:bundle_parser", "${services_path}/bundlemgr:parser_common", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", ] external_deps = [ diff --git a/services/bundlemgr/test/unittest/bms_install_daemon_test/bms_install_daemon_test.cpp b/services/bundlemgr/test/unittest/bms_install_daemon_test/bms_install_daemon_test.cpp index f644149bcd..b8c87eb818 100755 --- a/services/bundlemgr/test/unittest/bms_install_daemon_test/bms_install_daemon_test.cpp +++ b/services/bundlemgr/test/unittest/bms_install_daemon_test/bms_install_daemon_test.cpp @@ -74,13 +74,13 @@ void BmsInstallDaemonTest::SetUpTestCase() { if (access(ROOT_DIR.c_str(), F_OK) != 0) { bool result = OHOS::ForceCreateDirectory(ROOT_DIR); - ASSERT_TRUE(result) << "fail to create root dir"; + EXPECT_TRUE(result) << "fail to create root dir"; } if (chown(ROOT_DIR.c_str(), ROOT_UID, ROOT_UID) != 0) { - ASSERT_TRUE(false) << "fail to change root dir own ship"; + EXPECT_TRUE(false) << "fail to change root dir own ship"; } if (chmod(ROOT_DIR.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) { - ASSERT_TRUE(false) << "fail to change root dir mode"; + EXPECT_TRUE(false) << "fail to change root dir mode"; } } @@ -186,9 +186,9 @@ bool BmsInstallDaemonTest::CheckBundleDataDirExist() const HWTEST_F(BmsInstallDaemonTest, Startup_0100, Function | SmallTest | Level0) { std::shared_ptr installdService = std::make_shared(); - ASSERT_NE(installdService, nullptr); + EXPECT_NE(installdService, nullptr); bool ready = installdService->IsServiceReady(); - ASSERT_EQ(false, ready); + EXPECT_EQ(false, ready); installdService->Start(); ready = installdService->IsServiceReady(); EXPECT_EQ(true, ready); @@ -203,10 +203,10 @@ HWTEST_F(BmsInstallDaemonTest, Startup_0100, Function | SmallTest | Level0) HWTEST_F(BmsInstallDaemonTest, Startup_0200, Function | SmallTest | Level0) { std::shared_ptr installdService = std::make_shared(); - ASSERT_NE(installdService, nullptr); + EXPECT_NE(installdService, nullptr); installdService->Start(); bool ready = installdService->IsServiceReady(); - ASSERT_EQ(true, ready); + EXPECT_EQ(true, ready); installdService->Stop(); ready = installdService->IsServiceReady(); EXPECT_EQ(false, ready); @@ -221,13 +221,13 @@ HWTEST_F(BmsInstallDaemonTest, Startup_0200, Function | SmallTest | Level0) HWTEST_F(BmsInstallDaemonTest, Startup_0300, Function | SmallTest | Level0) { std::shared_ptr installdService = std::make_shared(); - ASSERT_NE(installdService, nullptr); + EXPECT_NE(installdService, nullptr); installdService->Start(); bool ready = installdService->IsServiceReady(); - ASSERT_EQ(true, ready); + EXPECT_EQ(true, ready); installdService->Stop(); ready = installdService->IsServiceReady(); - ASSERT_EQ(false, ready); + EXPECT_EQ(false, ready); installdService->Start(); ready = installdService->IsServiceReady(); EXPECT_EQ(true, ready); @@ -242,10 +242,10 @@ HWTEST_F(BmsInstallDaemonTest, Startup_0300, Function | SmallTest | Level0) HWTEST_F(BmsInstallDaemonTest, Startup_0400, Function | SmallTest | Level0) { std::shared_ptr installdService = std::make_shared(); - ASSERT_NE(installdService, nullptr); + EXPECT_NE(installdService, nullptr); installdService->Start(); bool ready = installdService->IsServiceReady(); - ASSERT_EQ(true, ready); + EXPECT_EQ(true, ready); installdService->Start(); ready = installdService->IsServiceReady(); EXPECT_EQ(true, ready); @@ -272,9 +272,9 @@ HWTEST_F(BmsInstallDaemonTest, Communication_0100, Function | SmallTest | Level0 HWTEST_F(BmsInstallDaemonTest, Communication_0200, Function | SmallTest | Level0) { std::shared_ptr installdService = std::make_shared(); - ASSERT_NE(installdService, nullptr); + EXPECT_NE(installdService, nullptr); bool ready = installdService->IsServiceReady(); - ASSERT_EQ(false, ready); + EXPECT_EQ(false, ready); InstalldClient::GetInstance()->ResetInstalldProxy(); int result = InstalldClient::GetInstance()->CreateBundleDir(BUNDLE_CODE_DIR); EXPECT_EQ(result, ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR); @@ -301,9 +301,9 @@ HWTEST_F(BmsInstallDaemonTest, Communication_0300, Function | SmallTest | Level0 HWTEST_F(BmsInstallDaemonTest, Communication_0400, Function | SmallTest | Level0) { std::shared_ptr installdService = std::make_shared(); - ASSERT_NE(installdService, nullptr); + EXPECT_NE(installdService, nullptr); bool ready = installdService->IsServiceReady(); - ASSERT_EQ(false, ready); + EXPECT_EQ(false, ready); InstalldClient::GetInstance()->ResetInstalldProxy(); int result = InstalldClient::GetInstance()->CreateBundleDataDir(BUNDLE_DATA_DIR, UID, GID); EXPECT_EQ(result, ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR); @@ -318,11 +318,11 @@ HWTEST_F(BmsInstallDaemonTest, Communication_0400, Function | SmallTest | Level0 HWTEST_F(BmsInstallDaemonTest, BundleDir_0100, Function | SmallTest | Level0) { int result = CreateBundleDir(BUNDLE_CODE_DIR); - ASSERT_EQ(result, 0); + EXPECT_EQ(result, 0); bool dirExist = CheckBundleDirExist(); - ASSERT_TRUE(dirExist); + EXPECT_TRUE(dirExist); int result1 = RemoveBundleDir(BUNDLE_CODE_DIR); - ASSERT_EQ(result1, 0); + EXPECT_EQ(result1, 0); dirExist = CheckBundleDirExist(); EXPECT_FALSE(dirExist); } @@ -336,7 +336,7 @@ HWTEST_F(BmsInstallDaemonTest, BundleDir_0100, Function | SmallTest | Level0) HWTEST_F(BmsInstallDaemonTest, BundleDir_0200, Function | SmallTest | Level0) { int result = CreateBundleDir(""); - ASSERT_EQ(result, ERR_APPEXECFWK_INSTALLD_PARAM_ERROR); + EXPECT_EQ(result, ERR_APPEXECFWK_INSTALLD_PARAM_ERROR); bool dirExist = CheckBundleDirExist(); EXPECT_FALSE(dirExist); } @@ -350,7 +350,7 @@ HWTEST_F(BmsInstallDaemonTest, BundleDir_0200, Function | SmallTest | Level0) HWTEST_F(BmsInstallDaemonTest, BundleDir_0300, Function | SmallTest | Level0) { int result1 = CreateBundleDir(SYSTEM_DIR); - ASSERT_EQ(result1, ERR_APPEXECFWK_INSTALLD_CREATE_DIR_FAILED); + EXPECT_EQ(result1, ERR_APPEXECFWK_INSTALLD_CREATE_DIR_FAILED); bool dirExist = CheckBundleDirExist(); EXPECT_FALSE(dirExist); } @@ -364,11 +364,11 @@ HWTEST_F(BmsInstallDaemonTest, BundleDir_0300, Function | SmallTest | Level0) HWTEST_F(BmsInstallDaemonTest, BundleDataDir_0100, Function | SmallTest | Level0) { int result = CreateBundleDataDir(BUNDLE_DATA_DIR, UID, GID); - ASSERT_EQ(result, 0); + EXPECT_EQ(result, 0); bool dirExist = CheckBundleDataDirExist(); - ASSERT_TRUE(dirExist); + EXPECT_TRUE(dirExist); int result1 = RemoveBundleDataDir(BUNDLE_DATA_DIR); - ASSERT_EQ(result1, 0); + EXPECT_EQ(result1, 0); dirExist = CheckBundleDataDirExist(); EXPECT_FALSE(dirExist); } @@ -382,11 +382,11 @@ HWTEST_F(BmsInstallDaemonTest, BundleDataDir_0100, Function | SmallTest | Level0 HWTEST_F(BmsInstallDaemonTest, BundleDataDir_0200, Function | SmallTest | Level0) { int result = CreateBundleDataDir(BUNDLE_DATA_DIR, UID, GID); - ASSERT_EQ(result, 0); + EXPECT_EQ(result, 0); bool dirExist = CheckBundleDataDirExist(); - ASSERT_TRUE(dirExist); + EXPECT_TRUE(dirExist); int result1 = CleanBundleDataDir(BUNDLE_DATA_DIR); - ASSERT_EQ(result1, 0); + EXPECT_EQ(result1, 0); dirExist = CheckBundleDataDirExist(); EXPECT_TRUE(dirExist); } @@ -400,7 +400,7 @@ HWTEST_F(BmsInstallDaemonTest, BundleDataDir_0200, Function | SmallTest | Level0 HWTEST_F(BmsInstallDaemonTest, BundleDataDir_0300, Function | SmallTest | Level0) { int result = CreateBundleDataDir("", UID, GID); - ASSERT_EQ(result, ERR_APPEXECFWK_INSTALLD_PARAM_ERROR); + EXPECT_EQ(result, ERR_APPEXECFWK_INSTALLD_PARAM_ERROR); bool dirExist = CheckBundleDataDirExist(); EXPECT_FALSE(dirExist); } @@ -414,7 +414,7 @@ HWTEST_F(BmsInstallDaemonTest, BundleDataDir_0300, Function | SmallTest | Level0 HWTEST_F(BmsInstallDaemonTest, BundleDataDir_0400, Function | SmallTest | Level0) { int result = CreateBundleDataDir(BUNDLE_DATA_DIR, -1, GID); - ASSERT_EQ(result, ERR_APPEXECFWK_INSTALLD_PARAM_ERROR); + EXPECT_EQ(result, ERR_APPEXECFWK_INSTALLD_PARAM_ERROR); bool dirExist = CheckBundleDataDirExist(); EXPECT_FALSE(dirExist); } @@ -428,7 +428,7 @@ HWTEST_F(BmsInstallDaemonTest, BundleDataDir_0400, Function | SmallTest | Level0 HWTEST_F(BmsInstallDaemonTest, BundleDataDir_0500, Function | SmallTest | Level0) { int result = CreateBundleDataDir(BUNDLE_DATA_DIR, UID, -1); - ASSERT_EQ(result, ERR_APPEXECFWK_INSTALLD_PARAM_ERROR); + EXPECT_EQ(result, ERR_APPEXECFWK_INSTALLD_PARAM_ERROR); bool dirExist = CheckBundleDataDirExist(); EXPECT_FALSE(dirExist); } @@ -442,7 +442,7 @@ HWTEST_F(BmsInstallDaemonTest, BundleDataDir_0500, Function | SmallTest | Level0 HWTEST_F(BmsInstallDaemonTest, BundleDataDir_0600, Function | SmallTest | Level0) { int result = CreateBundleDataDir(SYSTEM_DIR, UID, GID); - ASSERT_EQ(result, ERR_APPEXECFWK_INSTALLD_CREATE_DIR_FAILED); + EXPECT_EQ(result, ERR_APPEXECFWK_INSTALLD_CREATE_DIR_FAILED); bool dirExist = CheckBundleDataDirExist(); EXPECT_FALSE(dirExist); } @@ -457,10 +457,10 @@ HWTEST_F(BmsInstallDaemonTest, ExtractBundleFile_0100, Function | SmallTest | Le { CreateBundleDir(BUNDLE_CODE_DIR); bool dirExist = CheckBundleDirExist(); - ASSERT_TRUE(dirExist); + EXPECT_TRUE(dirExist); auto bundleFile = BUNDLE_FILE; int result = ExtractModuleFiles(bundleFile, TEMP_DIR); - ASSERT_EQ(result, 0); + EXPECT_EQ(result, 0); int result1 = RenameModuleDir(TEMP_DIR, MODULE_DIR); EXPECT_EQ(result1, 0); } @@ -475,7 +475,7 @@ HWTEST_F(BmsInstallDaemonTest, ExtractBundleFile_0200, Function | SmallTest | Le { CreateBundleDir(BUNDLE_CODE_DIR); bool dirExist = CheckBundleDirExist(); - ASSERT_TRUE(dirExist); + EXPECT_TRUE(dirExist); int result = ExtractModuleFiles("", TEMP_DIR); EXPECT_EQ(result, ERR_APPEXECFWK_INSTALLD_PARAM_ERROR); } @@ -490,7 +490,7 @@ HWTEST_F(BmsInstallDaemonTest, ExtractBundleFile_0300, Function | SmallTest | Le { CreateBundleDir(BUNDLE_CODE_DIR); bool dirExist = CheckBundleDirExist(); - ASSERT_TRUE(dirExist); + EXPECT_TRUE(dirExist); auto bundleFile = BUNDLE_FILE; int result = ExtractModuleFiles(bundleFile, ""); EXPECT_EQ(result, ERR_APPEXECFWK_INSTALLD_PARAM_ERROR); @@ -506,10 +506,10 @@ HWTEST_F(BmsInstallDaemonTest, ExtractBundleFile_0400, Function | SmallTest | Le { CreateBundleDir(BUNDLE_CODE_DIR); bool dirExist = CheckBundleDirExist(); - ASSERT_TRUE(dirExist); + EXPECT_TRUE(dirExist); auto bundleFile = BUNDLE_FILE; int result = ExtractModuleFiles(bundleFile, TEMP_DIR); - ASSERT_EQ(result, 0); + EXPECT_EQ(result, 0); int result1 = RenameModuleDir("", MODULE_DIR); EXPECT_EQ(result1, ERR_APPEXECFWK_INSTALLD_PARAM_ERROR); } @@ -524,10 +524,10 @@ HWTEST_F(BmsInstallDaemonTest, ExtractBundleFile_0500, Function | SmallTest | Le { CreateBundleDir(BUNDLE_CODE_DIR); bool dirExist = CheckBundleDirExist(); - ASSERT_TRUE(dirExist); + EXPECT_TRUE(dirExist); auto bundleFile = BUNDLE_FILE; int result = ExtractModuleFiles(bundleFile, TEMP_DIR); - ASSERT_EQ(result, 0); + EXPECT_EQ(result, 0); int result1 = RenameModuleDir(TEMP_DIR, ""); EXPECT_EQ(result1, ERR_APPEXECFWK_INSTALLD_PARAM_ERROR); } diff --git a/services/bundlemgr/test/unittest/bms_service_bundle_scan_test/BUILD.gn b/services/bundlemgr/test/unittest/bms_service_bundle_scan_test/BUILD.gn old mode 100644 new mode 100755 index df19802567..77e8ff494b --- a/services/bundlemgr/test/unittest/bms_service_bundle_scan_test/BUILD.gn +++ b/services/bundlemgr/test/unittest/bms_service_bundle_scan_test/BUILD.gn @@ -20,7 +20,7 @@ module_output_path = "appexecfwk_standard/bundlemgrservice" ohos_unittest("BmsServiceBundleScanTest") { module_out_path = module_output_path - + include_dirs = [ "//third_party/jsoncpp/include" ] sources = [ "${services_path}/bundlemgr/src/bundle_data_mgr.cpp", "${services_path}/bundlemgr/src/bundle_data_storage_database.cpp", @@ -29,6 +29,9 @@ ohos_unittest("BmsServiceBundleScanTest") { "${services_path}/bundlemgr/src/bundle_mgr_service_event_handler.cpp", "${services_path}/bundlemgr/src/bundle_scanner.cpp", "${services_path}/bundlemgr/src/bundle_status_callback_death_recipient.cpp", + "${services_path}/bundlemgr/src/kvstore_death_recipient_callback.cpp", + "${services_path}/bundlemgr/src/module_usage_data_storage.cpp", + "${services_path}/bundlemgr/src/permission_changed_death_recipient.cpp", ] sources += @@ -56,6 +59,7 @@ ohos_unittest("BmsServiceBundleScanTest") { "//foundation/distributeddatamgr/distributeddatamgr/interfaces/innerkits/distributeddata:distributeddata_inner", "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", ] deps += bundle_install_deps diff --git a/services/bundlemgr/test/unittest/bms_service_bundle_scan_test/bms_service_bundle_scan_test.cpp b/services/bundlemgr/test/unittest/bms_service_bundle_scan_test/bms_service_bundle_scan_test.cpp index 8abd6d4c9e..b7fbba7d28 100755 --- a/services/bundlemgr/test/unittest/bms_service_bundle_scan_test/bms_service_bundle_scan_test.cpp +++ b/services/bundlemgr/test/unittest/bms_service_bundle_scan_test/bms_service_bundle_scan_test.cpp @@ -110,27 +110,17 @@ void BmsServiceBundleScanTest::CreateFile(const std::string &path) const APP_LOGE("path too long"); return; } - std::string realPath; - realPath.reserve(PATH_MAX); - realPath.resize(PATH_MAX - 1); - - // if path not exist, realpath return nullptr && result put into buffer of second pointer - if (realpath(path.c_str(), &(realPath[0])) == nullptr) { - APP_LOGW("CreateFile-translate:%{public}s not exist path", realPath.c_str()); - } - mode_t mode = 0666; - int fd = open(realPath.c_str(), O_RDWR | O_CREAT, mode); + int fd = open(path.c_str(), O_RDWR | O_CREAT, mode); if (fd == -1) { - APP_LOGE("CreateFile-open:%{public}s error", realPath.c_str()); + APP_LOGE("CreateFile-open:%{public}s error", path.c_str()); return; } if (close(fd) != 0) { - APP_LOGW("CreateFile-close:%{public}s error", realPath.c_str()); + APP_LOGW("CreateFile-close:%{public}s error", path.c_str()); } - - if (access(realPath.c_str(), F_OK) != 0) { - APP_LOGE("CreateFile-checkFile:%{public}s not exist", realPath.c_str()); + if (access(path.c_str(), F_OK) != 0) { + APP_LOGE("CreateFile-checkFile:%{public}s not exist", path.c_str()); } } @@ -198,7 +188,7 @@ HWTEST_F(BmsServiceBundleScanTest, BundleScan_0300, Function | SmallTest | Level CreateFile(TEST_FILE_NAME_3); int number = static_cast(TriggerScan()); - ASSERT_EQ(3, number); + EXPECT_EQ(3, number); EXPECT_TRUE(IsScanResultContain(TEST_FILE_NAME_1)); EXPECT_TRUE(IsScanResultContain(TEST_FILE_NAME_2)); @@ -254,7 +244,7 @@ HWTEST_F(BmsServiceBundleScanTest, BundleScan_0500, Function | SmallTest | Level CreateFile(TEST_FILE_NAME_6); int number = static_cast(TriggerScan()); - ASSERT_EQ(3, number); + EXPECT_EQ(3, number); EXPECT_TRUE(IsScanResultContain(TEST_FILE_NAME_1)); EXPECT_TRUE(IsScanResultContain(TEST_FILE_NAME_2)); diff --git a/services/bundlemgr/test/unittest/bms_service_startup_test/BUILD.gn b/services/bundlemgr/test/unittest/bms_service_startup_test/BUILD.gn old mode 100644 new mode 100755 index f6486bdf03..9ac08d9de4 --- a/services/bundlemgr/test/unittest/bms_service_startup_test/BUILD.gn +++ b/services/bundlemgr/test/unittest/bms_service_startup_test/BUILD.gn @@ -20,7 +20,7 @@ module_output_path = "appexecfwk_standard/bundlemgrservice" ohos_unittest("BmsServiceStartupTest") { module_out_path = module_output_path - + include_dirs = [ "//third_party/jsoncpp/include" ] sources = [ "${services_path}/bundlemgr/src/bundle_data_mgr.cpp", "${services_path}/bundlemgr/src/bundle_data_storage_database.cpp", @@ -29,6 +29,9 @@ ohos_unittest("BmsServiceStartupTest") { "${services_path}/bundlemgr/src/bundle_mgr_service_event_handler.cpp", "${services_path}/bundlemgr/src/bundle_scanner.cpp", "${services_path}/bundlemgr/src/bundle_status_callback_death_recipient.cpp", + "${services_path}/bundlemgr/src/kvstore_death_recipient_callback.cpp", + "${services_path}/bundlemgr/src/module_usage_data_storage.cpp", + "${services_path}/bundlemgr/src/permission_changed_death_recipient.cpp", ] sources += @@ -56,6 +59,7 @@ ohos_unittest("BmsServiceStartupTest") { "//foundation/distributeddatamgr/distributeddatamgr/interfaces/innerkits/distributeddata:distributeddata_inner", "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", "//utils/native/base:utils", ] diff --git a/services/bundlemgr/test/unittest/bms_service_startup_test/bms_service_startup_test.cpp b/services/bundlemgr/test/unittest/bms_service_startup_test/bms_service_startup_test.cpp index 82311aceb2..5605132d41 100755 --- a/services/bundlemgr/test/unittest/bms_service_startup_test/bms_service_startup_test.cpp +++ b/services/bundlemgr/test/unittest/bms_service_startup_test/bms_service_startup_test.cpp @@ -55,7 +55,7 @@ HWTEST_F(BmsServiceStartupTest, Startup_0100, Function | SmallTest | Level0) { std::shared_ptr bms = DelayedSingleton::GetInstance(); bool ready = bms->IsServiceReady(); - ASSERT_EQ(false, ready); + EXPECT_EQ(false, ready); bms->OnStart(); ready = bms->IsServiceReady(); EXPECT_EQ(true, ready); @@ -72,7 +72,7 @@ HWTEST_F(BmsServiceStartupTest, Startup_0200,Function | SmallTest | Level0) std::shared_ptr bms = DelayedSingleton::GetInstance(); bms->OnStart(); bool ready = bms->IsServiceReady(); - ASSERT_EQ(true, ready); + EXPECT_EQ(true, ready); bms->OnStop(); ready = bms->IsServiceReady(); EXPECT_EQ(false, ready); @@ -89,10 +89,10 @@ HWTEST_F(BmsServiceStartupTest, Startup_0300,Function | SmallTest | Level0) std::shared_ptr bms = DelayedSingleton::GetInstance(); bms->OnStart(); bool ready = bms->IsServiceReady(); - ASSERT_EQ(true, ready); + EXPECT_EQ(true, ready); bms->OnStop(); ready = bms->IsServiceReady(); - ASSERT_EQ(false, ready); + EXPECT_EQ(false, ready); bms->OnStart(); ready = bms->IsServiceReady(); EXPECT_EQ(true, ready); @@ -109,7 +109,7 @@ HWTEST_F(BmsServiceStartupTest, Startup_0400,Function | SmallTest | Level0) std::shared_ptr bms = DelayedSingleton::GetInstance(); bms->OnStart(); bool ready = bms->IsServiceReady(); - ASSERT_EQ(true, ready); + EXPECT_EQ(true, ready); bms->OnStart(); ready = bms->IsServiceReady(); EXPECT_EQ(true, ready); diff --git a/services/formmgr/BUILD.gn b/services/formmgr/BUILD.gn new file mode 100644 index 0000000000..9036ae87b3 --- /dev/null +++ b/services/formmgr/BUILD.gn @@ -0,0 +1,111 @@ +# Copyright (c) 2021 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/appexecfwk/standard/appexecfwk.gni") + +config("formmgr_config") { + include_dirs = [ + "include", + "//third_party/json/include", + "//utils/system/safwk/native/include", + ] + cflags_cc = [ "-fexceptions" ] +} + +group("fms_target") { + deps = [ ":libfms" ] +} + +ohos_shared_library("libfms") { + include_dirs = [ + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler/include", + "//foundation/aafwk/standard/interfaces/innerkits/ability_manager/include", + "//base/security/permission/interfaces/innerkits/permission_standard/permissionsdk/main/cpp/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/bundlemgr", + + # "//third_party/libuuid", + ] + sources = [ + "src/form_ability_connection.cpp", + "src/form_acquire_connection.cpp", + "src/form_ams_helper.cpp", + "src/form_batch_delete_connection.cpp", + "src/form_bms_helper.cpp", + "src/form_cache_mgr.cpp", + "src/form_cast_temp_connection.cpp", + "src/form_data_mgr.cpp", + "src/form_db_cache.cpp", + "src/form_db_info.cpp", + "src/form_delete_connection.cpp", + "src/form_dump_mgr.cpp", + "src/form_event_notify_connection.cpp", + "src/form_host_callback.cpp", + "src/form_host_record.cpp", + "src/form_item_info.cpp", + "src/form_mgr_adapter.cpp", + "src/form_mgr_service.cpp", + "src/form_msg_event_connection.cpp", + "src/form_provider_mgr.cpp", + "src/form_refresh_connection.cpp", + "src/form_refresh_limiter.cpp", + "src/form_storage_mgr.cpp", + "src/form_supply_callback.cpp", + "src/form_sys_event_receiver.cpp", + "src/form_task_mgr.cpp", + "src/form_timer_mgr.cpp", + "src/form_util.cpp", + ] + + defines = [ + "APP_LOG_TAG = \"FormMgrService\"", + "LOG_DOMAIN = 0xD001120", + ] + + configs = [ + ":formmgr_config", + "//base/miscservices/time/services:time_service_config", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:formmgr_sdk_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/common:libappexecfwk_common", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${libs_path}/libeventhandler:libeventhandler_target", + "//base/powermgr/power_manager/interfaces/innerkits:powermgr_client", + "//base/security/permission/interfaces/innerkits/permission_standard/permissionsdk:libpermissionsdk_standard", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/distributedschedule/dmsfwk/interfaces/innerkits/uri:zuri", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//utils/native/base:utils", + + # "//third_party/libuuid:libuuid_static", + ] + + external_deps = [ + "ces_standard:cesfwk_core", + "ces_standard:cesfwk_innerkits", + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + "os_account_standard:libaccountkits", + ] + + subsystem_name = "appexecfwk" + part_name = "appexecfwk_standard" +} diff --git a/services/formmgr/include/form_ability_connection.h b/services/formmgr/include/form_ability_connection.h new file mode 100644 index 0000000000..8794c9ffa7 --- /dev/null +++ b/services/formmgr/include/form_ability_connection.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_ABILITY_CONNECTION_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_ABILITY_CONNECTION_H + +#include "event_handler.h" +#include "form_item_info.h" +#include "provider_connect_stub.h" +#include "want.h" + +namespace OHOS { +namespace AppExecFwk { +using WantParams = OHOS::AAFwk::WantParams; + +/** + * @class FormAbilityConnection + * Form Ability Connection Stub. + */ +class FormAbilityConnection : public ProviderConnectStub { +public: + FormAbilityConnection() = default; + virtual ~FormAbilityConnection() = default; + + /** + * @brief OnAbilityConnectDone, AbilityMs notify caller ability the result of connect. + * @param element service ability's ElementName. + * @param remoteObject the session proxy of service ability. + * @param resultCode ERR_OK on success, others on failure. + */ + virtual void OnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) override; + + /** + * @brief OnAbilityDisconnectDone, AbilityMs notify caller ability the result of disconnect. + * @param element service ability's ElementName. + * @param resultCode ERR_OK on success, others on failure. + */ + virtual void OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode) override; + + /** + * @brief remote object died event. + * @param remoteObject the remote object of service ability. + */ + void OnConnectDied(const wptr &remoteObject); + + /** + * @brief Get connectId. + * @return The ability connection id. + */ + long GetConnectId(); + + /** + * @brief Set connectId. + * @param connectId The ability connection id. + */ + void SetConnectId(long connectId); + + // std::string GetProviderKey(); + +private: + int64_t formId_; + std::string deviceId_; + std::string bundleName_; + std::string abilityName_; + bool isFreeInstall_; + long connectId_ = 0; + + DISALLOW_COPY_AND_MOVE(FormAbilityConnection); +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_ABILITY_CONNECTION_H \ No newline at end of file diff --git a/services/formmgr/include/form_acquire_connection.h b/services/formmgr/include/form_acquire_connection.h new file mode 100644 index 0000000000..8f680067d3 --- /dev/null +++ b/services/formmgr/include/form_acquire_connection.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_ACQUIRE_CONNECTION_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_ACQUIRE_CONNECTION_H + +#include "event_handler.h" +#include "form_ability_connection.h" +#include "form_item_info.h" +#include "want.h" + +namespace OHOS { +namespace AppExecFwk { +using WantParams = OHOS::AAFwk::WantParams; + +/** + * @class FormAcquireConnection + * Form Acquire Connection Stub. + */ +class FormAcquireConnection : public FormAbilityConnection { +public: + FormAcquireConnection(const int64_t formId, const FormItemInfo &info, const WantParams &wantParams); + virtual ~FormAcquireConnection() = default; + + /** + * @brief OnAbilityConnectDone, AbilityMs notify caller ability the result of connect. + * @param element service ability's ElementName. + * @param remoteObject the session proxy of service ability. + * @param resultCode ERR_OK on success, others on failure. + */ + void OnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) override; + +private: + int64_t formId_; + FormItemInfo info_; + WantParams wantParams_; + + DISALLOW_COPY_AND_MOVE(FormAcquireConnection); +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_ACQUIRE_CONNECTION_H \ No newline at end of file diff --git a/services/formmgr/include/form_ams_helper.h b/services/formmgr/include/form_ams_helper.h new file mode 100644 index 0000000000..1d554279be --- /dev/null +++ b/services/formmgr/include/form_ams_helper.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_AMS_HELPER_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_AMS_HELPER_H + +#include +#include +#include "ability_connect_callback_interface.h" +#include "ability_manager_interface.h" +#include "iremote_object.h" +#include "uri.h" + +namespace OHOS { +namespace AppExecFwk { +using IAbilityConnection = OHOS::AAFwk::IAbilityConnection; +using IAbilityManager = OHOS::AAFwk::IAbilityManager; +using Want = OHOS::AAFwk::Want; +/** + * @class FormAmsHelper + * Ams helpler. + */ +class FormAmsHelper final : public DelayedRefSingleton { + DECLARE_DELAYED_REF_SINGLETON(FormAmsHelper) +public: + DISALLOW_COPY_AND_MOVE(FormAmsHelper); + + /** + * @brief acquire a form ability manager if it not existed, + * @return returns the ability manager ipc object or nullptr for failed. + */ + sptr GetAbilityManager(); + /** + * @brief Connect session with service ability. + * @param want Special want for service type's ability. + * @param connect Callback used to notify caller the result of connecting or disconnecting. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode ConnectServiceAbility( + const Want &want, const sptr &connect); + /** + * @brief Disconnect session with service ability. + * @param want Special want for service type's ability. + * @param connect Callback used to notify caller the result of connecting or disconnecting. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode DisConnectServiceAbility(const sptr &connect); + /** + * @brief Add the ability manager instance for debug. + * @param abilityManager the ability manager ipc object. + */ + void SetAbilityManager(const sptr &abilityManager); +private: + sptr abilityManager_ = nullptr; +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_AMS_HELPER_H diff --git a/services/formmgr/include/form_batch_delete_connection.h b/services/formmgr/include/form_batch_delete_connection.h new file mode 100644 index 0000000000..93dcf7cda9 --- /dev/null +++ b/services/formmgr/include/form_batch_delete_connection.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_BATCH_DELETE_CONNECTION_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_BATCH_DELETE_CONNECTION_H + +#include + +#include "event_handler.h" +#include "form_ability_connection.h" +#include "want.h" + +namespace OHOS { +namespace AppExecFwk { +using WantParams = OHOS::AAFwk::WantParams; + +/** + * @class FormBatchDeleteConnection + * Form batch delete connection stub. + */ +class FormBatchDeleteConnection : public FormAbilityConnection { +public: + FormBatchDeleteConnection(const std::set &formIds); + virtual ~FormBatchDeleteConnection() = default; + + /** + * @brief OnAbilityConnectDone, AbilityMs notify caller ability the result of connect. + * @param element service ability's ElementName. + * @param remoteObject the session proxy of service ability. + * @param resultCode ERR_OK on success, others on failure. + */ + void OnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) override; + +private: + std::set formIds_; + + DISALLOW_COPY_AND_MOVE(FormBatchDeleteConnection); +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_BATCH_DELETE_CONNECTION_H \ No newline at end of file diff --git a/services/formmgr/include/form_bms_helper.h b/services/formmgr/include/form_bms_helper.h new file mode 100644 index 0000000000..8d377a1826 --- /dev/null +++ b/services/formmgr/include/form_bms_helper.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_BMS_HELPER_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_BMS_HELPER_H + +#include +#include "ability_connect_callback_interface.h" +#include "ability_manager_interface.h" +#include "bundle_info.h" +#include "bundle_mgr_interface.h" + +namespace OHOS { +namespace AppExecFwk { +using IAbilityConnection = OHOS::AAFwk::IAbilityConnection; +using IAbilityManager = OHOS::AAFwk::IAbilityManager; +using Want = OHOS::AAFwk::Want; + +/** + * @class FormBmsHelper + * Bms helpler. + */ +class FormBmsHelper final : public DelayedRefSingleton { + DECLARE_DELAYED_REF_SINGLETON(FormBmsHelper) + +public: + DISALLOW_COPY_AND_MOVE(FormBmsHelper); + + /** + * @brief Notify module removable. + * @param bundleName Provider ability bundleName. + * @param moduleName Provider ability moduleName. + */ + void NotifyModuleRemovable(const std::string &bundleName, const std::string &moduleName); + /** + * @brief Notify module not removable. + * @param bundleName Provider ability bundleName. + * @param moduleName Provider ability moduleName. + */ + void NotifyModuleNotRemovable(const std::string &bundleName, const std::string &moduleName) const; + + /** + * @brief Acquire a bundle manager, if it not existed, + * @return returns the bundle manager ipc object, or nullptr for failed. + */ + sptr GetBundleMgr(); + + /** + * @brief Add the bundle manager instance for debug. + * @param bundleManager the bundle manager ipc object. + */ + void SetBundleManager(const sptr &bundleManager); + +private: + /** + * @brief Generate module key. + * @param bundleName Provider ability bundleName. + * @param moduleName Provider ability moduleName. + * @return Module key. + */ + std::string GenerateModuleKey(const std::string &bundleName, const std::string &moduleName) const; + +private: + sptr iBundleMgr_ = nullptr; +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_BMS_HELPER_H diff --git a/services/formmgr/include/form_cache_mgr.h b/services/formmgr/include/form_cache_mgr.h new file mode 100644 index 0000000000..d6fb1803db --- /dev/null +++ b/services/formmgr/include/form_cache_mgr.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_CACHE_MGR_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_CACHE_MGR_H + +#include +#include +#include +#include +#include + +namespace OHOS { +namespace AppExecFwk { +/** + * @class FormCacheMgr + * Form cache data manager. + */ +class FormCacheMgr final : public DelayedRefSingleton { +DECLARE_DELAYED_REF_SINGLETON(FormCacheMgr) +public: + DISALLOW_COPY_AND_MOVE(FormCacheMgr); + + /** + * @brief Get form data. + * @param formId Form id. + * @param data Cache data. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool GetData(const int64_t formId, std::string &data) const; + + /** + * @brief Add form data. + * @param formId Form id. + * @param data Cache data. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool AddData(const int64_t formId, const std::string &data); + + /** + * @brief Delete form data. + * @param formId Form id. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool DeleteData(const int64_t formId); + + /** + * @brief update form data. + * @param formId Form id. + * @param data Cache data. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool UpdateData(const int64_t formId, const std::string &data); + /** + * @brief Check if form data is exist or not. + * @param formId, Form id. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool IsExist(const int64_t formId) const; +private: + mutable std::mutex cacheMutex_; + std::map cacheData_; +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_CACHE_MGR_H diff --git a/services/formmgr/include/form_cast_temp_connection.h b/services/formmgr/include/form_cast_temp_connection.h new file mode 100644 index 0000000000..d0892a7954 --- /dev/null +++ b/services/formmgr/include/form_cast_temp_connection.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_CAST_TEMP_CONNECTION_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_CAST_TEMP_CONNECTION_H + +#include "event_handler.h" +#include "form_ability_connection.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @class FormCastTempConnection + * Cast temp form Connection Stub. + */ +class FormCastTempConnection : public FormAbilityConnection { +public: + FormCastTempConnection(const int64_t formId); + virtual ~FormCastTempConnection() = default; + + /** + * @brief OnAbilityConnectDone, AbilityMs notify caller ability the result of connect. + * @param element service ability's ElementName. + * @param remoteObject the session proxy of service ability. + * @param resultCode ERR_OK on success, others on failure. + */ + void OnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) override; + +private: + int64_t formId_; + DISALLOW_COPY_AND_MOVE(FormCastTempConnection); +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_CAST_TEMP_CONNECTION_H \ No newline at end of file diff --git a/services/formmgr/include/form_data_mgr.h b/services/formmgr/include/form_data_mgr.h new file mode 100644 index 0000000000..d4eb6d02cb --- /dev/null +++ b/services/formmgr/include/form_data_mgr.h @@ -0,0 +1,412 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_DATA_MGR_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_DATA_MGR_H + +#include +#include +#include +#include +#include +#include + +#include "form_host_record.h" +#include "form_id_key.h" +#include "form_info.h" +#include "form_item_info.h" +#include "form_js_info.h" +#include "form_record.h" +#include "iremote_object.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @class FormDataMgr + * form data manager. + */ +class FormDataMgr final : public DelayedRefSingleton { +DECLARE_DELAYED_REF_SINGLETON(FormDataMgr) +public: + DISALLOW_COPY_AND_MOVE(FormDataMgr); + /** + * @brief Allot form info by item info. + * @param formId The Id of the form. + * @param formInfo Form item info. + * @param callingUid The UID of the proxy. + * @return Returns form record. + */ + FormRecord AllotFormRecord(const FormItemInfo &formInfo, const int callingUid); + /** + * @brief Create form js info by form record. + * @param formId The Id of the form. + * @param record Form record. + * @param formInfo Js info. + * @return None. + */ + void CreateFormInfo(const int64_t formId, const FormRecord &record, FormJsInfo &formInfo); + /** + * @brief Delete form js info by form record. + * @param formId The Id of the form. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool DeleteFormRecord(const int64_t formId); + /** + * @brief Clean removed forms for host. + * @param removedFormIds The id list of the forms. + */ + void CleanHostRemovedForms(const std::vector &removedFormIds); + /** + * @brief Delete form js info by form record. + * @return Returns all form records map. + */ + std::map &GetAllFormRecord(); + + /** + * @brief Get all form client host record. + * @return Returns all form client host record. + */ + std::vector &GetClientRecords(); + + /** + * @brief Get all form host records. + * @return Returns all form host records vector. + */ + std::vector &GetAllFormHostRecord(); + /** + * @brief Allot form host record by caller token. + * @param info The form item info. + * @param callerToken callerToken + * @param formId The Id of the form. + * @param callingUid The UID of the proxy. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool AllotFormHostRecord(const FormItemInfo &info, const sptr &callerToken, + const int64_t formId, const int callingUid); + /** + * @brief Check temp form count is max. + * @return Returns ERR_OK if the temp form not reached; returns ERR_MAX_SYSTEM_TEMP_FORMS is reached. + */ + int CheckTempEnoughForm() const; + /** + * @brief Check form count is max. + * @param callingUid The UID of the proxy. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + int CheckEnoughForm(const int callingUid) const; + /** + * @brief Delete temp form. + * @param formId The Id of the form. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool DeleteTempForm(const int64_t formId); + /** + * @brief Check temp form is exist. + * @param formId The Id of the form. + * @return Returns true if the temp form is exist; returns false is not exist. + */ + bool ExistTempForm(const int64_t formId) const; + /** + * @brief Modify form temp flag by formId. + * @param formId The Id of the form. + * @param formTempFlg The form temp flag. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool ModifyFormTempFlg(const int64_t formId, const bool formTempFlg); + /** + * @brief Add form user uid from form record. + * @param formId The Id of the form. + * @param formUserUid The form user uid. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool AddFormUserUid(const int64_t formId, const int32_t formUserUid); + /** + * @brief Delete form user uid from form record. + * @param formId The Id of the form. + * @param uid calling user id. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool DeleteFormUserUid(const int64_t formId, const int32_t uid); + /** + * @brief Update form record. + * @param formId The Id of the form. + * @param formRecord The form record. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool UpdateFormRecord(const int64_t formId, const FormRecord &formRecord); + /** + * @brief Get form record. + * @param formId The Id of the form. + * @param formRecord The form record. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool GetFormRecord(const int64_t formId, FormRecord &formRecord) const; + /** + * @brief Get form record. + * @param bundleName Bundle name. + * @param formInfos The form record list. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool GetFormRecord(const std::string &bundleName, std::vector &formInfos); + /** + * @brief Check form record is exist. + * @param formId The Id of the form. + * @return Returns true if the form record is exist; returns false is not exist. + */ + bool ExistFormRecord(const int64_t formId) const; + /** + * @brief Has form user uids in form record. + * @param formId The Id of the form. + * @return Returns true if this form has form user uids; returns false is not has. + */ + bool HasFormUserUids(const int64_t formId) const; + /** + * @brief Get form host record. + * @param formId The id of the form. + * @param formHostRecord The form host record. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool GetFormHostRecord(const int64_t formId, FormHostRecord &formHostRecord) const; + /** + * @brief Delete form host record. + * @param callerToken The client stub of the form host record. + * @param formId The id of the form. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool DeleteHostRecord(const sptr &callerToken, const int64_t formId); + /** + * @brief Handle form host died. + * @param remoteHost Form host proxy object. + */ + void HandleHostDied(const sptr &remoteHost); + /** + * @brief Refresh enable or not. + * @param formId The Id of the form. + * @return true on enbale, false on disable. + */ + bool IsEnableRefresh(int64_t formId); + /** + * @brief Check calling uid is valid. + * @param formUserUids The form user uids. + * @return Returns true if this user uid is valid; returns false otherwise. + */ + bool IsCallingUidValid(const std::vector &formUserUids) const; + /** + * @brief Generate udid. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool GenerateUdidHash(); + /** + * @brief Generate form id. + * @return form id. + */ + int64_t GenerateFormId(); + /** + * @brief Get udid. + * @return udid. + */ + int64_t GetUdidHash() const; + /** + * @brief Set udid. + * @param udidHash udid. + */ + void SetUdidHash(const int64_t udidHash); + + /** + * @brief Get the matched form host record by client stub. + * + * @param callerToken The client stub of the form host record. + * @param formHostRecord The form host record. + * @return Returns true if this function is successfully called, returns false otherwise. + */ + bool GetMatchedHostClient(const sptr &callerToken, FormHostRecord &formHostRecord) const; + + /** + * @brief Set needRefresh for FormRecord. + * @param formId The Id of the form. + * @param needRefresh true or false. + */ + void SetNeedRefresh(const int64_t formId, const bool needRefresh); + /** + * @brief Set isCountTimerRefresh for FormRecord. + * @param formId The Id of the form. + * @param countTimerRefresh true or false. + */ + void SetCountTimerRefresh(const int64_t formId, const bool countTimerRefresh); + /** + * @brief Get updated form info. + * @param record FormRecord. + * @param targetForms Target forms. + * @param updatedForm Updated form info. + * @return Returns true on success, false on failure. + */ + bool GetUpdatedForm(const FormRecord &record, const std::vector &targetForms, FormInfo &updatedForm); + /** + * @brief Set isEnableUpdate for FormRecord. + * @param formId The Id of the form. + * @param enableUpdate true or false. + */ + void SetEnableUpdate(const int64_t formId, const bool enableUpdate); + /** + * @brief Set update info for FormRecord. + * @param formId The Id of the form. + * @param enableUpdate true or false. + * @param updateDuration Update duration. + * @param updateAtHour Update at hour. + * @param updateAtMin Update at minute. + */ + void SetUpdateInfo(const int64_t formId, const bool enableUpdate, const long updateDuration, + const int updateAtHour, const int updateAtMin); + /** + * @brief Clean removed form records. + * @param bundleName BundleName. + * @param removedForms The id list of the forms. + */ + void CleanRemovedFormRecords(const std::string &bundleName, std::set &removedForms); + /** + * @brief Clean removed temp form records. + * @param bundleName BundleName. + * @param removedForms The id list of the forms. + */ + void CleanRemovedTempFormRecords(const std::string &bundleName, std::set &removedForms); + /** + * @brief Get recreate form records. + * @param reCreateForms The id list of the forms. + */ + void GetReCreateFormRecordsByBundleName(const std::string &bundleName, std::set &reCreateForms); + /** + * @brief Set form isInited = true. + * @param formId The Id of the form. + * @param isInited isInited property + */ + void SetFormCacheInited(const int64_t formId, const bool isInited); + /** + * @brief Set versionUpgrade. + * @param formId The Id of the form. + * @param versionUpgrade true or false + */ + void SetVersionUpgrade(const int64_t formId, const bool versionUpgrade); + /** + * @brief Update form for host clients. + * @param formId The Id of the form. + * @param needRefresh true or false + */ + void UpdateHostNeedRefresh(const int64_t formId, const bool needRefresh); + /** + * @brief Update form for host clients. + * @param formId The Id of the form. + * @param formRecord The form info. + * @return Returns true if form update, false if other. + */ + bool UpdateHostForm(const int64_t formId, const FormRecord &formRecord); + /** + * @brief handle update form flag. + * @param formIDs The id of the forms. + * @param callerToken Caller ability token. + * @param flag form flag. + * @param refreshForms Refresh forms + * @return Returns ERR_OK on success, others on failure. + */ + int32_t UpdateHostFormFlag(std::vector formIds, const sptr &callerToken, + const bool flag, std::vector &refreshForms); + /** + * @brief Find matched form id. + * @param formId The form id. + * @return Matched form id. + */ + int64_t FindMatchedFormId(const int64_t formId); + /** + * @brief Clear host data by uId. + * @param uId The caller uId. + */ + void ClearHostDataByUId(const int uId); + /** + * @brief Get no host temp forms. + * @param uid The caller uid. + * @param noHostTempFormsMap no host temp forms. + * @param foundFormsMap Form Id list. + */ + void GetNoHostTempForms(const int uid, std::map> &noHostTempFormsMap, + std::map &foundFormsMap); +private: + /** + * @brief Create form record. + * @param formInfo The form item info. + * @param callingUid The UID of the proxy. + * @return Form record. + */ + FormRecord CreateFormRecord(const FormItemInfo &formInfo, const int callingUid) const; + /** + * @brief Create host record. + * @param info The form item info. + * @param callerToken The UID of the proxy. + * @param callingUid The UID of the proxy. + * @param record The form host record. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool CreateHostRecord(const FormItemInfo &info, const sptr &callerToken, + const int callingUid, FormHostRecord &record); + /** + * @brief Parse update config. + * @param record The form record. + * @param info The form item info. + * @return None. + */ + void ParseUpdateConfig(FormRecord &record, const FormItemInfo &info) const; + /** + * @brief Parse update interval config. + * @param record The form record. + * @param configDuration interval duration. + */ + void ParseIntervalConfig(FormRecord &record, const int configDuration) const; + /** + * @brief Parse at time config. + * @param record The form record. + * @param info form item info. + */ + void ParseAtTimerConfig(FormRecord record, const FormItemInfo &info) const; + /** + * @brief Get the temp forms from host and delete temp form in cache. + * @param record The form record. + * @param recordTempForms Getted the temp forms. + */ + void HandleHostDiedForTempForms(const FormHostRecord &record, std::vector &recordTempForms); + /** + * @brief Check if two forms is same or not. + * @param record FormRecord. + * @param formInfo FormInfo. + * @return Returns true on success, false on failure. + */ + bool IsSameForm(const FormRecord &record, const FormInfo &formInfo); + /** + * @brief handle update form flag. + * @param formIDs The id of the forms. + * @param callerToken Caller ability token. + * @param flag form flag. + * @return Returns ERR_OK on success, others on failure. + */ + bool IsFormCached(const FormRecord record); +private: + mutable std::mutex formRecordMutex_; + mutable std::mutex formHostRecordMutex_; + mutable std::mutex formTempMutex_; + std::map formRecords_; + std::vector clientRecords_; + std::vector tempForms_; + int64_t udidHash_; +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_HOST_DATA_MGR_H diff --git a/services/formmgr/include/form_db_cache.h b/services/formmgr/include/form_db_cache.h new file mode 100644 index 0000000000..1be4e0fdd2 --- /dev/null +++ b/services/formmgr/include/form_db_cache.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_DB_CACHE_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_DB_CACHE_H + +#include +#include +#include + +#include "appexecfwk_errors.h" +#include "form_id_key.h" +#include "form_record.h" +#include "form_storage_mgr.h" + +namespace OHOS { +namespace AppExecFwk { +class FormDbCache final : public DelayedRefSingleton { +DECLARE_DELAYED_REF_SINGLETON(FormDbCache) +public: + DISALLOW_COPY_AND_MOVE(FormDbCache); + + /** + * @brief Load form data from DB to DbCache when starting. + * @return Void. + */ + void Start(); + + /** + * @brief Get all form data from DbCache. + * @param formDBInfos Storage all DbCache. + * @return Void + */ + void GetAllFormInfo(std::vector &formDBInfos); + + /** + * @brief Save or update form data to DbCache and DB. + * @param formDBInfo Form data. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode SaveFormInfo(const FormDBInfo &formDBInfo); + + /** + * @brief Save or update form data to DbCache and DB. + * @param formDBInfo Form data. + * @return Returns ERR_OK on success, others on failure.(NoLock) + */ + ErrCode SaveFormInfoNolock(const FormDBInfo &formDBInfo); + + /** + * @brief Delete form data in DbCache and DB with formId. + * @param formId form data Id. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode DeleteFormInfo(int64_t formId); + + /** + * @brief Get record from DB cache with formId + * @param formId Form data Id + * @param record Form data + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode GetDBRecord(const int64_t formId, FormRecord &record) const; + /** + * @brief Get record from DB cache with formId + * @param formId Form data Id + * @param record Form db data + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode GetDBRecord(const int64_t formId, FormDBInfo &record) const; + /** + * @brief Use record save or update DB data and DB cache with formId + * @param formId Form data Id + * @param record Form data + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode UpdateDBRecord(const int64_t formId, const FormRecord &record) const; + + /** + * @brief Delete form data in DbCache and DB with formId. + * @param formId form data Id. + * @param removedDBForms Removed db form infos + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode DeleteFormInfoByBundleName(const std::string &bundleName, std::vector &removedDBForms); + /** + * @brief Get no host db record. + * @param uid The caller uid. + * @param noHostFormDBList no host db record list. + * @param foundFormsMap Form Id list. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode GetNoHostDBForms(const int uid, std::map> &noHostFormDBList, + std::map &foundFormsMap); + /** + * @brief Get match count by bundleName and moduleName. + * @param bundleName BundleName. + * @param moduleName ModuleName. + * @return Returns match count. + */ + int GetMatchCount(const std::string &bundleName, const std::string &moduleName); +private: + std::unique_ptr dataStorage_; + mutable std::mutex formDBInfosMutex_; + std::vector formDBInfos_; +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_DB_CACHE_H diff --git a/services/formmgr/include/form_db_info.h b/services/formmgr/include/form_db_info.h new file mode 100644 index 0000000000..8e18aaddc8 --- /dev/null +++ b/services/formmgr/include/form_db_info.h @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_INNER_FORM_INFO_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_INNER_FORM_INFO_H + +#include + +#include "form_record.h" +#include "nlohmann/json.hpp" + +namespace OHOS { +namespace AppExecFwk { +struct FormDBInfo { + int64_t formId; + std::string formName; + std::string bundleName; + std::string moduleName; + std::string abilityName; + std::vector formUserUids; + + /** + * @brief Constructors + * + */ + FormDBInfo() + { + formId = -1; + } + /** + * @brief Constructors + * + */ + FormDBInfo(const FormDBInfo &formDBInfo) + { + formId = formDBInfo.formId; + formName = formDBInfo.formName; + bundleName = formDBInfo.bundleName; + moduleName = formDBInfo.moduleName; + abilityName = formDBInfo.abilityName; + formUserUids = formDBInfo.formUserUids; + } + /** + * @brief Constructors + * + */ + FormDBInfo(const int64_t formIdTmp, const FormRecord &formRecord) + { + formId = formIdTmp; + formName = formRecord.formName; + bundleName = formRecord.bundleName; + moduleName = formRecord.moduleName; + abilityName = formRecord.abilityName; + formUserUids = formRecord.formUserUids; + } + bool Contains(const int uId) const + { + return std::find(formUserUids.begin(), formUserUids.end(), uId) != formUserUids.end(); + } + void Remove(const int uId) + { + auto itUId = std::find(formUserUids.begin(), formUserUids.end(), uId); + if (itUId != formUserUids.end()) { + formUserUids.erase(itUId); + } + } + /** + * @brief overloaded == for Indicates the formDBInfo by formId + * @return Returns true if the data equal; returns false otherwise. + */ + bool operator== (const FormDBInfo &formDBInfo) const + { + return (this->formId == formDBInfo.formId); + } + /** + * @brief Compare two data + * @return Returns true if the data equal; returns false otherwise. + */ + bool Compare(const FormDBInfo &formDBInfo) const + { + if (formId != formDBInfo.formId) { + return false; + } + if (formName != formDBInfo.formName) { + return false; + } + if (bundleName != formDBInfo.bundleName) { + return false; + } + if (moduleName != formDBInfo.moduleName) { + return false; + } + if (abilityName != formDBInfo.abilityName) { + return false; + } + if (formUserUids != formDBInfo.formUserUids) { + return false; + } + + return true; + } +}; + +class InnerFormInfo { +public: + /** + * @brief Constructors + */ + InnerFormInfo() + { + formDBInfo_.formId = -1; + } + /** + * @brief Constructors + * + */ + InnerFormInfo(const FormDBInfo &formDBInfo) + { + formDBInfo_.formId = formDBInfo.formId; + formDBInfo_.formName = formDBInfo.formName; + formDBInfo_.bundleName = formDBInfo.bundleName; + formDBInfo_.moduleName = formDBInfo.moduleName; + formDBInfo_.abilityName = formDBInfo.abilityName; + formDBInfo_.formUserUids = formDBInfo.formUserUids; + } + /** + * @brief Constructors + * + */ + InnerFormInfo(const InnerFormInfo &innerFormInfo) + { + formDBInfo_.formId = innerFormInfo.formDBInfo_.formId; + formDBInfo_.formName = innerFormInfo.formDBInfo_.formName; + formDBInfo_.bundleName = innerFormInfo.formDBInfo_.bundleName; + formDBInfo_.moduleName = innerFormInfo.formDBInfo_.moduleName; + formDBInfo_.abilityName = innerFormInfo.formDBInfo_.abilityName; + formDBInfo_.formUserUids = innerFormInfo.formDBInfo_.formUserUids; + } + /** + * @brief Constructors + * + */ + InnerFormInfo(const int64_t formId, const FormRecord &formRecord) + { + formDBInfo_.formId = formId; + formDBInfo_.formName = formRecord.formName; + formDBInfo_.bundleName = formRecord.bundleName; + formDBInfo_.moduleName = formRecord.moduleName; + formDBInfo_.abilityName = formRecord.abilityName; + formDBInfo_.formUserUids = formRecord.formUserUids; + } + /** + * @brief Destructor + * + */ + virtual ~InnerFormInfo(){}; + /** + * @brief overloaded == for Indicates the formInfo by formId + * @return Returns true if the data equal; returns false otherwise. + */ + bool operator== (const InnerFormInfo &innerFormInfo) const + { + return (this->formDBInfo_.formId == innerFormInfo.formDBInfo_.formId); + } + + /** + * @brief Transform the InnerFormInfo object to json. + * @param jsonObject Indicates the obtained json object. + */ + void ToJson(nlohmann::json &jsonObject) const; + + /** + * @brief Transform the json object to InnerFormInfo object. + * @param jsonObject Indicates the obtained json object. + * @return Returns true on success, false on failure. + */ + bool FromJson(const nlohmann::json &jsonObject); + + /** + * @brief Get application form id. + * @return Returns the form id. + */ + int64_t GetFormId() const + { + return formDBInfo_.formId; + } + + /** + * @brief Set application form id. + * @param formId Indicates the form id to be set. + */ + void SetFormId(const int64_t formId) + { + formDBInfo_.formId = formId; + } + + /** + * @brief Get application form name. + * @return Returns the form name. + */ + std::string GetModuleName() const + { + return formDBInfo_.moduleName; + } + + /** + * @brief Set application form name. + * @param formName Indicates the form name to be set. + */ + void SetModuleName(const std::string &moduleName) + { + formDBInfo_.moduleName = moduleName; + } + + /** + * @brief Get application bundle name. + * @return Returns the bundle name. + */ + std::string GetBundleName() const + { + return formDBInfo_.bundleName; + } + + /** + * @brief Set application bundle name. + * @param bundleName Indicates the bundle name to be set. + */ + void SetBundleName(const std::string &bundleName) + { + formDBInfo_.bundleName = bundleName; + } + + /** + * @brief Get application ability name. + * @return Returns the ability name. + */ + std::string GetAbilityName() const + { + return formDBInfo_.abilityName; + } + + /** + * @brief Set application ability name. + * @param abilityName Indicates the ability name to be set. + */ + void SetAbilityName(const std::string &abilityName) + { + formDBInfo_.abilityName = abilityName; + } + + /** + * @brief Get application formName. + * @return Returns the formName. + */ + std::string GetFormName() const + { + return formDBInfo_.formName; + } + + /** + * @brief Set application formName. + * @param userId Indicates the formName to be set. + */ + void SetFormName(std::string formName) + { + formDBInfo_.formName = formName; + } + + /** + * @brief Get application user uids. + * @return Returns the user uids. + */ + std::vector GetUserUids() const + { + return formDBInfo_.formUserUids; + } + + /** + * @brief Set application user uids. + * @param userId Indicates the user uids to be set. + */ + void SetUserUids(const std::vector &formUserUids) + { + formDBInfo_.formUserUids.insert(formDBInfo_.formUserUids.end(), formUserUids.begin(), formUserUids.end()); + } + + /** + * @brief Set application formRecord + * @param formRecord Indicates the formRecord to be set. + */ + void SetFormDBInfo(const FormDBInfo &formDBInfo) + { + formDBInfo_ = formDBInfo; + } + + /** + * @brief Get application formRecord. + * @return Returns the formRecord + */ + FormDBInfo GetFormDBInfo() const + { + return formDBInfo_; + } + + void AddUserUid(const int callingUid); + bool DeleteUserUid(const int callingUid); + +private: + FormDBInfo formDBInfo_; +}; + +// void to_json(nlohmann::json &jsonObject, const FormDBInfo &info); +// void from_json(const nlohmann::json &jsonObject, FormDBInfo &info); +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_INNER_FORM_INFO_H diff --git a/services/formmgr/include/form_delete_connection.h b/services/formmgr/include/form_delete_connection.h new file mode 100644 index 0000000000..4da0e28406 --- /dev/null +++ b/services/formmgr/include/form_delete_connection.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_DELETE_CONNECTION_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_DELETE_CONNECTION_H + +#include "event_handler.h" +#include "form_ability_connection.h" + +namespace OHOS { +namespace AppExecFwk { + +/** + * @class FormDeleteConnection + * Form Delete Connection Stub. + */ +class FormDeleteConnection : public FormAbilityConnection { +public: + FormDeleteConnection(const int64_t formId); + virtual ~FormDeleteConnection() = default; + + /** + * @brief OnAbilityConnectDone, AbilityMs notify caller ability the result of connect. + * @param element service ability's ElementName. + * @param remoteObject the session proxy of service ability. + * @param resultCode ERR_OK on success, others on failure. + */ + void OnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) override; + +private: + int64_t formId_; + DISALLOW_COPY_AND_MOVE(FormDeleteConnection); +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_DELETE_CONNECTION_H \ No newline at end of file diff --git a/services/formmgr/include/form_dump_mgr.h b/services/formmgr/include/form_dump_mgr.h new file mode 100644 index 0000000000..0d35da6141 --- /dev/null +++ b/services/formmgr/include/form_dump_mgr.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_DUMP_MGR_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_DUMP_MGR_H + +#include + +#include "form_db_info.h" +#include "form_host_record.h" +#include "form_dump_mgr.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @class FormDumpMgr + * Form dump mgr. + */ +class FormDumpMgr final : public DelayedRefSingleton { + DECLARE_DELAYED_REF_SINGLETON(FormDumpMgr) +public: + DISALLOW_COPY_AND_MOVE(FormDumpMgr); + + /** + * @brief Dump all of form storage infos. + * @param storageInfos Form storage infos + * @param formInfos Form storage dump info. + */ + void DumpStorageFormInfos(const std::vector &storageInfos, std::string &formInfos) const; + /** + * @brief Dump form infos. + * @param formRecordInfos Form record infos. + * @param formInfos Form dump infos. + */ + void DumpFormInfos(const std::vector &formRecordInfos, std::string &formInfos) const; + /** + * @brief Dump form infos. + * @param formRecordInfo Form Host record info. + * @param formInfo Form dump info. + */ + void DumpFormHostInfo(const FormHostRecord &formHostRecord, std::string &formInfo) const; + /** + * @brief Dump form infos. + * @param formRecordInfo Form record info. + * @param formInfo Form dump info. + */ + void DumpFormInfo(const FormRecord &formRecordInfo, std::string &formInfo) const; +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_DUMP_MGR_H diff --git a/services/formmgr/include/form_event_notify_connection.h b/services/formmgr/include/form_event_notify_connection.h new file mode 100644 index 0000000000..f06043a118 --- /dev/null +++ b/services/formmgr/include/form_event_notify_connection.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_EVENT_NOTIFY_CONNECTION_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_EVENT_NOTIFY_CONNECTION_H + +#include "event_handler.h" +#include "form_ability_connection.h" +#include "want.h" + +namespace OHOS { +namespace AppExecFwk { +using Want = OHOS::AAFwk::Want; +/** + * @class FormEventNotifyConnection + * Form Event Notify Connection Stub. + */ +class FormEventNotifyConnection : public FormAbilityConnection { +public: + FormEventNotifyConnection(const std::vector formEvents, const int32_t formVisibleType); + virtual ~FormEventNotifyConnection() = default; + + /** + * @brief OnAbilityConnectDone, AbilityMs notify caller ability the result of connect. + * + * @param element service ability's ElementName. + * @param remoteObject the session proxy of service ability. + * @param resultCode ERR_OK on success, others on failure. + */ + void OnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) override; + +private: + std::vector formEvents_; + int32_t formVisibleType_; + DISALLOW_COPY_AND_MOVE(FormEventNotifyConnection); +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_EVENT_NOTIFY_CONNECTION_H \ No newline at end of file diff --git a/services/formmgr/include/form_host_callback.h b/services/formmgr/include/form_host_callback.h new file mode 100644 index 0000000000..fafe033c00 --- /dev/null +++ b/services/formmgr/include/form_host_callback.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORMMGR_FORM_HOST_CALLBACK_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORMMGR_FORM_HOST_CALLBACK_H + +#include + +#include "form_js_info.h" +#include "form_record.h" +#include "ipc_types.h" +#include "iremote_object.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @class FormHostCallback + * FormHost callback is used to call form host service. + */ +class FormHostCallback { +public: + FormHostCallback() = default; + virtual ~FormHostCallback() = default; + /** + * @brief Request to give back a Form. + * @param formId The Id of the forms to create. + * @param record Form info. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + void OnAcquired(const int64_t formId, const FormRecord &record, const sptr &callerToken); + + /** + * @brief Form is updated. + * @param formId The Id of the form to update. + * @param record Form info. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + void OnUpdate(const int64_t formId, const FormRecord &record, const sptr &callerToken); + + /** + * @brief Form provider is uninstalled. + * @param formIds The Id list of the forms. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + void OnUninstall(std::vector &formIds, const sptr &callerToken); +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORMMGR_FORM_HOST_CALLBACK_H diff --git a/services/formmgr/include/form_host_record.h b/services/formmgr/include/form_host_record.h new file mode 100644 index 0000000000..79e0869f7b --- /dev/null +++ b/services/formmgr/include/form_host_record.h @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_HOST_RECORD_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_HOST_RECORD_H + +#include +#include +#include +#include "app_log_wrapper.h" +#include "form_host_callback.h" +#include "form_item_info.h" +#include "form_record.h" +#include "iremote_object.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @class FormHostRecord + * Form host data. + */ +class FormHostRecord { +public: + /** + * @brief Create form host record. + * @param callback remote object. + * @param callingUid Calling uid. + */ + static FormHostRecord CreateRecord(const FormItemInfo &info, const sptr &callback, int callingUid); + /** + * @brief Add form id. + * @param formId The Id of the form. + */ + void AddForm(int64_t formId); + /** + * @brief Delete form id. + * @param formId The Id of the form. + */ + void DelForm(int64_t formId); + /** + * @brief forms_ is empty or not. + * @return forms_ is empty or not. + */ + bool IsEmpty() const; + /** + * @brief formId is in forms_ or not. + * @param formId The Id of the form. + * @return formId is in forms_ or not. + */ + bool Contains(int64_t formId) const; + + /** + * @brief Set refresh enable flag. + * @param formId The Id of the form. + * @param flag True for enbale, false for disable. + */ + void SetEnableRefresh(int64_t formId, bool flag); + + /** + * @brief Refresh enable or not. + * @param formId The Id of the form. + * @return true on enbale, false on disable.. + */ + bool IsEnableRefresh(int64_t formId) const; + + /** + * @brief Set need refresh enable flag. + * @param formId The Id of the form. + * @param flag True for enbale, false for disable. + */ + void SetNeedRefresh(int64_t formId, bool flag); + /** + * @brief Need Refresh enable or not. + * @param formId The Id of the form. + * @return true on enbale, false on disable.. + */ + bool IsNeedRefresh(int64_t formId) const; + + /** + * @brief Send form data to form host. + * @param id The Id of the form. + * @param record Form record. + */ + void OnAcquire(int64_t id, const FormRecord &record); + + /** + * @brief Update form data to form host. + * @param id The Id of the form. + * @param record Form record. + */ + void OnUpdate(int64_t id, const FormRecord &record); + /** + * Send form uninstall message to form host. + * + * @param id The Id of the form. + * @param record Form record. + */ + void OnFormUninstalled(std::vector &formIds); + + /** + * @brief Release resource. + * @param id The Id of the form. + * @param record Form record. + */ + void CleanResource(); + /** + * @brief Get callerUid_. + * @return callerUid_. + */ + int GetCallerUid() const + { + return callerUid_; + } + /** + * @brief Get clientStub_. + * @return clientStub_. + */ + sptr GetClientStub() const; + /** + * @brief Get deathRecipient_. + * @return deathRecipient_. + */ + sptr GetDeathRecipient() const; + /** + * @brief Set value of callerUid_. + * @param callerUid Caller uid. + */ + void SetCallerUid(const int callerUid); + /** + * @brief Set value of clientStub_. + * @param clientStub remote object. + */ + void SetClientStub(const sptr &clientStub); + /** + * @brief Set value of clientImpl_. + * @param clientImpl Form host callback object. + */ + void SetClientImpl(const std::shared_ptr &clientImpl); + /** + * @brief Set value of deathRecipient_. + * @param clientImpl DeathRecipient object. + */ + void SetDeathRecipient(const sptr &deathRecipient); + /** + * @brief Add deathRecipient object to clientStub_. + * @param deathRecipient DeathRecipient object. + */ + void AddDeathRecipient(const sptr& deathRecipient); + /** + * @brief Get hostBundleName_. + * @return hostBundleName_. + */ + std::string GetHostBundleName() const; + /** + * @brief Set hostBundleName_. + * @param hostBandleName Host bundle name. + */ + void SetHostBundleName(const std::string &hostBundleName); + +private: + int callerUid_; + sptr clientStub_ = nullptr; + std::shared_ptr clientImpl_ = nullptr; + sptr deathRecipient_ = nullptr; + std::unordered_map forms_; + std::unordered_map needRefresh_; + std::string hostBundleName_; + + /** + * @class ClientDeathRecipient + * notices IRemoteBroker died. + */ + class ClientDeathRecipient : public IRemoteObject::DeathRecipient { + public: + /** + * @brief Constructor + */ + ClientDeathRecipient() = default; + ~ClientDeathRecipient() = default; + /** + * @brief handle remote object died event. + * @param remote remote object. + */ + void OnRemoteDied(const wptr &remote) override; + }; +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_HOST_RECORD_H \ No newline at end of file diff --git a/services/formmgr/include/form_id_key.h b/services/formmgr/include/form_id_key.h new file mode 100644 index 0000000000..53da57e89f --- /dev/null +++ b/services/formmgr/include/form_id_key.h @@ -0,0 +1,68 @@ +/* +* Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_ID_KEY_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_ID_KEY_H + +#include + +namespace OHOS { +namespace AppExecFwk { +struct FormIdKey { +public: + + std::string bundleName; + std::string moduleName; + std::string abilityName; + std::string formName; + int specificationId; + int orientation; + + bool operator== (const FormIdKey &formIdKey) const + { + return specificationId == formIdKey.specificationId + && orientation == formIdKey.orientation + && bundleName == formIdKey.bundleName + && moduleName == formIdKey.moduleName + && abilityName == formIdKey.abilityName + && formName == formIdKey.formName; + } + /** + * @brief overloaded == for Indicates the formDBInfo by formId + * @return Returns true if the data equal; returns false otherwise. + */ + bool operator< (const FormIdKey &formIdKey) const + { + return specificationId != formIdKey.specificationId + || orientation != formIdKey.orientation + || bundleName != formIdKey.bundleName + || moduleName != formIdKey.moduleName + || abilityName != formIdKey.abilityName + || formName != formIdKey.formName; + } + int hashCode() + { + return std::hash()(bundleName) + + std::hash()(moduleName) + + std::hash()(abilityName) + + std::hash()(formName) + + std::hash()(specificationId) + + std::hash()(orientation); + } +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_ID_KEY_H diff --git a/services/formmgr/include/form_item_info.h b/services/formmgr/include/form_item_info.h new file mode 100644 index 0000000000..aa0a499ea0 --- /dev/null +++ b/services/formmgr/include/form_item_info.h @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_CONFIG_INFO_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_CONFIG_INFO_H + +#include +#include +#include +#include +#include "form_record.h" + +namespace OHOS { +namespace AppExecFwk { +class FormItemInfo { +public: + /** + * @brief Get formId_. + * @return formId_. + */ + int64_t GetFormId() const; + /** + * @brief Set value of formId_. + * @param formId Form Id. + */ + void SetFormId(int64_t formId); + /** + * @brief Get packageName_. + * @return packageName_. + */ + std::string GetPackageName() const; + /** + * @brief Set value of packageName_. + * @param packageName Package name. + */ + void SetPackageName(const std::string &packageName); + /** + * @brief Get providerBundleName_. + * @return providerBundleName_. + */ + std::string GetProviderBundleName() const; + /** + * @brief Set value of providerBundleName_. + * @param providerBundleName Provider bundle Name. + */ + void SetProviderBundleName(const std::string &providerBundleName_); + /** + * @brief Get hostBundleName_. + * @return hostBundleName_. + */ + std::string GetHostBundleName() const; + /** + * @brief Set value of hostBundleName_. + * @param hostBundleName_ Host bundle Name. + */ + void SetHostBundleName(const std::string &hostBundleName_); + /** + * @brief Get moduleName_. + * @return moduleName_. + */ + std::string GetModuleName() const; + /** + * @brief Set value of moduleName_. + * @param moduleName Module Name. + */ + void SetModuleName(const std::string &moduleName); + /** + * @brief Get abilityName_. + * @return abilityName_. + */ + std::string GetAbilityName() const; + /** + * @brief Set value of abilityName_. + * @param abilityName Ability name. + */ + void SetAbilityName(const std::string &abilityName); + /** + * @brief Get formName_. + * @return formName_. + */ + std::string GetFormName() const; + /** + * @brief Set value of formName_. + * @param formName Form name. + */ + void SetFormName(const std::string &formName); + /** + * @brief Get jsComponentName_. + * @return jsComponentName_. + */ + std::string GetJsComponentName() const; + /** + * @brief Set value of jsComponentName_. + * @param jsComponentName Js component name. + */ + void SetJsComponentName(const std::string &jsComponentName); + /** + * @brief Get abilityModuleName_. + * @return abilityModuleName_. + */ + std::string GetAbilityModuleName() const; + /** + * @brief Set value of abilityModuleName_. + * @param abilityModuleName ability module name_. + */ + void SetAbilityModuleName(const std::string &abilityModuleName); + /** + * @brief Get specificationId_. + * @return specificationId_. + */ + int GetSpecificationId() const; + /** + * @brief Set value of specificationId_. + * @param specificationId Specification id. + */ + void SetSpecificationId(const int specificationId); + + /** + * @brief Obtains the updageFlag. + * @return Returns updageFlag. + */ + bool IsEnableUpdateFlag() const; + /** + * @brief Set value of updateFlag_. + * @param IsEnableUpdateFlag Enable update flag or not. + */ + void SetEnableUpdateFlag(bool IsEnableUpdateFlag); + /** + * @brief Get updateDuration_. + * @return updateDuration_. + */ + int GetUpdateDuration() const; + /** + * @brief Set value of updateDuration_. + * @param updateDuration Update duration. + */ + void SetUpdateDuration(int updateDuration); + /** + * @brief Get scheduledUpdateTime_. + * @return scheduledUpdateTime_. + */ + std::string GetScheduledUpdateTime() const; + /** + * @brief Set value of scheduledUpdateTime_. + * @param scheduledUpdateTime Scheduled update time. + */ + void SetScheduledUpdateTime(const std::string &scheduledUpdateTime); + /** + * @brief Get hapSourceDirs_. + * @param dirs Hap source dirs. + * @return Returns true on success, false on failure. + */ + bool GetHapSourceDirs(std::vector &dirs) const; + /** + * @brief Add hap source dir. + * @param hapSourceDir Hap source dir. + */ + void AddHapSourceDirs(const std::string &hapSourceDir); + /** + * @brief Set value of hapSourceDirs_. + * @param hapSourceDirs Hap source dirs. + */ + void SetHapSourceDirs(const std::vector &hapSourceDirs); + /** + * @brief Obtains the temporaryFlag. + * @return Returns temporaryFlag. + */ + bool IsTemporaryForm() const; + /** + * @brief Set value of temporaryFlag_. + * @param temporaryFlag Temporary flag. + */ + void SetTemporaryFlag(bool temporaryFlag); + /** + * @brief Obtains the hap source by ability module name. + * @param moduleName ability module name + * @return Returns hap source. + */ + std::string GetHapSourceByModuleName(const std::string &moduleName) const; + /** + * @brief Add module info. + * @param moduleName Module name. + * @param moduleSourceDir Module source dir. + */ + void AddModuleInfo(const std::string &moduleName, const std::string &moduleSourceDir); + /** + * @brief Check if item valid or not. + * @return Valid or not + */ + bool IsValidItem() const; + /** + * @brief Check if item match or not. + * @return Match or not + */ + bool IsMatch(const FormRecord &record) const; + /** + * @brief Check if form config same or not. + * @return Same or not + */ + bool IsSameFormConfig(const FormRecord &record) const; + /** + * @brief Check if visible notify or not. + * @return visible notify or not + */ + bool IsFormVisibleNotify() const; + /** + * @brief Set value of formVisibleNotify_. + * @param isFormVisibleNotify visible notify or not. + */ + void SetFormVisibleNotify(bool isFormVisibleNotify); +private: + /** + * @brief Equal or not. + * @param left left string. + * @param right right string. + * @return Equal or not + */ + bool IsEqual(const std::string &left, const std::string &right); + +private: + int64_t formId_ = -1; + std::string packageName_; + std::string providerBundleName_; + std::string hostBundleName_; + std::string moduleName_; + std::string abilityName_; + std::string formName_; + int32_t specificationId_; + bool updateFlag_; + int32_t updateDuration_; + std::string scheduledUpdateTime_; + std::vector hapSourceDirs_; + bool temporaryFlag_; + bool formVisibleNotify_; + + std::string jsComponentName_; + std::string abilityModuleName_; + std::unordered_map moduleInfoMap_; +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_CONFIG_INFO_H diff --git a/services/formmgr/include/form_mgr_adapter.h b/services/formmgr/include/form_mgr_adapter.h new file mode 100644 index 0000000000..b795fb900f --- /dev/null +++ b/services/formmgr/include/form_mgr_adapter.h @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_MGR_ADAPTER_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_MGR_ADAPTER_H + +#include + +#include "bundle_info.h" +#include "bundle_mgr_interface.h" +#include "form_info.h" +#include "form_host_record.h" +#include "form_item_info.h" +#include "form_js_info.h" +#include "form_provider_data.h" +#include "form_db_info.h" +#include "ipc_types.h" +#include "iremote_object.h" +#include "want.h" + +namespace OHOS { +namespace AppExecFwk { +using Want = OHOS::AAFwk::Want; +using WantParams = OHOS::AAFwk::WantParams; +/** + * @class FormMgrAdapter + * Form request handler from form host. + */ +class FormMgrAdapter { +public: + FormMgrAdapter(){}; + virtual ~FormMgrAdapter(){}; + + /** + * @brief Add form with want, send want to form manager service. + * @param formId The Id of the forms to add. + * @param want The want of the form to add. + * @param callerToken Caller ability token. + * @param formInfo Form info. + * @return Returns ERR_OK on success, others on failure. + */ + int AddForm(const int64_t formId, const Want &want, const sptr &callerToken, FormJsInfo &formInfo); + + /** + * @brief Delete forms with formIds, send formIds to form manager service. + * @param formId The Id of the forms to delete. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + int DeleteForm(const int64_t formId, const sptr &callerToken); + + /** + * @brief Release forms with formIds, send formIds to form Mgr service. + * @param formId The Id of the forms to release. + * @param callerToken Caller ability token. + * @param delCache Delete Cache or not. + * @return Returns ERR_OK on success, others on failure. + */ + int ReleaseForm(const int64_t formId, const sptr &callerToken, const bool delCache); + + /** + * @brief Update form with formId, send formId to form manager service. + * @param formId The Id of the form to update. + * @param bundleName Provider ability bundleName. + * @param formProviderData form provider data. + * @return Returns ERR_OK on success, others on failure. + */ + int UpdateForm(const int64_t formId, const std::string &bundleName, const FormProviderData &formProviderData); + + /** + * @brief Request form with formId and want, send formId and want to form manager service. + * + * @param formId The Id of the form to update. + * @param callerToken Caller ability token. + * @param want The want of the form to request. + * @return Returns ERR_OK on success, others on failure. + */ + int RequestForm(const int64_t formId, const sptr &callerToken, const Want &want); + + /** + * @brief Form visible/invisible notify, send formIds to form manager service. + * + * @param formIds The vector of form Ids. + * @param callerToken Caller ability token. + * @param formVisibleType The form visible type, including FORM_VISIBLE and FORM_INVISIBLE. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode NotifyWhetherVisibleForms(const std::vector &formIds, const sptr &callerToken, + const int32_t formVisibleType); + + /** + * @brief temp form to normal form. + * @param formId The Id of the form. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + int CastTempForm(const int64_t formId, const sptr &callerToken); + + /** + * @brief Dump all of form storage infos. + * @param formInfos All of form storage infos. + * @return Returns ERR_OK on success, others on failure. + */ + int DumpStorageFormInfos(std::string &formInfos) const; + /** + * @brief Dump form info by a bundle name. + * @param bundleName The bundle name of form provider. + * @param formInfos Form infos. + * @return Returns ERR_OK on success, others on failure. + */ + int DumpFormInfoByBundleName(const std::string &bundleName, std::string &formInfos) const; + /** + * @brief Dump form info by a bundle name. + * @param formId The id of the form. + * @param formInfo Form info. + * @return Returns ERR_OK on success, others on failure. + */ + int DumpFormInfoByFormId(const std::int64_t formId, std::string &formInfo) const; + + /** + * @brief set next refresh time. + * @param formId The id of the form. + * @param nextTime next refresh time. + * @return Returns ERR_OK on success, others on failure. + */ + int SetNextRefreshTime(const int64_t formId, const int64_t nextTime); + + /** + * @brief enable update form. + * @param formIDs The id of the forms. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + int EnableUpdateForm(const std::vector formIDs, const sptr &callerToken); + + /** + * @brief disable update form. + * @param formIDs The id of the forms. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + int DisableUpdateForm(const std::vector formIDs, const sptr &callerToken); + + /** + * @brief Process js message event. + * @param formId Indicates the unique id of form. + * @param want information passed to supplier. + * @param callerToken Caller ability token. + * @return Returns true if execute success, false otherwise. + */ + int MessageEvent(const int64_t formId, const Want &want, const sptr &callerToken); +private: + /** + * @brief Get form configure info. + * @param want The want of the request. + * @param formItemInfo Form configure info. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode GetFormConfigInfo(const Want& want, FormItemInfo &formItemInfo); + /** + * @brief Get bundle info. + * @param want The want of the request. + * @param bundleInfo Bundle info. + * @param packageName Package name. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode GetBundleInfo(const AAFwk::Want &want, BundleInfo &bundleInfo, std::string &packageName); + /** + * @brief Get form info. + * @param want The want of the request. + * @param formInfo Form info. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode GetFormInfo(const AAFwk::Want &want, FormInfo &formInfo); + /** + * @brief Get form configure info. + * @param want The want of the request. + * @param bundleInfo Bundle info. + * @param formInfo Form info. + * @param formItemInfo Form configure info. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode GetFormItemInfo(const AAFwk::Want &want, const BundleInfo &bundleInfo, const FormInfo &formInfo, + FormItemInfo &formItemInfo); + /** + * @brief Dimension valid check. + * @param formInfo Form info. + * @param dimensionId Dimension id. + * @return Returns true on success, false on failure. + */ + bool IsDimensionValid(const FormInfo &formInfo, int dimensionId) const; + /** + * @brief Create form configure info. + * @param bundleInfo Bundle info. + * @param formInfo Form info. + * @param itemInfo Form configure info. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode CreateFormItemInfo(const BundleInfo& bundleInfo, const FormInfo& formInfo, FormItemInfo& itemInfo); + /** + * @brief Allocate form by formId. + * @param info Form configure info. + * @param callerToken Caller ability token. + * @param wantParams WantParams of the request. + * @param formInfo Form info for form host. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode AllotFormById(const FormItemInfo &info, const sptr &callerToken, + const WantParams &wantParams, FormJsInfo &formInfo); + /** + * @brief Allocate form by form configure info. + * @param info Form configure info. + * @param callerToken Caller ability token. + * @param wantParams WantParams of the request. + * @param formInfo Form info for form host. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode AllotFormByInfo(const FormItemInfo &info, const sptr &callerToken, + const WantParams& wantParams, FormJsInfo &formInfo); + /** + * @brief Acquire form data from form provider. + * @param formId The Id of the form.. + * @param info Form configure info. + * @param wantParams WantParams of the request. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode AcquireProviderFormInfoAsync(const int64_t formId, const FormItemInfo &info, const WantParams &wantParams); + + /** + * @brief Handle release form. + * @param formId The form id. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode HandleReleaseForm(const int64_t formId, const sptr &callerToken); + + /** + * @brief Handle delete form. + * @param formId The form id. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode HandleDeleteForm(const int64_t formId, const sptr &callerToken); + + /** + * @brief Handle delete temp form. + * @param formId The form id. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode HandleDeleteTempForm(const int64_t formId, const sptr &callerToken); + + /** + * @brief Handle delete form storage. + * @param dbRecord Form storage information. + * @param uid calling user id. + * @param formId The form id. + * @return Function result and has other host flag. + */ + ErrCode HandleDeleteFormCache(FormRecord &dbRecord, const int uid, const int64_t formId); + + /** + * @brief Padding udid hash. + * @param formId The form id. + * @return Padded form id. + */ + int64_t PaddingUDIDHash(const int64_t formId) const; + + /** + * @brief Add existed form record. + * @param info Form configure info. + * @param callerToken Caller ability token. + * @param record Form data. + * @param formId The form id. + * @param wantParams WantParams of the request. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode AddExistFormRecord(const FormItemInfo &info, const sptr &callerToken, + const FormRecord &record, const int64_t formId, const WantParams &wantParams); + + /** + * @brief Add new form record. + * @param info Form configure info. + * @param formId The form id. + * @param callerToken Caller ability token. + * @param wantParams WantParams of the request. + * @param formInfo Form info for form host. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode AddNewFormRecord(const FormItemInfo &info, const int64_t formId, + const sptr &callerToken, const WantParams &wantParams, FormJsInfo &formInfo); + + /** + * @brief Send event notify to form provider. The event notify type include FORM_VISIBLE and FORM_INVISIBLE. + * + * @param providerKey The provider key string which consists of the provider bundle name and ability name. + * @param formIdsByProvider The map of form Ids and their event type which have the same provider. + * @param formVisibleType The form visible type, including FORM_VISIBLE and FORM_INVISIBLE. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode HandleEventNotify(const std::string &providerKey, const std::vector &formIdsByProvider, + const int32_t formVisibleType); + + /** + * @brief Increase the timer refresh count. + * + * @param formId The form id. + * @return none. + */ + void IncreaseTimerRefreshCount(const int64_t formId); + + /** + * @brief handle update form flag. + * @param formIDs The id of the forms. + * @param callerToken Caller ability token. + * @param flag form flag. + * @return Returns ERR_OK on success, others on failure. + */ + int HandleUpdateFormFlag(const std::vector formIds, + const sptr &callerToken, const bool flag); + + /** + * @brief handle update form flag. + * @param formIDs The id of the forms. + * @param callerToken Caller ability token. + * @param flag form flag. + * @return Returns ERR_OK on success, others on failure. + */ + bool IsFormCached(const FormRecord record); + + /** + * @brief set next refresht time locked. + * @param formId The form's id. + * @param nextTime next refresh time. + * @return Returns ERR_OK on success, others on failure. + */ + int SetNextRefreshtTimeLocked(const int64_t formId, const int64_t nextTime); + + /** + * @brief set next refresht time locked. + * @param formId The form's id. + * @param bundleName Provider ability bundleName. + * @return Returns true or false. + */ + bool IsUpdateValid(const int64_t formId, const std::string &bundleName); + /** + * @brief Handle cast temp form. + * @param formId The form id. + * @param record Form information. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode HandleCastTempForm(const int64_t formId, const FormRecord &record); + + /** + * @brief Add form timer. + * @param formRecord Form information. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode AddFormTimer(const FormRecord &formRecord); + + /** + * @brief get bundleName. + * @param bundleName for output. + * @return Returns true on success, others on failure. + */ + bool GetBundleName(std::string &bundleName); +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_MGR_ADAPTER_H diff --git a/services/formmgr/include/form_mgr_service.h b/services/formmgr/include/form_mgr_service.h new file mode 100644 index 0000000000..a2cd4970a0 --- /dev/null +++ b/services/formmgr/include/form_mgr_service.h @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_MGR_SERVICE_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_MGR_SERVICE_H + +#include +#include +#include +#include +#include +#include + +#include "event_handler.h" +#include "form_mgr_adapter.h" +#include "form_mgr_stub.h" +#include "form_provider_data.h" +#include "iremote_object.h" + +namespace OHOS { +namespace AppExecFwk { +enum class ServiceRunningState { STATE_NOT_START, STATE_RUNNING }; +/** + * @class FormMgrService + * FormMgrService provides a facility for managing form life cycle. + */ +class FormMgrService : public SystemAbility, + public FormMgrStub, + public std::enable_shared_from_this { + DECLARE_DELAYED_SINGLETON(FormMgrService); + DECLEAR_SYSTEM_ABILITY(FormMgrService); +public: + /** + * @brief Start envent for the form manager service. + */ + void OnStart() override; + /** + * @brief Stop envent for the form manager service. + */ + void OnStop() override; + + /** + * @brief Add form with want, send want to form manager service. + * @param formId The Id of the forms to add. + * @param want The want of the form to add. + * @param callerToken Caller ability token. + * @param formInfo Form info. + * @return Returns ERR_OK on success, others on failure. + */ + int AddForm(const int64_t formId, const Want &want, const sptr &callerToken, + FormJsInfo &formInfo) override; + + /** + * @brief Delete forms with formIds, send formIds to form manager service. + * @param formId The Id of the forms to delete. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + int DeleteForm(const int64_t formId, const sptr &callerToken) override; + + /** + * @brief Release forms with formIds, send formIds to form manager service. + * @param formId The Id of the forms to release. + * @param callerToken Caller ability token. + * @param delCache Delete Cache or not. + * @return Returns ERR_OK on success, others on failure. + */ + int ReleaseForm(const int64_t formId, const sptr &callerToken, const bool delCache) override; + + /** + * @brief Update form with formId, send formId to form manager service. + * @param formId The Id of the form to update. + * @param bundleName Provider ability bundleName. + * @param FormProviderData Form binding data. + * @return Returns ERR_OK on success, others on failure. + */ + int UpdateForm(const int64_t formId, const std::string &bundleName, + const FormProviderData &FormProviderData) override; + + /** + * @brief set next refresh time. + * @param formId The id of the form. + * @param nextTime next refresh time. + * @return Returns ERR_OK on success, others on failure. + */ + int SetNextRefreshTime(const int64_t formId, const int64_t nextTime) override; + + /** + * @brief lifecycle update. + * @param formIds formIds of hostclient. + * @param callerToken Caller ability token. + * @param updateType update type,enable or disable. + * @return Returns true on success, false on failure. + */ + int LifecycleUpdate(const std::vector &formIds, const sptr &callerToken, + const int32_t updateType) override; + + /** + * @brief Request form with formId and want, send formId and want to form manager service. + * @param formId The Id of the form to update. + * @param callerToken Caller ability token. + * @param want The want of the form to add. + * @return Returns ERR_OK on success, others on failure. + */ + int RequestForm(const int64_t formId, const sptr &callerToken, const Want &want) override; + + /** + * @brief Form visible/invisible notify, send formIds to form manager service. + * @param formIds The Id list of the forms to notify. + * @param callerToken Caller ability token. + * @param formVisibleType The form visible type, including FORM_VISIBLE and FORM_INVISIBLE. + * @return Returns ERR_OK on success, others on failure. + */ + int NotifyWhetherVisibleForms(const std::vector &formIds, const sptr &callerToken, + const int32_t formVisibleType) override; + + /** + * @brief temp form to normal form. + * @param formId The Id of the form. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + int CastTempForm(const int64_t formId, const sptr &callerToken) override; + + /** + * @brief Dump all of form storage infos. + * @param formInfos All of form storage infos. + * @return Returns ERR_OK on success, others on failure. + */ + int DumpStorageFormInfos(std::string &formInfos) override; + /** + * @brief Dump form info by a bundle name. + * @param bundleName The bundle name of form provider. + * @param formInfos Form infos. + * @return Returns ERR_OK on success, others on failure. + */ + int DumpFormInfoByBundleName(const std::string &bundleName, std::string &formInfos) override; + /** + * @brief Dump form info by a bundle name. + * @param formId The id of the form. + * @param formInfo Form info. + * @return Returns ERR_OK on success, others on failure. + */ + int DumpFormInfoByFormId(const std::int64_t formId, std::string &formInfo) override; + + /** + * @brief Process js message event. + * @param formId Indicates the unique id of form. + * @param want information passed to supplier. + * @param callerToken Caller ability token. + * @return Returns true if execute success, false otherwise. + */ + int MessageEvent(const int64_t formId, const Want &want, const sptr &callerToken) override; + + /** + * @brief Check whether if the form manager service is ready. + * @return Returns true if the form manager service is ready; returns false otherwise. + */ + bool IsReady() const; + +private: + /** + * @brief initialization of form manager service. + */ + ErrCode Init(); + + /** + * @brief Permission check by callingUid. + * @param formId the id of the form. + * @return Returns true on success, false on failure. + */ + bool CheckFormPermission(); + + /** + * @brief Permission check. + * @param bundleName bundleName. + * @return Returns true on success, false on failure. + */ + bool CheckFormPermission(const std::string &bundleName) const; +private: + ServiceRunningState state_; + + std::shared_ptr runner_ = nullptr; + std::shared_ptr handler_ = nullptr; + + std::unique_ptr formMgrAdapter_ = nullptr; + + bool resetFlag = false; + + mutable std::mutex instanceMutex_; + + sptr remote = nullptr; + + static const int32_t ENABLE_FORM_UPDATE = 5; + + DISALLOW_COPY_AND_MOVE(FormMgrService); +}; +static bool resetFlag = false; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_MGR_SERVICE_H diff --git a/services/formmgr/include/form_msg_event_connection.h b/services/formmgr/include/form_msg_event_connection.h new file mode 100644 index 0000000000..6fd0981744 --- /dev/null +++ b/services/formmgr/include/form_msg_event_connection.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_MSG_EVENT_CONNECTION_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_MSG_EVENT_CONNECTION_H + +#include "event_handler.h" +#include "form_ability_connection.h" +#include "want.h" + +namespace OHOS { +namespace AppExecFwk { +using Want = OHOS::AAFwk::Want; +/** + * @class FormMsgEventConnection + * Form Refresh Connection Stub. + */ +class FormMsgEventConnection : public FormAbilityConnection { +public: + FormMsgEventConnection(const int64_t formId, const Want &want); + virtual ~FormMsgEventConnection() = default; + + /** + * @brief OnAbilityConnectDone, AbilityMs notify caller ability the result of connect. + * + * @param element service ability's ElementName. + * @param remoteObject the session proxy of service ability. + * @param resultCode ERR_OK on success, others on failure. + */ + void OnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) override; + +private: + int64_t formId_; + Want want_; + DISALLOW_COPY_AND_MOVE(FormMsgEventConnection); +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_MSG_EVENT_CONNECTION_H \ No newline at end of file diff --git a/services/formmgr/include/form_provider_mgr.h b/services/formmgr/include/form_provider_mgr.h new file mode 100644 index 0000000000..31e24cee31 --- /dev/null +++ b/services/formmgr/include/form_provider_mgr.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_PROVIDER_MGRR_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_PROVIDER_MGRR_H +#include +#include +#include "form_provider_info.h" +#include "form_record.h" +#include "want.h" + +namespace OHOS { +namespace AppExecFwk { +using Want = OHOS::AAFwk::Want; +/** + * @class FormProviderMgr + * Form provider manager. + */ +class FormProviderMgr final : public DelayedRefSingleton { + DECLARE_DELAYED_REF_SINGLETON(FormProviderMgr) +public: + DISALLOW_COPY_AND_MOVE(FormProviderMgr); + + /** + * @brief handle for acquire back event from provider. + * @param formId The id of the form. + * @param providerFormInfo provider form info. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode AcquireForm(const int64_t formId, const FormProviderInfo &formProviderInfo); + /** + * @brief handle for update form event from provider. + * @param formId The id of the form. + * @param providerFormInfo provider form info. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode UpdateForm(const int64_t formId, const FormProviderInfo &formProviderInfo); + /** + * handle for update form event from provider. + * + * @param formId The id of the form. + * @param formRecord The form's record. + * @param formProviderData provider form info. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode UpdateForm(const int64_t formId, FormRecord &formRecord, const FormProviderData &formProviderData); + /** + * @brief Refresh form. + * + * @param formId The form id. + * @param want The want of the form to request. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode RefreshForm(const int64_t formId, const Want &want); + /** + * @brief Connect ams for refresh form + * + * @param formId The form id. + * @param record Form data. + * @param want The want of the form. + * @param isTimerRefresh The flag of timer refresh. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode ConnectAmsForRefresh(const int64_t formId, const FormRecord &record, const Want &want, + const bool isTimerRefresh); + /** + * @brief Notify provider form delete. + * @param formId The form id. + * @param record Form information. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode NotifyProviderFormDelete(const int64_t formId, const FormRecord &formRecord); + /** + * @brief Notify provider forms batch delete. + * @param bundleName BundleName. + * @param bundleName AbilityName. + * @param formIds form id list. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode NotifyProviderFormsBatchDelete(const std::string &bundleName, const std::string &abilityName, + const std::set &formIds); + /** + * @brief Process js message event. + * @param formId Indicates the unique id of form. + * @param record Form record. + * @param want information passed to supplier. + * @return Returns true if execute success, false otherwise. + */ + int MessageEvent(const int64_t formId, const FormRecord &record, const Want &want); +private: + FormRecord GetFormAbilityInfo(const FormRecord &record) const; + /** + * @brief Increase the timer refresh count. + * + * @param formId The form id. + */ + void IncreaseTimerRefreshCount(const int64_t formId); + bool IsFormCached(const FormRecord &record); +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_PROVIDER_MGRR_H \ No newline at end of file diff --git a/services/formmgr/include/form_record.h b/services/formmgr/include/form_record.h new file mode 100644 index 0000000000..9664003ab6 --- /dev/null +++ b/services/formmgr/include/form_record.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_RECORD_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_RECORD_H + +#include +#include "form_provider_info.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @class FormRecord + * Form data. + */ +class FormRecord { +public: + int64_t formId; + bool isInited = false; + bool needFreeInstall = false; + bool versionUpgrade = false; + bool needRefresh = false; + bool isCountTimerRefresh = false; + std::string packageName; + std::string bundleName; + std::string moduleName; + std::string abilityName; + std::string formName; + int32_t specification; + bool isEnableUpdate; + long updateDuration; + int updateAtHour; + int updateAtMin; + FormProviderInfo formProviderInfo; + std::vector hapSourceDirs; + std::string jsFormCodePath; + bool formTempFlg; + std::vector formUserUids; + bool formVisibleNotify; + int formVisibleNotifyState; +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_RECORD_H diff --git a/services/formmgr/include/form_refresh_connection.h b/services/formmgr/include/form_refresh_connection.h new file mode 100644 index 0000000000..142c06ae99 --- /dev/null +++ b/services/formmgr/include/form_refresh_connection.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_REFRESH_CONNECTION_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_REFRESH_CONNECTION_H + +#include "event_handler.h" +#include "form_ability_connection.h" +#include "want.h" + +namespace OHOS { +namespace AppExecFwk { +using Want = OHOS::AAFwk::Want; +/** + * @class FormRefreshConnection + * Form Refresh Connection Stub. + */ +class FormRefreshConnection : public FormAbilityConnection { +public: + FormRefreshConnection(const int64_t formId, const Want &want); + virtual ~FormRefreshConnection() = default; + + /** + * @brief OnAbilityConnectDone, AbilityMs notify caller ability the result of connect. + * + * @param element service ability's ElementName. + * @param remoteObject the session proxy of service ability. + * @param resultCode ERR_OK on success, others on failure. + */ + void OnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) override; + +private: + int64_t formId_; + Want want_; + DISALLOW_COPY_AND_MOVE(FormRefreshConnection); +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_REFRESH_CONNECTION_H \ No newline at end of file diff --git a/services/formmgr/include/form_refresh_limiter.h b/services/formmgr/include/form_refresh_limiter.h new file mode 100644 index 0000000000..e4202b169b --- /dev/null +++ b/services/formmgr/include/form_refresh_limiter.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_TIMER_REFRESH_LIMITER_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_TIMER_REFRESH_LIMITER_H + +#include +#include +#include +#include "form_timer.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @class FormRefreshLimiter + * Form refresh limite manager. + */ +class FormRefreshLimiter { +public: + /** + * @brief Add form limit info by formId. + * @param formId The form id. + * @return Returns true on success, false on failure. + */ + bool AddItem(int64_t formId); + /** + * @brief Delete form limit info by formId. + * @param formId The form id. + */ + void DeleteItem(int64_t formId); + /** + * @brief Reset limit info. + */ + void ResetLimit(); + /** + * @brief Refresh enable or not. + * @param formId The form id. + * @return Returns ERR_OK on success, others on failure. + */ + bool IsEnableRefresh(int64_t formId); + /** + * @brief Get refresh count. + * @param formId The form id. + * @return refresh count. + */ + int GetRefreshCount(int64_t formId) const; + /** + * @brief Increase refresh count. + * @param formId The form id. + */ + void Increase(int64_t formId); + /** + * @brief Mark remind flag. + * @param formId The form id. + */ + void MarkRemind(int64_t formId); + /** + * @brief Get remind list. + * @return remind list. + */ + std::vector GetRemindList() const; + /** + * @brief Get remind list and reset limit. + * @return remind list. + */ + std::vector GetRemindListAndResetLimit(); + /** + * @brief Get item count. + * @return Item count. + */ + int GetItemCount() const; +private: + mutable std::mutex limiterMutex_; + std::map limiterMap_; +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_TIMER_REFRESH_LIMITER_H \ No newline at end of file diff --git a/services/formmgr/include/form_storage_mgr.h b/services/formmgr/include/form_storage_mgr.h new file mode 100644 index 0000000000..ac3e13e5f3 --- /dev/null +++ b/services/formmgr/include/form_storage_mgr.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_STORAGE_MGR_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_STORAGE_MGR_H + +#include +#include +#include +#include + +#include "appexecfwk_errors.h" +#include "form_db_info.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @class FormStorageMgr + * Form data storage. + */ +class FormStorageMgr { +public: + FormStorageMgr() = default; + virtual ~FormStorageMgr() = default; + /** + * @brief Load all form data from DB to innerFormInfos. + * @param innerFormInfos Storage all form data. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode LoadFormData(std::vector &innerFormInfos) const; + + /** + * @brief Get form data from DB to innerFormInfo with formId. + * @param innerFormInfo Storage form data. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode GetStorageFormInfoById(const std::string &formId, InnerFormInfo &innerFormInfo) const; + + /** + * @brief Save or update the form data in DB. + * @param innerFormInfo Indicates the InnerFormInfo object to be save. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode SaveStorageFormInfo(const InnerFormInfo &innerFormInfo) const; + + /** + * @brief Modify the form data in DB. + * @param innerFormInfo Indicates the InnerFormInfo object to be Modify. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode ModifyStorageFormInfo(const InnerFormInfo &innerFormInfo) const; + + /** + * @brief Delete the form data in DB. + * @param formId The form data Id. + * @return Returns ERR_OK on success, others on failure. + */ + ErrCode DeleteStorageFormInfo(const std::string &formId) const; +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_STORAGE_MGR_H diff --git a/services/formmgr/include/form_supply_callback.h b/services/formmgr/include/form_supply_callback.h new file mode 100644 index 0000000000..031ff49c12 --- /dev/null +++ b/services/formmgr/include/form_supply_callback.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORMMGR_FORM_SUPPLY_CALLBACK_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORMMGR_FORM_SUPPLY_CALLBACK_H + +#include "form_ability_connection.h" +#include "form_supply_stub.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @class FormSupplyCallback + * form supply service stub. + */ +class FormSupplyCallback : public FormSupplyStub { +public: + FormSupplyCallback() = default; + virtual ~FormSupplyCallback() = default; + static sptr GetInstance(); + + /** + * @brief Accept form binding data from form provider. + * @param providerFormInfo Form binding data. + * @param want input data. + * @return Returns ERR_OK on success, others on failure. + */ + int OnAcquire(const FormProviderInfo &formInfo, const Want &want) override; + + /** + * @brief Accept other event. + * @param want input data. + * @return Returns ERR_OK on success, others on failure. + */ + int OnEventHandle(const Want &want) override; + + /** + * @brief Save ability Connection for the callback. + * @param connection ability connection. + */ + void AddConnection(sptr connection); + /** + * @brief Delete ability connection after the callback come. + * @param connectId The ability connection id generated when save. + */ + void RemoveConnection(long connectId); +private: + static std::mutex mutex_; + static sptr instance_; + + mutable std::mutex conMutex_; + std::map> connections_; + DISALLOW_COPY_AND_MOVE(FormSupplyCallback); +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORMMGR_FORM_SUPPLY_CALLBACK_H diff --git a/services/formmgr/include/form_sys_event_receiver.h b/services/formmgr/include/form_sys_event_receiver.h new file mode 100644 index 0000000000..0706083cf8 --- /dev/null +++ b/services/formmgr/include/form_sys_event_receiver.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_PROVIDER_RECEIVER_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_PROVIDER_RECEIVER_H + +#include "common_event_subscriber.h" +#include "common_event_subscribe_info.h" +#include "form_id_key.h" +#include "form_info.h" +#include "form_record.h" +#include "form_timer.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @class FormSysEventReceiver + * Receive system common event. + */ +class FormSysEventReceiver : public EventFwk::CommonEventSubscriber { +public: + FormSysEventReceiver() = default; + FormSysEventReceiver(const EventFwk::CommonEventSubscribeInfo &subscriberInfo); + virtual ~FormSysEventReceiver() = default; + /** + * @brief System common event receiver. + * @param eventData Common event data. + */ + virtual void OnReceiveEvent(const EventFwk::CommonEventData &eventData) override; +private: + void HandleProviderUpdated(const std::string &bundleName); + bool ProviderFormUpdated(const int64_t formId, const FormRecord &formRecord, + const std::vector &targetForms); + void HandleProviderRemoved(const std::string &bundleName); + void HandleBundleDataCleared(const std::string &bundleName, const int uid); + void HandleFormHostDataCleared(const int uid); + void ClearFormDBRecordData(const int uid, std::map &removedFormsMap); + void ClearTempFormRecordData(const int uid, std::map &removedFormsMap); + void BatchDeleteNoHostDBForms(const int uid, std::map> &noHostFormDbMap, + std::map &removedFormsMap); + /** + * @brief Delete no host temp forms. + * @param uid The caller uid. + * @param noHostTempFormsMap no host temp forms. + * @param foundFormsMap Form Id list. + */ + void BatchDeleteNoHostTempForms(const int uid, std::map> &noHostTempFormsMap, + std::map &foundFormsMap); + void ReCreateForm(const int64_t formId); + bool IsSameForm(const FormRecord &record, const FormInfo &formInfo); + void GetTimerCfg(const bool updateEnabled, const int updateDuration, const std::string &configUpdateAt, + FormTimerCfg &cfg); + void HandleTimerUpdate(const int64_t formId, const FormRecord &record, const FormTimerCfg &timerCfg); +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_PROVIDER_RECEIVER_H \ No newline at end of file diff --git a/services/formmgr/include/form_task_mgr.h b/services/formmgr/include/form_task_mgr.h new file mode 100644 index 0000000000..103e52a84e --- /dev/null +++ b/services/formmgr/include/form_task_mgr.h @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_TASK_MGR_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_TASK_MGR_H + +#include +#include + +#include "event_handler.h" +#include "form_item_info.h" +#include "form_js_info.h" +#include "form_provider_info.h" +#include "form_record.h" +#include "ipc_types.h" +#include "iremote_object.h" +#include "form_record.h" +#include "want.h" + +namespace OHOS { +namespace AppExecFwk { +using Want = OHOS::AAFwk::Want; +using WantParams = OHOS::AAFwk::WantParams; +/** + * @class FormTaskMgr + * form task manager. + */ +class FormTaskMgr final : public DelayedRefSingleton { + DECLARE_DELAYED_REF_SINGLETON(FormTaskMgr) + +public: + DISALLOW_COPY_AND_MOVE(FormTaskMgr); + + /** + * @brief SetEventHandler. + * @param handler event handler + */ + inline void SetEventHandler(const std::shared_ptr &handler) + { + eventHandler_ = handler; + } + + /** + * @brief Acquire form data from form provider(task). + * @param formId The Id of the form. + * @param want The want of the request. + * @param remoteObject Form provider proxy object. + */ + void PostAcquireTask(const int64_t formId, const Want &want, const sptr &remoteObject); + + /** + * @brief Delete form data from form provider(task). + * @param formId The Id of the form. + * @param want The want of the request. + * @param remoteObject Form provider proxy object. + */ + void PostDeleteTask(const int64_t formId, const Want &want, const sptr &remoteObject); + /** + * @brief Notify provider batch delete. + * @param formIds The Id list. + * @param want The want of the request. + * @param remoteObject Form provider proxy object. + */ + void PostProviderBatchDeleteTask(std::set &formIds, const Want &want, + const sptr &remoteObject); + /** + * @brief Refresh form data from form provider(task). + * + * @param formId The Id of the form. + * @param want The want of the form. + * @param remoteObject Form provider proxy object. + * @return none. + */ + void PostRefreshTask(const int64_t formId, const Want &want, const sptr &remoteObject); + + /** + * @brief Cast temp form data from form provider(task). + * + * @param formId The Id of the form. + * @param want The want of the request. + * @param remoteObject Form provider proxy object. + * @return none. + */ + void PostCastTempTask(const int64_t formId, const Want &want, const sptr &remoteObject); + + /** + * @brief Post form data to form host(task) when acquire form. + * @param formId The Id of the form. + * @param callingUid Calling uid. + * @param info Form configure info. + * @param wantParams WantParams of the request. + * @param remoteObject Form provider proxy object. + */ + + void PostAcquireTaskToHost(const int64_t formId, const FormRecord &record, const sptr &remoteObject); + + /** + * @brief Post form data to form host(task) when update form. + * @param formId The Id of the form. + * @param callingUid Calling uid. + * @param info Form configure info. + * @param wantParams WantParams of the request. + * @param remoteObject Form provider proxy object. + */ + void PostUpdateTaskToHost(const int64_t formId, const FormRecord &record, const sptr &remoteObject); + + /** + * @brief Handel form host died(task). + * @param remoteHost Form host proxy object. + */ + void PostHostDiedTask(const sptr &remoteHost); + + /** + * @brief Post event notify to form provider. + * + * @param formEvent The vector of form ids. + * @param formVisibleType The form visible type, including FORM_VISIBLE and FORM_INVISIBLE. + * @param want The want of the form. + * @param remoteObject The form provider proxy object. + * @return none. + */ + void PostEventNotifyTask(const std::vector &formEvent, const int32_t formVisibleType, const Want &want, + const sptr &remoteObject); + + /** + * @brief Post message event to form provider. + * @param formId The Id of the from. + * @param message Event message. + * @param want The want of the request. + * @param remoteObject Form provider proxy object. + */ + void PostFormEventTask(const int64_t formId, const std::string &message, const Want &want, + const sptr &remoteObject); + + /** + * @brief Post uninstall message to form host(task). + * @param formIds The Id list of the forms. + * @param remoteObject Form provider proxy object. + */ + void PostUninstallTaskToHost(const std::vector &formIds, const sptr &remoteObject); +private: + /** + * @brief Acquire form data from form provider. + * @param formId The Id of the from. + * @param want The want of the request. + * @param remoteObject Form provider proxy object. + */ + void AcquireProviderFormInfo(const int64_t formId, const Want &want, const sptr &remoteObject); + + /** + * @brief Notify form provider for delete form. + * @param formId The Id of the from. + * @param want The want of the form. + * @param remoteObject Form provider proxy object. + * @return none. + */ + void NotifyFormDelete(const int64_t formId, const Want &want, const sptr &remoteObject); + + /** + * @brief Notify form provider for updating form. + * @param formId The Id of the from. + * @param want The want of the form. + * @param remoteObject Form provider proxy object. + * @return none. + */ + void NotifyFormUpdate(const int64_t formId, const Want &want, const sptr &remoteObject); + + /** + * @brief Event notify to form provider. + * + * @param formEvents The vector of form ids. + * @param formVisibleType The form visible type, including FORM_VISIBLE and FORM_INVISIBLE. + * @param want The want of the form. + * @param remoteObject The form provider proxy object. + * @return none. + */ + void EventNotify(const std::vector &formEvents, const int32_t formVisibleType, const Want &want, + const sptr &remoteObject); + + /** + * @brief Notify form provider for cast temp form. + * + * @param formId The Id of the from. + * @param want The want of the form. + * @param remoteObject Form provider proxy object. + * @return none. + */ + void NotifyCastTemp(const int64_t formId, const Want &want, const sptr &remoteObject); + /** + * @brief Post form data to form host when acquire form.. + * @param formId The Id of the form. + * @param callingUid Calling uid. + * @param info Form configure info. + * @param wantParams WantParams of the request. + * @param remoteObject Form provider proxy object. + */ + void AcquireTaskToHost(const int64_t formId, const FormRecord &record, const sptr &remoteObject); + + /** + * @brief Post form data to form host when update form. + * @param formId The Id of the form. + * @param callingUid Calling uid. + * @param info Form configure info. + * @param wantParams WantParams of the request. + * @param remoteObject Form provider proxy object. + */ + void UpdateTaskToHost(const int64_t formId, const FormRecord &record, const sptr &remoteObject); + + /** + * @brief Handle form host died. + * @param remoteHost Form host proxy object. + */ + void HostDied(const sptr &remoteHost); + + /** + * @brief Post provider batch delete. + * @param formIds The Id list. + * @param want The want of the request. + * @param remoteObject Form provider proxy object. + */ + void ProviderBatchDelete(std::set &formIds, const Want &want, const sptr &remoteObject); + /** + * @brief Fire message event to form provider. + * @param formId The Id of the from. + * @param message Event message. + * @param want The want of the request. + * @param remoteObject Form provider proxy object. + */ + void FireFormEvent(const int64_t formId, const std::string &message, const Want &want, + const sptr &remoteObject); + + /** + * @brief Handle uninstall message. + * @param formIds The Id list of the forms. + * @param remoteObject Form provider proxy object. + */ + void FormUninstall(const std::vector &formIds, const sptr &remoteObject); + + /** + * @brief Create form data for form host. + * @param formId The Id of the form. + * @param record Form record. + * @return Form data. + */ + FormJsInfo CreateFormJsInfo(const int64_t formId, const FormRecord &record); + +private: + std::shared_ptr eventHandler_ = nullptr; +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_TASK_MGR_H diff --git a/services/formmgr/include/form_timer.h b/services/formmgr/include/form_timer.h new file mode 100644 index 0000000000..94cf7ffcff --- /dev/null +++ b/services/formmgr/include/form_timer.h @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_TIMER_TASK_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_TIMER_TASK_H +namespace OHOS { +namespace AppExecFwk { +/** + * @enum UpdateType + * Update type. + */ +enum UpdateType { + TYPE_INTERVAL_CHANGE, + TYPE_ATTIME_CHANGE, + TYPE_INTERVAL_TO_ATTIME, + TYPE_ATTIME_TO_INTERVAL, + TYPE_INTERVAL_ONCE, +}; +/** + * @class FormTimer + * form timer task. + */ +class FormTimer { +public: + int64_t formId; + int64_t period; + int hour; + int min; + bool isUpdateAt; + int64_t refreshTime; + bool isEnable = true; + bool isCountTimer = false; + UpdateType type; + + FormTimer() + { + formId = -1; + period = -1; + hour = -1; + min = -1; + isUpdateAt = false; + isCountTimer = false; + } + + FormTimer(int64_t id, bool countTimer) + { + formId = id; + period = -1; + hour = -1; + min = -1; + isUpdateAt = false; + isCountTimer = countTimer; + } + + FormTimer(int64_t id, long repeatTime) + { + formId = id; + period = repeatTime; + hour = -1; + min = -1; + isUpdateAt = false; + isCountTimer = true; + } + + FormTimer(int64_t id, int hourTime, int minTime) + { + formId = id; + hour = hourTime; + min = minTime; + period = -1; + isUpdateAt = true; + isCountTimer = false; + } +}; +/** + * @class UpdateAtItem + * Update item at time. + */ +class UpdateAtItem { +public: + int updateAtTime = -1; + FormTimer refreshTask; +}; +/** + * @class DynamicRefreshItem + * Dynamic refresh item. + */ +class DynamicRefreshItem { +public: + int64_t formId = 0L; + int64_t settedTime = -1L; + + DynamicRefreshItem(){} + + DynamicRefreshItem(int64_t id, int64_t time) + { + formId = id; + settedTime = time; + } +}; +/** + * @struct LimitInfo + * Limit info about a form. + */ +struct LimitInfo { + int refreshCount = 0; + bool isReported = false; + bool remindFlag = false; +}; + +/** + * @struct FormTimerCfg + * Form timer config info. + */ +struct FormTimerCfg { + bool enableUpdate = false; + int64_t updateDuration = 0L; + int updateAtHour = -1; + int updateAtMin = -1; +}; + +// class TimerInfo : public ITimerInfo { +// public: +// TimerInfo(); +// virtual ~TimerInfo(); +// virtual void OnTrigger() override; +// virtual void SetType(const int &type) override; +// virtual void SetRepeat(bool repeat) override; +// virtual void SetInterval(const uint64_t &interval) override; +// virtual void SetWantAgent(std::shared_ptr wantAgent) override; +// void SetCallbackInfo(std::function callBack); + +// private: +// std::function callBack_; +// }; + +// TimerInfo::TimerInfo() +// { +// } + +// TimerInfo::~TimerInfo() +// { +// } + +// void TimerInfo::OnTrigger() +// { +// callBack_(); +// } + +// void TimerInfo::SetCallbackInfo(std::function callBack) +// { +// callBack_ = callBack; +// } + +// void TimerInfo::SetType(const int &_type) +// { +// type = _type; +// } + +// void TimerInfo::SetRepeat(bool _repeat) +// { +// repeat = _repeat; +// } +// void TimerInfo::SetInterval(const uint64_t &_interval) +// { +// interval = _interval; +// } +// void TimerInfo::SetWantAgent(std::shared_ptr _wantAgent) +// { +// wantAgent = _wantAgent; +// } + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_TIMER_TASK_H diff --git a/services/formmgr/include/form_timer_mgr.h b/services/formmgr/include/form_timer_mgr.h new file mode 100644 index 0000000000..b710a2a079 --- /dev/null +++ b/services/formmgr/include/form_timer_mgr.h @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_TIMER_MGR_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_TIMER_MGR_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common_event_subscriber.h" +#include "common_event_subscribe_info.h" +#include "form_refresh_limiter.h" +#include "form_timer.h" + +#include "thread_pool.h" +#include "timer.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @class FormTimerMgr + * form timer task manager. + */ +class FormTimerMgr final : public DelayedRefSingleton { +DECLARE_DELAYED_REF_SINGLETON(FormTimerMgr) +public: + DISALLOW_COPY_AND_MOVE(FormTimerMgr); + /** + * @brief Add form timer by timer task. + * @param task The form timer task. + * @return Returns true on success, false on failure. + */ + bool AddFormTimer(const FormTimer &task); + /** + * @brief Add duration form timer. + * @param formId The Id of the form. + * @param updateDuration Update duration + * @return Returns true on success, false on failure. + */ + bool AddFormTimer(const int64_t formId, const long updateDuration); + /** + * @brief Add scheduled form timer. + * @param formId The Id of the form. + * @param updateAtHour Hour + * @param updateAtMin Min + * @return Returns true on success, false on failure. + */ + bool AddFormTimer(const int64_t formId, const long updateAtHour, const long updateAtMin); + /** + * @brief Remove form timer by form id. + * @param formId The Id of the form. + * @return Returns true on success, false on failure. + */ + bool RemoveFormTimer(const int64_t formId); + /** + * @brief Update form timer. + * @param formId The Id of the form. + * @param type Timer type. + * @param timerCfg Timer config. + * @return Returns true on success, false on failure. + */ + bool UpdateFormTimer(const int64_t formId, const UpdateType &type, const FormTimerCfg &timerCfg); + /** + * @brief Is limiter enable refresh. + * @param formId The Id of the form. + * @return Returns true on success, false on failure. + */ + bool IsLimiterEnableRefresh(const int64_t formId); + /** + * @brief Increase refresh count. + * @param formId The Id of the form. + */ + void IncreaseRefreshCount(const int64_t formId); + /** + * @brief Set next refresh time. + * @param formId The Id of the form. + * @param nextGapTime Next gap time. + * @return Returns true on success, false on failure. + */ + bool SetNextRefreshTime(const int64_t formId, const long nextGapTime); + /** + * @brief Get refresh count. + * @param formId The Id of the form. + * @return Returns refresh count. + */ + int GetRefreshCount(const int64_t formId) const; + /** + * @brief Mark remind. + * @param formId The Id of the form. + * @return true or false. + */ + void MarkRemind(const int64_t formId); + + /** + * @brief Handle system time changed. + */ + void HandleSystemTimeChanged(); + /** + * @brief Reset form limiter. + */ + void HandleResetLimiter(); + /** + * @brief Update attime trigger. + * @param updateTime Update time. + */ + void OnUpdateAtTrigger(long updateTime); + /** + * @brief Dynamic time trigger. + * @param updateTime Update time. + */ + void OnDynamicTimeTrigger(long updateTime); + +private: + /** + * @brief Add update at timer. + * @param task Update time task. + * @return Returns true on success, false on failure. + */ + bool AddUpdateAtTimer(const FormTimer &task); + /** + * @brief Add update at timer item. + * @param task Update at timer item. + */ + void AddUpdateAtItem(const UpdateAtItem &atItem); + /** + * @brief Add update interval timer task. + * @param task Update interval timer task. + * @return Returns true on success, false on failure. + */ + bool AddIntervalTimer(const FormTimer &task); + /** + * @brief interval timer task timeout. + */ + void OnIntervalTimeOut(); + /** + * @brief Get remind tasks. + * @param remindTasks Remind tasks. + * @return Returns true on success, false on failure. + */ + bool GetRemindTasks(std::vector &remindTasks); + /** + * @brief Set enableFlag for interval timer task. + * @param formId The Id of the form. + * @param flag Enable flag. + */ + void SetIntervalEnableFlag(int64_t formId, bool flag); + /** + * @brief Update Interval timer task value. + * @param formId The Id of the form. + * @param timerCfg task value. + * @return Returns true on success, false on failure. + */ + bool UpdateIntervalValue(const int64_t formId, const FormTimerCfg &timerCfg); + /** + * @brief Update update at timer task value. + * @param formId The Id of the form. + * @param timerCfg task value. + * @return Returns true on success, false on failure. + */ + bool UpdateAtTimerValue(const int64_t formId, const FormTimerCfg &timerCfg); + /** + * @brief Interval timer task to update at timer task. + * @param formId The Id of the form. + * @param timerCfg task value. + * @return Returns true on success, false on failure. + */ + bool IntervalToAtTimer(const int64_t formId, const FormTimerCfg &timerCfg); + /** + * @brief Update at timer task to interval timer task. + * @param formId The Id of the form. + * @param timerCfg task value. + * @return Returns true on success, false on failure. + */ + bool AtTimerToIntervalTimer(const int64_t formId, const FormTimerCfg &timerCfg); + /** + * @brief Delete interval timer task. + * @param formId The Id of the form. + * @return Returns true on success, false on failure. + */ + bool DeleteIntervalTimer(const int64_t formId); + /** + * @brief Delete update at timer. + * @param formId The Id of the form. + */ + void DeleteUpdateAtTimer(const int64_t formId); + /** + * @brief Update at timer task alarm. + * @return Returns true on success, false on failure. + */ + bool UpdateAtTimerAlarm(); + /** + * @brief Update limiter task alarm. + * @return Returns true on success, false on failure. + */ + bool UpdateLimiterAlarm(); + /** + * @brief Delete dynamic refresh item. + * @param formId The Id of the form. + */ + void DeleteDynamicItem(const int64_t formId); + /** + * @brief Update dynamic refresh task alarm. + * @return Returns true on success, false on failure. + */ + bool UpdateDynamicAlarm(); + /** + * @brief Clear dynamic refresh resource. + */ + void ClearDynamicResource(); + /** + * @brief Fint next at timer item. + * @param nowTime Update time. + * @param updateAtItem Next at timer item. + * @return Returns true on success, false on failure. + */ + bool FindNextAtTimerItem(const int nowTime, UpdateAtItem &updateAtItem); + /** + * @brief Clear update at timer resource. + */ + void ClearUpdateAtTimerResource(); + + /** + * @brief Execute Form timer task. + * @param task Form timer task. + */ + void ExecTimerTask(const FormTimer &task); + + /** + * @brief Init. + */ + void Init(); + /** + * @brief Ensure init interval timer resource. + */ + void EnsureInitIntervalTimer(); + /** + * @brief Clear interval timer resource. + */ + void ClearIntervalTimer(); + /** + * @brief Get thread pool for timer task. + */ + OHOS::ThreadPool* GetTaskThreadExecutor(); + + /** + * @brief Set enable flag. + * @param formId The Id of the form. + * @param flag Enable flag. + */ + void SetEnableFlag(int64_t formId, bool flag); +private: + /** + * @class TimerReceiver + * timer event receiver. + */ + class TimerReceiver : public EventFwk::CommonEventSubscriber { + public: + TimerReceiver() = default; + TimerReceiver(const EventFwk::CommonEventSubscribeInfo &subscriberInfo); + virtual ~TimerReceiver() = default; + /** + * @brief Receive common event. + * @param eventData Common event data. + */ + virtual void OnReceiveEvent(const EventFwk::CommonEventData &eventData) override; + }; + + struct { + bool operator()(DynamicRefreshItem a, DynamicRefreshItem b) const + { + return (a.settedTime > b.settedTime ? true : false); + } + } CompareDynamicRefreshItem; + + mutable std::mutex intervalMutex_; + mutable std::mutex updateAtMutex_; + mutable std::mutex dynamicMutex_; + mutable std::mutex refreshMutex_; + FormRefreshLimiter refreshLimiter_; + std::map intervalTimerTasks_; + std::list updateAtTimerTasks_; + std::vector dynamicRefreshTasks_; + + std::shared_ptr timerReceiver_; + + OHOS::ThreadPool* taskExecutor_; + Utils::Timer* intervalTimer_; + + long dynamicWakeUpTime_ = LONG_MAX; + long atTimerWakeUpTime_ = LONG_MAX; +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_TIMER_MGR_H diff --git a/services/formmgr/include/form_util.h b/services/formmgr/include/form_util.h new file mode 100644 index 0000000000..d043693889 --- /dev/null +++ b/services/formmgr/include/form_util.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_UTIL_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_UTIL_H + +#include "want.h" + +namespace OHOS { +namespace AppExecFwk { +using Want = OHOS::AAFwk::Want; +/** + * @class FormUtil + * form utils. + */ +class FormUtil { +public: + /** + * @brief create want for form. + * @param formName The name of the form. + * @param specificationId specification id. + * @param isTemporaryForm temporary form or not. + * @param want The want of the form. + */ + static void CreateFormWant(const std::string &formName, const int32_t specificationId, const bool isTemporaryForm, + Want &want); + /** + * @brief create default want for form. + * @param want The want of the form.. + * @param uri The uri. + * @param userId user id. + */ + static void CreateDefaultFormWant(Want &want, const std::string &uri, const int32_t userId); + + /** + * @brief create udid for form. + * @return udid. + */ + static std::string GenerateUdid(); + + /** + * @brief create form id for form. + * @param udidHash udid hash + * @return new form id. + */ + static int64_t GenerateFormId(int64_t udidHash); + + /** + * @brief padding form id. + * @param formId The id of the form. + * @param udidHash udid hash. + * @return new form id. + */ + static int64_t PaddingUDIDHash(int64_t formId, int64_t udidHash); + + /** + * @brief create udid hash. + * @param udidHash udid hash. + * @return Returns true on success, false on failure. + */ + static bool GenerateUdidHash(int64_t &udidHash); + /** + * @brief Get current system nanosecond. + * @return Current system nanosecond. + */ + static long GetCurrentNanosecond(); + /** + * @brief Get current system millisecond. + * @return Current system millisecond. + */ + static long GetCurrentMillisecond(); + /** + * @brief Get millisecond from tm. + * @param tmAtTime tm time. + * @return Millisecond. + */ + static long GetMillisecondFromTm(struct tm &tmAtTime); + + /** + * @brief split string. + * @param in string. + * @param delim delimiter. + * @return string list. + */ + static std::vector StringSplit(const std::string &in, const std::string &delim); +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_INCLUDE_FORM_UTIL_H \ No newline at end of file diff --git a/services/formmgr/src/form_ability_connection.cpp b/services/formmgr/src/form_ability_connection.cpp new file mode 100644 index 0000000000..4a22a38647 --- /dev/null +++ b/services/formmgr/src/form_ability_connection.cpp @@ -0,0 +1,102 @@ + +/* + * Copyright (c) 2021 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 "appexecfwk_errors.h" +#include "app_log_wrapper.h" +#include "form_ability_connection.h" +#include "form_supply_callback.h" +#include "form_task_mgr.h" +#include "ipc_types.h" +#include "message_parcel.h" +#include "want.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @brief OnAbilityConnectDone, AbilityMs notify caller ability the result of connect. + * @param element service ability's ElementName. + * @param remoteObject the session proxy of service ability. + * @param resultCode ERR_OK on success, others on failure. + */ +void FormAbilityConnection::OnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) +{ + if (resultCode != ERR_OK) { + APP_LOGE("%{public}s, abilityName:%{public}s, formId:%{public}lld, resultCode:%{public}d", + __func__, element.GetAbilityName().c_str(), formId_, resultCode); + return; + } + // deviceId_ = element.GetDeviceID(); + // bundleName_ = element.GetBundleName(); + // abilityName_ = element.GetAbilityName(); + + if (isFreeInstall_) { + // Handle free install for form provider app + } +} +/** + * @brief OnAbilityDisconnectDone, AbilityMs notify caller ability the result of disconnect. + * @param element service ability's ElementName. + * @param resultCode ERR_OK on success, others on failure. + */ +void FormAbilityConnection::OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode) +{ + APP_LOGD("%{public}s, element:%{public}s, resultCode:%{public}d", __func__, element.GetURI().c_str(), resultCode); + if (connectId_ > 0) { + FormSupplyCallback::GetInstance()->RemoveConnection(connectId_); + } else { + APP_LOGE("%{public}s fail, connectId_ invalidate. connectId_: %{public}ld", __func__, connectId_); + } +} + +/** + * @brief Remote object died event. + * @param remoteObject the remote object of service ability. + */ +void FormAbilityConnection::OnConnectDied(const wptr &remoteObject) +{ + if (connectId_ > 0) { + FormSupplyCallback::GetInstance()->RemoveConnection(connectId_); + } else { + APP_LOGE("%{public}s fail, connectId_ invalidate. connectId_: %{public}ld", __func__, connectId_); + } +} +/** + * @brief Set connectId. + * @param connectId The ability connection id. + */ +void FormAbilityConnection::SetConnectId(long connectId) +{ + APP_LOGI("%{public}s, connectId_: %{public}ld", __func__, connectId); + connectId_ = connectId; +} +/** + * @brief Get connectId. + * @return The ability connection id. + */ +long FormAbilityConnection::GetConnectId() +{ + return connectId_; +} +// std::string FormAbilityConnection::GetProviderKey() +// { +// if(deviceId_.empty() || bundleName_.empty() || abilityName_.empty()) { +// return ""; +// } +// return deviceId_ + "::" + bundleName_ + "::" + abilityName_; +// } +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/formmgr/src/form_acquire_connection.cpp b/services/formmgr/src/form_acquire_connection.cpp new file mode 100644 index 0000000000..7a6a765285 --- /dev/null +++ b/services/formmgr/src/form_acquire_connection.cpp @@ -0,0 +1,65 @@ + +/* + * Copyright (c) 2021 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 "appexecfwk_errors.h" +#include "app_log_wrapper.h" +#include "form_acquire_connection.h" +#include "form_constants.h" +#include "form_supply_callback.h" +#include "form_task_mgr.h" +#include "form_util.h" +#include "ipc_types.h" +#include "message_parcel.h" +#include "want.h" + +namespace OHOS { +namespace AppExecFwk { +FormAcquireConnection::FormAcquireConnection(const int64_t formId, const FormItemInfo &info, +const WantParams &wantParams) + :formId_(formId), + info_(info), + wantParams_(wantParams) +{ +} +/** + * @brief OnAbilityConnectDone, AbilityMs notify caller ability the result of connect. + * @param element service ability's ElementName. + * @param remoteObject the session proxy of service ability. + * @param resultCode ERR_OK on success, others on failure. + */ +void FormAcquireConnection::OnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) +{ + APP_LOGI("%{public}s called.", __func__); + if (resultCode != ERR_OK) { + APP_LOGE("%{public}s, abilityName:%{public}s, formId:%{public}lld, resultCode:%{public}d", + __func__, element.GetAbilityName().c_str(), formId_, resultCode); + return; + } + FormSupplyCallback::GetInstance()->AddConnection(this); + Want want; + want.SetParams(wantParams_); + FormUtil::CreateFormWant(info_.GetFormName(), info_.GetSpecificationId(), info_.IsTemporaryForm(), want); + if (want.GetBoolParam(Constants::RECREATE_FORM_KEY, false)) { + want.SetParam(Constants::ACQUIRE_TYPE, Constants::ACQUIRE_TYPE_RECREATE_FORM); + } else { + want.SetParam(Constants::ACQUIRE_TYPE, Constants::ACQUIRE_TYPE_CREATE_FORM); + } + want.SetParam(Constants::FORM_CONNECT_ID, this->GetConnectId()); + FormTaskMgr::GetInstance().PostAcquireTask(formId_, want, remoteObject); +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/formmgr/src/form_ams_helper.cpp b/services/formmgr/src/form_ams_helper.cpp new file mode 100644 index 0000000000..7a393c4aa0 --- /dev/null +++ b/services/formmgr/src/form_ams_helper.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2021 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 "ability_manager_interface.h" +#include "appexecfwk_errors.h" +#include "app_log_wrapper.h" +#include "form_ams_helper.h" +#include "if_system_ability_manager.h" +#include "ipc_skeleton.h" +#include "iservice_registry.h" +#include "system_ability_definition.h" + +namespace OHOS { +namespace AppExecFwk { +FormAmsHelper::FormAmsHelper(){} +FormAmsHelper::~FormAmsHelper(){} + +/** + * @brief acquire a form ability manager, if it not existed, + * @return returns the ability manager ipc object, or nullptr for failed. + */ +sptr FormAmsHelper::GetAbilityManager() +{ + if (abilityManager_ == nullptr) { + sptr systemManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (systemManager == nullptr) { + APP_LOGE("%{public}s:fail to get registry", __func__); + return nullptr; + } + sptr remoteObject = systemManager->GetSystemAbility(ABILITY_MGR_SERVICE_ID); + if (remoteObject == nullptr) { + APP_LOGE("%{public}s:fail to connect AbilityMgrService", __func__); + return nullptr; + } + APP_LOGD("connect AbilityMgrService success"); + + abilityManager_ = iface_cast(remoteObject); + } + + return abilityManager_; +} + +/** + * @brief ConnectAbility, connect session with service ability. + * @param want Special want for service type's ability. + * @param connect Callback used to notify caller the result of connecting or disconnecting. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormAmsHelper::ConnectServiceAbility( + const Want &want, const sptr &connect) +{ + APP_LOGI("%{public}s called.", __func__); + sptr ams = GetAbilityManager(); + if (ams == nullptr) { + APP_LOGE("%{public}s:ability service not connect", __func__); + return ERR_APPEXECFWK_FORM_BIND_PROVIDER_FAILED; + } + return ams->ConnectAbility(want, connect, nullptr); +} +/** + * @brief DisConnectAbility, disconnect session with service ability. + * @param want Special want for service type's ability. + * @param connect Callback used to notify caller the result of connecting or disconnecting. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormAmsHelper::DisConnectServiceAbility(const sptr &connect) +{ + sptr ams = GetAbilityManager(); + if (ams == nullptr) { + APP_LOGE("%{public}s:ability service not connect", __func__); + return ERR_APPEXECFWK_FORM_BIND_PROVIDER_FAILED; + } + return ams->DisconnectAbility(connect); +} +/** + * @brief Add the ability manager instance for debug. + * @param abilityManager the ability manager ipc object. + */ +void FormAmsHelper::SetAbilityManager(const sptr &abilityManager) +{ + abilityManager_ = abilityManager; +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/formmgr/src/form_batch_delete_connection.cpp b/services/formmgr/src/form_batch_delete_connection.cpp new file mode 100644 index 0000000000..6da3a394ea --- /dev/null +++ b/services/formmgr/src/form_batch_delete_connection.cpp @@ -0,0 +1,55 @@ + +/* + * Copyright (c) 2021 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 "appexecfwk_errors.h" +#include "app_log_wrapper.h" +#include "form_batch_delete_connection.h" +#include "form_constants.h" +#include "form_supply_callback.h" +#include "form_task_mgr.h" +#include "form_util.h" +#include "ipc_types.h" +#include "message_parcel.h" +#include "want.h" + +namespace OHOS { +namespace AppExecFwk { +FormBatchDeleteConnection::FormBatchDeleteConnection(const std::set &formIds) + :formIds_(formIds) +{ +} +/** + * @brief OnAbilityConnectDone, AbilityMs notify caller ability the result of connect. + * @param element service ability's ElementName. + * @param remoteObject the session proxy of service ability. + * @param resultCode ERR_OK on success, others on failure. + */ +void FormBatchDeleteConnection::OnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) +{ + APP_LOGI("%{public}s called.", __func__); + if (resultCode != ERR_OK) { + APP_LOGE("%{public}s, abilityName:%{public}s, resultCode:%{public}d", + __func__, element.GetAbilityName().c_str(), resultCode); + return; + } + FormSupplyCallback::GetInstance()->AddConnection(this); + Want want; + want.SetParam(Constants::FORM_CONNECT_ID, this->GetConnectId()); + FormTaskMgr::GetInstance().PostProviderBatchDeleteTask(formIds_, want, remoteObject); +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/formmgr/src/form_bms_helper.cpp b/services/formmgr/src/form_bms_helper.cpp new file mode 100644 index 0000000000..22180d2263 --- /dev/null +++ b/services/formmgr/src/form_bms_helper.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2021 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 "ability_manager_interface.h" +#include "appexecfwk_errors.h" +#include "app_log_wrapper.h" +#include "form_bms_helper.h" +#include "if_system_ability_manager.h" +#include "ipc_skeleton.h" +#include "iservice_registry.h" +#include "system_ability_definition.h" + +namespace OHOS { +namespace AppExecFwk { +FormBmsHelper::FormBmsHelper() +{} + +FormBmsHelper::~FormBmsHelper() +{} + +/** + * @brief Acquire a bundle manager, if it not existed. + * @return returns the bundle manager ipc object, or nullptr for failed. + */ +sptr FormBmsHelper::GetBundleMgr() +{ + APP_LOGI("%{public}s called.", __func__); + + if (iBundleMgr_ == nullptr) { + sptr systemAbilityManager = + SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + auto remoteObject = systemAbilityManager->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID); + if (remoteObject == nullptr) { + APP_LOGE("%{public}s error, failed to get bundle manager service.", __func__); + return nullptr; + } + + iBundleMgr_ = iface_cast(remoteObject); + if (iBundleMgr_ == nullptr) { + APP_LOGE("%{public}s error, failed to get bundle manager service", __func__); + return nullptr; + } + } + return iBundleMgr_; +} + +/** + * @brief Add the bundle manager instance for debug. + * @param bundleManager the bundle manager ipc object. + */ +void FormBmsHelper::SetBundleManager(const sptr &bundleManager) +{ + APP_LOGI("%{public}s called.", __func__); + + iBundleMgr_ = bundleManager; +} +/** + * @brief Notify module removable. + * @param bundleName Provider ability bundleName. + * @param moduleName Provider ability moduleName. + */ +void FormBmsHelper::NotifyModuleRemovable(const std::string &bundleName, const std::string &moduleName) +{ + APP_LOGI("%{public}s, bundleName:%{public}s, moduleName:%{public}s", __func__, bundleName.c_str(), + moduleName.c_str()); + if (bundleName.empty() || moduleName.empty()) { + return; + } + + std::string key = GenerateModuleKey(bundleName, moduleName); + APP_LOGI("%{public}s, begin to notify %{public}s removable", __func__, key.c_str()); + sptr iBundleMgr = GetBundleMgr(); + if (iBundleMgr == nullptr) { + APP_LOGE("%{public}s, failed to get IBundleMgr.", __func__); + return; + } + + std::string originId = IPCSkeleton::ResetCallingIdentity(); + // iBundleMgr->UpdateModuleRemovableFlag(bundleName, moduleName, FLAG_MODULE_NOT_USED_BY_FORM); + + IPCSkeleton::SetCallingIdentity(originId); +} +/** + * @brief Notify module not removable. + * @param bundleName Provider ability bundleName. + * @param moduleName Provider ability moduleName. + */ +void FormBmsHelper::NotifyModuleNotRemovable(const std::string &bundleName, const std::string &moduleName) const +{ + std::string key = GenerateModuleKey(bundleName, moduleName); + APP_LOGI("%{public}s, begin to notify %{public}s not removable", __func__, key.c_str()); +} + +std::string FormBmsHelper::GenerateModuleKey(const std::string &bundleName, const std::string &moduleName) const +{ + return bundleName + "#" + moduleName; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/formmgr/src/form_cache_mgr.cpp b/services/formmgr/src/form_cache_mgr.cpp new file mode 100644 index 0000000000..002f41b9da --- /dev/null +++ b/services/formmgr/src/form_cache_mgr.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2021 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 "app_log_wrapper.h" +#include "form_cache_mgr.h" + +namespace OHOS { +namespace AppExecFwk { +FormCacheMgr::FormCacheMgr() +{ + APP_LOGI("create form cache manager instance"); +} +FormCacheMgr::~FormCacheMgr() +{ + APP_LOGI("destroy form cache manager instance"); +} + +/** + * @brief Get form data. + * @param formId, Form id. + * @param data, Cache data. + * @return Returns true if this function is successfully called; returns false otherwise. + */ +bool FormCacheMgr::GetData(const int64_t formId, std::string &data) const +{ + APP_LOGI("get cache data"); + std::lock_guard lock(cacheMutex_); + if (cacheData_.empty()) { + APP_LOGE("form cache is empty"); + return false; + } + auto formData = cacheData_.find(formId); + if (formData == cacheData_.end()) { + APP_LOGE("cache data not find"); + return false; + } + + data = formData->second; + + return true; +} + +/** + * @brief Add form data. + * @param formId, Form id. + * @param data, Cache data. + * @return Returns true if this function is successfully called; returns false otherwise. + */ +bool FormCacheMgr::AddData(const int64_t formId, const std::string &data) +{ + APP_LOGI("add new cache data"); + std::lock_guard lock(cacheMutex_); + std::pair::iterator, bool> retVal + = cacheData_.emplace(formId, data); + + return retVal.second; +} + +/** + * @brief Delete form data. + * @param formId, Form id. + * @return Returns true if this function is successfully called; returns false otherwise. + */ +bool FormCacheMgr::DeleteData(const int64_t formId) +{ + APP_LOGI("delete cache data"); + std::lock_guard lock(cacheMutex_); + auto formData = cacheData_.find(formId); + if (formData == cacheData_.end()) { + APP_LOGW("cache data is not exist"); + return true; + } + + return cacheData_.erase(formId); +} + +/** + * @brief Update form data. + * @param formId, Form id. + * @param data, Cache data. + * @return Returns true if this function is successfully called; returns false otherwise. + */ +bool FormCacheMgr::UpdateData(const int64_t formId, const std::string &data) +{ + APP_LOGI("update cache data"); + std::lock_guard lock(cacheMutex_); + auto formData = cacheData_.find(formId); + if (formData == cacheData_.end()) { + APP_LOGE("cache data is not exist"); + return false; + } + + formData->second = data; + return true; +} +/** + * @brief Check if form data is exist or not. + * @param formId, Form id. + * @return Returns true if this function is successfully called; returns false otherwise. + */ +bool FormCacheMgr::IsExist(const int64_t formId) const +{ + APP_LOGI("get cache data"); + std::lock_guard lock(cacheMutex_); + if (cacheData_.empty()) { + APP_LOGE("form cache is empty"); + return false; + } + auto formData = cacheData_.find(formId); + if (formData == cacheData_.end()) { + APP_LOGE("cache data not find"); + return false; + } + + return true; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/formmgr/src/form_cast_temp_connection.cpp b/services/formmgr/src/form_cast_temp_connection.cpp new file mode 100644 index 0000000000..e1c46519cd --- /dev/null +++ b/services/formmgr/src/form_cast_temp_connection.cpp @@ -0,0 +1,54 @@ + +/* + * Copyright (c) 2021 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 "appexecfwk_errors.h" +#include "app_log_wrapper.h" +#include "form_cast_temp_connection.h" +#include "form_constants.h" +#include "form_supply_callback.h" +#include "form_task_mgr.h" +#include "ipc_types.h" +#include "message_parcel.h" + +namespace OHOS { +namespace AppExecFwk { +FormCastTempConnection::FormCastTempConnection(const int64_t formId) + :formId_(formId) +{ +} +/** + * @brief OnAbilityConnectDone, AbilityMs notify caller ability the result of connect. + * @param element service ability's ElementName. + * @param remoteObject the session proxy of service ability. + * @param resultCode ERR_OK on success, others on failure. + */ +void FormCastTempConnection::OnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) +{ + APP_LOGI("%{public}s called.", __func__); + if (resultCode != ERR_OK) { + APP_LOGE("%{public}s, abilityName:%{public}s, formId:%{public}lld, resultCode:%{public}d", + __func__, element.GetAbilityName().c_str(), formId_, resultCode); + return; + } + FormSupplyCallback::GetInstance()->AddConnection(this); + + Want want; + want.SetParam(Constants::FORM_CONNECT_ID, this->GetConnectId()); + FormTaskMgr::GetInstance().PostCastTempTask(formId_, want, remoteObject); +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/formmgr/src/form_data_mgr.cpp b/services/formmgr/src/form_data_mgr.cpp new file mode 100644 index 0000000000..9a3518a81f --- /dev/null +++ b/services/formmgr/src/form_data_mgr.cpp @@ -0,0 +1,1126 @@ +/* + * Copyright (c) 2021 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 "appexecfwk_errors.h" +#include "app_log_wrapper.h" +#include "form_cache_mgr.h" +#include "form_constants.h" +#include "form_data_mgr.h" +#include "form_provider_mgr.h" +#include "form_util.h" +#include "ipc_skeleton.h" + + +namespace OHOS { +namespace AppExecFwk { +FormDataMgr::FormDataMgr() +{ + APP_LOGI("create form data manager instance"); + udidHash_ = 0L; +} +FormDataMgr::~FormDataMgr() +{ + APP_LOGI("destroy form data manager instance"); +} + +/** + * @brief Delete form js info by form record. + * @return Returns all form records map. + */ +std::map& FormDataMgr::GetAllFormRecord() +{ + return formRecords_; +} + +/** + * @brief Get all form client host record. + * @return Returns all form client host record. + */ +std::vector& FormDataMgr::GetClientRecords() +{ + return clientRecords_; +} + +/** + * @brief Get all form host records. + * @return Returns all form host records vector. + */ +std::vector& FormDataMgr::GetAllFormHostRecord() +{ + return clientRecords_; +} +/** + * @brief Allot form info by item info. + * @param formId The Id of the form. + * @param formInfo Form item info. + * @param callingUid The UID of the proxy. + * @return Returns form record. + */ +FormRecord FormDataMgr::AllotFormRecord(const FormItemInfo &formInfo, const int callingUid) +{ + APP_LOGI("%{public}s, allot form info", __func__); + if (formInfo.IsTemporaryForm() && !ExistTempForm(formInfo.GetFormId())) { + std::lock_guard lock(formTempMutex_); + tempForms_.emplace_back(formInfo.GetFormId()); + } + FormRecord record; + { + std::lock_guard lock(formRecordMutex_); + if (formRecords_.empty()) { // formRecords_ is empty, create a new one + APP_LOGD("%{public}s, form info not exist", __func__); + record = CreateFormRecord(formInfo, callingUid); + formRecords_.emplace(formInfo.GetFormId(), record); + } else { + auto info = formRecords_.find(formInfo.GetFormId()); + if (info == formRecords_.end()) { + APP_LOGD("%{public}s, form info not find", __func__); + record = CreateFormRecord(formInfo, callingUid); + formRecords_.emplace(formInfo.GetFormId(), record); + } else { + record = info->second; + } + } + } + APP_LOGI("%{public}s end", __func__); + return record; +} +/** + * @brief Delete form js info by form record. + * @param formId The Id of the form. + * @return Returns true if this function is successfully called; returns false otherwise. + */ +bool FormDataMgr::DeleteFormRecord(const int64_t formId) { + APP_LOGI("%{public}s, delete form info", __func__); + std::lock_guard lock(formRecordMutex_); + auto iter = formRecords_.find(formId); + if (iter == formRecords_.end()) { + APP_LOGE("%{public}s, form info is not exist", __func__); + return true; + } + formRecords_.erase(iter); + return true; +} +/** + * @brief Allot form host record by caller token. + * @param info The form item info. + * @param callerToken callerToken + * @param formId The Id of the form. + * @param callingUid The UID of the proxy. + * @param record Form host record. + * @return Returns true if this function is successfully called; returns false otherwise. + */ +bool FormDataMgr::AllotFormHostRecord(const FormItemInfo &info, const sptr &callerToken, + const int64_t formId, const int callingUid) +{ + APP_LOGI("%{public}s, allot form Host info", __func__); + std::lock_guard lock(formHostRecordMutex_); + for (auto &record : clientRecords_) { + if (callerToken == record.GetClientStub()) { + record.AddForm(formId); + APP_LOGI("%{public}s end", __func__); + return true; + } + } + FormHostRecord hostRecord; + bool isCreated = CreateHostRecord(info, callerToken, callingUid, hostRecord); + if (isCreated) { + hostRecord.AddForm(formId); + clientRecords_.emplace_back(hostRecord); + APP_LOGI("%{public}s end", __func__); + return true; + } + APP_LOGI("%{public}s end", __func__); + return false; +} +/** + * @brief Create host record. + * @param info The form item info. + * @param callerToken The UID of the proxy. + * @param callingUid The UID of the proxy. + * @param record The form host record. + * @return Returns true if this function is successfully called; returns false otherwise. + */ +bool FormDataMgr::CreateHostRecord(const FormItemInfo &info, const sptr &callerToken, + const int callingUid, FormHostRecord& record) { + if (callerToken == nullptr) { + APP_LOGE("%{public}s, invalid param", __func__); + return false; + } + + record = FormHostRecord::CreateRecord(info, callerToken, callingUid); + return true; +} +/** + * @brief Create form record. + * @param formInfo The form item info. + * @param callingUid The UID of the proxy. + * @return Form record. + */ +FormRecord FormDataMgr::CreateFormRecord(const FormItemInfo &formInfo, const int callingUid) const +{ + APP_LOGI("%{public}s, create form info", __func__); + FormRecord newRecord; + newRecord.formId = formInfo.GetFormId(); + newRecord.packageName = formInfo.GetPackageName(); + newRecord.bundleName = formInfo.GetProviderBundleName(); + newRecord.moduleName = formInfo.GetModuleName(); + newRecord.abilityName = formInfo.GetAbilityName(); + newRecord.formName = formInfo.GetFormName(); + newRecord.specification = formInfo.GetSpecificationId(); + newRecord.isEnableUpdate = formInfo.IsEnableUpdateFlag(); + newRecord.formTempFlg = formInfo.IsTemporaryForm(); + newRecord.formVisibleNotify = formInfo.IsFormVisibleNotify(); + newRecord.jsFormCodePath = formInfo.GetHapSourceByModuleName(newRecord.moduleName); + if (newRecord.isEnableUpdate) { + ParseUpdateConfig(newRecord, formInfo); + } + if (std::find(newRecord.formUserUids.begin(), newRecord.formUserUids.end(), + callingUid) == newRecord.formUserUids.end()) { + newRecord.formUserUids.emplace_back(callingUid); + } + + formInfo.GetHapSourceDirs(newRecord.hapSourceDirs); + APP_LOGI("%{public}s end", __func__); + return newRecord; +} +/** + * @brief Create form js info by form record. + * @param formId The Id of the form. + * @param record Form record. + * @param formInfo Js info. + * @return None. + */ +void FormDataMgr::CreateFormInfo(const int64_t formId, const FormRecord &record, FormJsInfo &formInfo) +{ + formInfo.formId = formId; + formInfo.bundleName = record.bundleName; + formInfo.abilityName = record.abilityName; + formInfo.formName = record.formName; + formInfo.formTempFlg = record.formTempFlg; + // formInfo.setInstantProvider(record.instantProvider); +} +/** + * @brief Check temp form count is max. + * @return Returns ERR_OK if the temp form not reached; returns ERR_MAX_SYSTEM_TEMP_FORMS is reached. + */ +int FormDataMgr::CheckTempEnoughForm() const +{ + if (tempForms_.size() >= Constants::MAX_TEMP_FORMS) { + APP_LOGW("%{public}s, already exist %{public}d temp forms in system", __func__, Constants::MAX_TEMP_FORMS); + // HiViewUtil.sendAddFormExceedLimitEvent(); + return ERR_MAX_SYSTEM_TEMP_FORMS; + } + return ERR_OK; +} +/** + * @brief Check form count is max. + * @param callingUid The UID of the proxy. + * @return Returns true if this function is successfully called; returns false otherwise. + */ +int FormDataMgr::CheckEnoughForm(const int callingUid) const +{ + APP_LOGI("%{public}s, callingUid: %{public}d", __func__, callingUid); + + if (formRecords_.size() - tempForms_.size() >= Constants::MAX_FORMS) { + APP_LOGW("%{public}s, already exist %{public}d forms in system", __func__, Constants::MAX_FORMS); + return ERR_MAX_SYSTEM_FORMS; + } + + int callingUidFormCounts = 0; + for (auto &recordPair : formRecords_) { + FormRecord record = recordPair.second; + if (IsCallingUidValid(record.formUserUids) && !record.formTempFlg) { + for (auto &userUid : record.formUserUids) { + if (userUid == callingUid) { + if (++callingUidFormCounts >= Constants::MAX_RECORD_PER_APP) + { + APP_LOGW("%{public}s, already use %{public}d forms", __func__, Constants::MAX_RECORD_PER_APP); + return ERR_MAX_RECORDS_PER_APP; + } + } + } + } + } + return ERR_OK; +} +/** + * @brief Delete temp form. + * @param formId The Id of the form. + * @return Returns true if this function is successfully called; returns false otherwise. + */ +bool FormDataMgr::DeleteTempForm(const int64_t formId) +{ + std::lock_guard lock(formTempMutex_); + auto iter = std::find(tempForms_.begin(), tempForms_.end(), formId); + if (iter == tempForms_.end()) { + APP_LOGE("%{public}s, temp form is not exist", __func__); + return true; + } + tempForms_.erase(iter); + return true; +} +/** + * @brief Check temp form is exist. + * @param formId The Id of the form. + * @return Returns true if the temp form is exist; returns false is not exist. + */ +bool FormDataMgr::ExistTempForm(const int64_t formId) const +{ + return (std::find(tempForms_.begin(), tempForms_.end(), formId) != tempForms_.end()); +} +/** + * @brief Check calling uid is valid. + * @param formUserUids The form user uids. + * @return Returns true if this user uid is valid; returns false otherwise. + */ +bool FormDataMgr::IsCallingUidValid(const std::vector &formUserUids) const +{ + if (formUserUids.size() != 0) { + for (auto &userUid : formUserUids) { + if (userUid == IPCSkeleton::GetCallingUid()) { + return true; + } + } + } + return false; +} +/** + * @brief Modify form temp flag by formId. + * @param formId The Id of the form. + * @param formTempFlg The form temp flag. + * @return Returns true if this function is successfully called; returns false otherwise. + */ +bool FormDataMgr::ModifyFormTempFlg(const int64_t formId, const bool formTempFlg) +{ + APP_LOGI("%{public}s, modify form temp flag by formId", __func__); + std::lock_guard lock(formRecordMutex_); + if (!ExistFormRecord(formId)) { + APP_LOGE("%{public}s, form info is not exist", __func__); + return false; + } + formRecords_[formId].formTempFlg = formTempFlg; + return true; +} +/** + * @brief Add form user uid from form record. + * @param formId The Id of the form. + * @param formRecord The form record. + * @return Returns true if this function is successfully called; returns false otherwise. + */ +bool FormDataMgr::AddFormUserUid(const int64_t formId, const int32_t formUserUid) +{ + APP_LOGI("%{public}s, add form user uid by formId", __func__); + std::lock_guard lock(formRecordMutex_); + if (!ExistFormRecord(formId)) { + APP_LOGE("%{public}s, form info is not exist", __func__); + return false; + } + if (std::find(formRecords_[formId].formUserUids.begin(), formRecords_[formId].formUserUids.end(), + formUserUid) == formRecords_[formId].formUserUids.end()) { + formRecords_[formId].formUserUids.emplace_back(formUserUid); + } + return true; +} +/** + * @brief Delete form user uid from form record. + * @param formId The Id of the form. + * @param uid calling user id. + * @return Returns true if this function is successfully called; returns false otherwise. + */ +bool FormDataMgr::DeleteFormUserUid(const int64_t formId, const int32_t uid) +{ + APP_LOGI("%{public}s, delete form user uid from form record", __func__); + std::lock_guard lock(formRecordMutex_); + if (ExistFormRecord(formId)) { + auto iter = std::find(formRecords_.at(formId).formUserUids.begin(), formRecords_.at(formId).formUserUids.end(), + uid); + if (iter != formRecords_.at(formId).formUserUids.end()) { + formRecords_.at(formId).formUserUids.erase(iter); + } + return true; + } else { + APP_LOGE("%{public}s, form info not find", __func__); + return false; + } +} +/** + * @brief Update form record. + * @param formId The Id of the form. + * @param formRecord The form record. + * @return Returns true if this function is successfully called; returns false otherwise. + */ +bool FormDataMgr::UpdateFormRecord(const int64_t formId, const FormRecord &formRecord) +{ + APP_LOGI("%{public}s, get form record by formId", __func__); + std::lock_guard lock(formRecordMutex_); + auto info = formRecords_.find(formId); + if (info != formRecords_.end()) { + formRecords_[formId] = formRecord; + return true; + } + return false; +} +/** + * @brief Get form record. + * @param formId The Id of the form. + * @param formRecord The form record. + * @return Returns true if this function is successfully called; returns false otherwise. + */ +bool FormDataMgr::GetFormRecord(const int64_t formId, FormRecord &formRecord) const +{ + APP_LOGI("%{public}s, get form record by formId", __func__); + std::lock_guard lock(formRecordMutex_); + auto info = formRecords_.find(formId); + if (info == formRecords_.end()) { + APP_LOGE("%{public}s, form info not find", __func__); + return false; + } + formRecord = info->second; + + APP_LOGI("%{public}s, get form record successfully", __func__); + return true; +} +/** + * @brief Get form record. + * @param bundleName Bundle name. + * @param formInfos The form record. + * @return Returns true if this function is successfully called; returns false otherwise. + */ +bool FormDataMgr::GetFormRecord(const std::string &bundleName, std::vector &formInfos) +{ + APP_LOGI("%{public}s, get form record by bundleName", __func__); + std::lock_guard lock(formRecordMutex_); + std::map::iterator itFormRecord; + for (itFormRecord = formRecords_.begin(); itFormRecord != formRecords_.end();itFormRecord++) { + if (bundleName == itFormRecord->second.bundleName) { + formInfos.emplace_back(itFormRecord->second); + } + } + if (formInfos.size() > 0) { + return true; + } else { + APP_LOGI("%{public}s, form info not find", __func__); + return false; + } +} +/** + * @brief Check form record is exist. + * @param formId The Id of the form. + * @return Returns true if the form record is exist; returns false is not exist. + */ +bool FormDataMgr::ExistFormRecord(const int64_t formId) const +{ + APP_LOGI("%{public}s, check form record is exist", __func__); + return (formRecords_.count(formId) > 0); +} +/** + * @brief Has form user uids in form record. + * @param formId The Id of the form. + * @return Returns true if this form has form user uids; returns false is not has. + */ +bool FormDataMgr::HasFormUserUids(const int64_t formId) const +{ + APP_LOGI("%{public}s, check form has user uids", __func__); + FormRecord record; + if (GetFormRecord(formId, record)) { + return record.formUserUids.empty() ? false : true; + } + return false; +} +/** + * @brief Get form host record. + * @param formId The id of the form. + * @param formHostRecord The form host record. + * @return Returns true if this function is successfully called; returns false otherwise. + */ +bool FormDataMgr::GetFormHostRecord(const int64_t formId, FormHostRecord &formHostRecord) const +{ + APP_LOGI("%{public}s, get form host record by formId", __func__); + std::lock_guard lock(formHostRecordMutex_); + for (auto &record : clientRecords_) { + if (record.Contains(formId)) { + formHostRecord = record; + return true; + } + } + + APP_LOGE("%{public}s, form host record not find", __func__); + return false; +} +/** + * @brief Delete form host record. + * @param callerToken The client stub of the form host record. + * @param formId The id of the form. + * @return Returns true if this function is successfully called; returns false otherwise. + */ +bool FormDataMgr::DeleteHostRecord(const sptr &callerToken, const int64_t formId) +{ + APP_LOGI("%{public}s start, delete form host record", __func__); + std::lock_guard lock(formHostRecordMutex_); + std::vector::iterator iter; + for (iter = clientRecords_.begin(); iter != clientRecords_.end(); ++iter) { + if (callerToken == iter->GetClientStub()) { + iter->DelForm(formId); + if (iter->IsEmpty()) { + iter->CleanResource(); + iter = clientRecords_.erase(iter); + } + break; + } + } + APP_LOGI("%{public}s end", __func__); + return true; +} +/** + * @brief Clean removed forms form host. + * @param removedFormIds The id list of the forms. + */ +void FormDataMgr::CleanHostRemovedForms(const std::vector &removedFormIds) +{ + APP_LOGI("%{public}s start, delete form host record by formId list", __func__); + std::vector matchedIds; + std::lock_guard lock(formHostRecordMutex_); + std::vector::iterator itHostRecord; + for (itHostRecord = clientRecords_.begin(); itHostRecord != clientRecords_.end();itHostRecord++) { + for (const int64_t& formId : removedFormIds) { + if (itHostRecord->Contains(formId)) { + matchedIds.emplace_back(formId); + itHostRecord->DelForm(formId); + } + } + if (!matchedIds.empty()) { + APP_LOGI("%{public}s, OnFormUninstalled called", __func__); + itHostRecord->OnFormUninstalled(matchedIds); + } + } + + APP_LOGI("%{public}s end", __func__); +} +/** + * @brief Handle form host died. + * @param remoteHost Form host proxy object. + */ +void FormDataMgr::HandleHostDied(const sptr &remoteHost) +{ + std::vector recordTempForms; + { + std::lock_guard lock(formHostRecordMutex_); + std::vector::iterator itHostRecord; + for (itHostRecord = clientRecords_.begin(); itHostRecord != clientRecords_.end();) { + if (remoteHost == itHostRecord->GetClientStub()) { + HandleHostDiedForTempForms(*itHostRecord, recordTempForms); + APP_LOGI("find died client, remove it"); + itHostRecord->CleanResource(); + itHostRecord = clientRecords_.erase(itHostRecord); + break; + } else { + itHostRecord++; + } + } + } + { + std::lock_guard lock(formRecordMutex_); + std::map::iterator itFormRecord; + for (itFormRecord = formRecords_.begin(); itFormRecord != formRecords_.end();) { + int64_t formId = itFormRecord->first; + // if temp form, remove it + if (std::find(recordTempForms.begin(), recordTempForms.end(), formId) != recordTempForms.end()) { + FormRecord formRecord = itFormRecord->second; + itFormRecord = formRecords_.erase(itFormRecord); + FormProviderMgr::GetInstance().NotifyProviderFormDelete(formId, formRecord); + } else { + itFormRecord++; + } + } + } +} + +/** + * @brief Get the temp forms from host and delete temp form in cache. + * @param record The form record. + * @param recordTempForms Getted the temp forms. + */ +void FormDataMgr::HandleHostDiedForTempForms(const FormHostRecord &record, std::vector &recordTempForms) +{ + std::lock_guard lock(formTempMutex_); + std::vector::iterator itForm; + for (itForm = tempForms_.begin(); itForm != tempForms_.end();) { + if (record.Contains(*itForm)) { + recordTempForms.emplace_back(*itForm); + itForm = tempForms_.erase(itForm); + } else { + itForm++; + } + } +} + +/** + * @brief Refresh enable or not. + * @param formId The Id of the form. + * @return true on enbale, false on disable. + */ +bool FormDataMgr::IsEnableRefresh(int64_t formId) +{ + std::lock_guard lock(formHostRecordMutex_); + for (auto &record : clientRecords_) { + if (record.IsEnableRefresh(formId)) { + return true; + } + } + + return false; +} +/** + * @brief Generate form id. + * @return form id. + */ +int64_t FormDataMgr::GenerateFormId() +{ + return FormUtil::GenerateFormId(udidHash_); +} +/** + * @brief Generate udid. + * @return Returns true if this function is successfully called; returns false otherwise. + */ +bool FormDataMgr::GenerateUdidHash() +{ + if (udidHash_ != Constants::INVALID_UDID_HASH) { + return true; + } + + bool bGenUdid = FormUtil::GenerateUdidHash(udidHash_); + if (!bGenUdid) { + APP_LOGE("%{public}s, Failed to generate udid.", __func__); + return false; + } + + return true; +} +/** + * @brief Get udid. + * @return udid. + */ +int64_t FormDataMgr::GetUdidHash() const +{ + return udidHash_; +} +/** + * @brief Set udid. + * @param udidHash udid. + */ +void FormDataMgr::SetUdidHash(const int64_t udidHash) +{ + udidHash_ = udidHash; +} + +/** + * @brief Get the matched form host record by client stub. + * + * @param callerToken The client stub of the form host record. + * @param formHostRecord The form host record. + * @return Returns true if this function is successfully called, returns false otherwise. + */ +bool FormDataMgr::GetMatchedHostClient(const sptr &callerToken, FormHostRecord &formHostRecord) const +{ + APP_LOGI("%{public}s, get the matched form host record by client stub.", __func__); + std::lock_guard lock(formHostRecordMutex_); + for (const FormHostRecord &record : clientRecords_) { + if (callerToken == record.GetClientStub()) { + formHostRecord = record; + return true; + } + } + + APP_LOGE("%{public}s, form host record not find.", __func__); + return false; +} + +/** + * @brief Set needRefresh for FormRecord. + * @param formId The Id of the form. + * @param needRefresh true or false. + */ +void FormDataMgr::SetNeedRefresh(const int64_t formId, const bool needRefresh) +{ + std::lock_guard lock(formRecordMutex_); + auto itFormRecord = formRecords_.find(formId); + if (itFormRecord == formRecords_.end()) { + APP_LOGE("%{public}s, form info not find", __func__); + return; + } + itFormRecord->second.needRefresh = needRefresh; +} + +/** + * @brief Set isCountTimerRefresh for FormRecord. + * @param formId The Id of the form. + * @param countTimerRefresh true or false. + */ +void FormDataMgr::SetCountTimerRefresh(const int64_t formId, const bool countTimerRefresh) +{ + std::lock_guard lock(formRecordMutex_); + auto itFormRecord = formRecords_.find(formId); + if (itFormRecord == formRecords_.end()) { + APP_LOGE("%{public}s, form info not find", __func__); + return; + } + itFormRecord->second.isCountTimerRefresh = countTimerRefresh; +} + +/** + * @brief Get updated form. + * @param record FormRecord. + * @param targetForms Target forms. + * @param updatedForm Updated formnfo. + * @return Returns true on success, false on failure. + */ +bool FormDataMgr::GetUpdatedForm(const FormRecord &record, const std::vector &targetForms, +FormInfo &updatedForm) +{ + if (targetForms.empty()) { + APP_LOGE("%{public}s error, targetForms is empty.", __func__); + return false; + } + + for (const FormInfo &item : targetForms) { + if (IsSameForm(record, item)) { + updatedForm = item; + APP_LOGD("%{public}s, find matched form.", __func__); + return true; + } + } + return false; +} +/** + * @brief Set isEnableUpdate for FormRecord. + * @param formId The Id of the form. + * @param enableUpdate true or false. + */ +void FormDataMgr::SetEnableUpdate(const int64_t formId, const bool enableUpdate) +{ + std::lock_guard lock(formRecordMutex_); + auto itFormRecord = formRecords_.find(formId); + if (itFormRecord == formRecords_.end()) { + APP_LOGE("%{public}s, form info not find", __func__); + return; + } + itFormRecord->second.isEnableUpdate = enableUpdate; +} +/** + * @brief Set update info for FormRecord. + * @param formId The Id of the form. + * @param enableUpdate true or false. + * @param updateDuration Update duration. + * @param updateAtHour Update at hour. + * @param updateAtMin Update at minute. + */ +void FormDataMgr::SetUpdateInfo(const int64_t formId, const bool enableUpdate, const long updateDuration, +const int updateAtHour, const int updateAtMin) +{ + std::lock_guard lock(formRecordMutex_); + auto itFormRecord = formRecords_.find(formId); + if (itFormRecord == formRecords_.end()) { + APP_LOGE("%{public}s, form info not find", __func__); + return; + } + + itFormRecord->second.isEnableUpdate = enableUpdate; + itFormRecord->second.updateDuration = updateDuration; + itFormRecord->second.updateAtHour = updateAtHour; + itFormRecord->second.updateAtMin = updateAtMin; +} +/** + * @brief Check if two forms is same or not. + * @param record FormRecord. + * @param formInfo FormInfo. + * @return Returns true on success, false on failure. + */ +bool FormDataMgr::IsSameForm(const FormRecord &record, const FormInfo &formInfo) +{ + if (record.bundleName == formInfo.bundleName + && record.moduleName == formInfo.moduleName + && record.abilityName == formInfo.abilityName + && record.formName == formInfo.name + && std::find(formInfo.supportDimensions.begin(), formInfo.supportDimensions.end(), record.specification) + != formInfo.supportDimensions.end()) { + return true; + } + + return false; +} +/** + * @brief Clean removed form records. + * @param removedForms The id list of the forms. + */ +void FormDataMgr::CleanRemovedFormRecords(const std::string &bundleName, std::set &removedForms) +{ + APP_LOGI("%{public}s, clean removed form records", __func__); + std::lock_guard lock(formRecordMutex_); + std::map::iterator itFormRecord; + for (itFormRecord = formRecords_.begin(); itFormRecord != formRecords_.end();) { + auto itForm = std::find(removedForms.begin(), removedForms.end(), itFormRecord->first); + if (itForm != removedForms.end()) { + itFormRecord = formRecords_.erase(itFormRecord); + } + else { + itFormRecord++; + } + } +} +/** + * @brief Clean removed temp form records. + * @param bundleName BundleName. + * @param removedForms The id list of the forms. + */ +void FormDataMgr::CleanRemovedTempFormRecords(const std::string &bundleName, std::set &removedForms) +{ + APP_LOGI("%{public}s, clean removed form records", __func__); + std::set removedTempForms; + { + std::lock_guard lock(formRecordMutex_); + std::map::iterator itFormRecord; + for (itFormRecord = formRecords_.begin(); itFormRecord != formRecords_.end();) { + if (itFormRecord->second.formTempFlg && bundleName == itFormRecord->second.bundleName) { + removedTempForms.emplace(itFormRecord->second.formId); + itFormRecord = formRecords_.erase(itFormRecord); + } + else { + itFormRecord++; + } + } + } + + if (removedTempForms.size() > 0) { + std::lock_guard lock(formTempMutex_); + std::vector::iterator itTemp; + for(itTemp = tempForms_.begin();itTemp != tempForms_.end();) { + if(removedTempForms.find(*itTemp) != removedTempForms.end()) { + itTemp = tempForms_.erase(itTemp); + } else { + itTemp++; + } + } + removedForms.merge(removedTempForms); + } +} +/** + * @brief Get recreate form records. + * @param reCreateForms The id list of the forms. + */ +void FormDataMgr::GetReCreateFormRecordsByBundleName(const std::string &bundleName, std::set &reCreateForms) +{ + std::lock_guard lock(formRecordMutex_); + std::map::iterator itFormRecord; + for (itFormRecord = formRecords_.begin(); itFormRecord != formRecords_.end();itFormRecord++) { + if (bundleName == itFormRecord->second.bundleName) { + reCreateForms.emplace(itFormRecord->second.formId); + } + } +} +/** + * @brief Set form isInited = true. + * @param formId The Id of the form. + * @param isInited isInited property + */ +void FormDataMgr::SetFormCacheInited(const int64_t formId, bool isInited) +{ + std::lock_guard lock(formRecordMutex_); + auto itFormRecord = formRecords_.find(formId); + if (itFormRecord == formRecords_.end()) { + APP_LOGE("%{public}s, form info not find", __func__); + return; + } + itFormRecord->second.isInited = isInited; + itFormRecord->second.needRefresh = !isInited; +} +/** + * @brief Set versionUpgrade. + * @param formId The Id of the form. + * @param versionUpgrade true or false + */ +void FormDataMgr::SetVersionUpgrade(const int64_t formId, const bool versionUpgrade) +{ + std::lock_guard lock(formRecordMutex_); + auto itFormRecord = formRecords_.find(formId); + if (itFormRecord == formRecords_.end()) { + APP_LOGE("%{public}s, form info not find", __func__); + return; + } + itFormRecord->second.versionUpgrade = versionUpgrade; +} +/** + * @brief Update form for host clients. + * @param formId The Id of the form. + * @param needRefresh true or false + */ +void FormDataMgr::UpdateHostNeedRefresh(const int64_t formId, const bool needRefresh) +{ + std::lock_guard lock(formHostRecordMutex_); + std::vector::iterator itHostRecord; + for (itHostRecord = clientRecords_.begin(); itHostRecord != clientRecords_.end();itHostRecord++) { + if (itHostRecord->Contains(formId)) { + itHostRecord->SetNeedRefresh(formId, needRefresh); + } + } +} +/** + * @brief Update form for host clients. + * @param formId The Id of the form. + * @param formRecord The form info. + * @return Returns true if form update, false if other. + */ +bool FormDataMgr::UpdateHostForm(const int64_t formId, const FormRecord &formRecord) +{ + bool isUpdated = false; + std::lock_guard lock(formHostRecordMutex_); + std::vector::iterator itHostRecord; + for (itHostRecord = clientRecords_.begin(); itHostRecord != clientRecords_.end();itHostRecord++) { + if (itHostRecord->IsEnableRefresh(formId)) { + // update form + itHostRecord->OnUpdate(formId, formRecord); + // set needRefresh + itHostRecord->SetNeedRefresh(formId, false); + isUpdated = true; + } + } + return isUpdated; +} +/** + * @brief handle update form flag. + * @param formIDs The id of the forms. + * @param callerToken Caller ability token. + * @param flag form flag. + * @param refreshForms Refresh forms + * @return Returns ERR_OK on success, others on failure. + */ +int32_t FormDataMgr::UpdateHostFormFlag(std::vector formIds, const sptr &callerToken, +const bool flag, std::vector &refreshForms) +{ + APP_LOGI("%{public}s start, flag: %{public}d", __func__, flag); + std::lock_guard lock(formHostRecordMutex_); + std::vector::iterator itHostRecord; + for (itHostRecord = clientRecords_.begin(); itHostRecord != clientRecords_.end();itHostRecord++) { + if (callerToken == itHostRecord->GetClientStub()) { + for (const int64_t formId : formIds) { + if (formId <= 0) { + APP_LOGW("%{public}s, formId %{public}lld is less than 0", __func__, formId); + continue; + } + + int64_t matchedFormId = FindMatchedFormId(formId); + if (!itHostRecord->Contains(matchedFormId)) { + APP_LOGW("%{public}s, form %{public}lld is not owned by this client, don't need to update flag", + __func__, formId); + continue; + } + + itHostRecord->SetEnableRefresh(matchedFormId, flag); + // set disable + if (!flag) { + APP_LOGI("%{public}s, flag is disable", __func__); + continue; + } + FormRecord formRecord; + if (GetFormRecord(matchedFormId, formRecord)) { + if (formRecord.needRefresh) { + APP_LOGI("%{public}s, formRecord need refresh", __func__); + refreshForms.emplace_back(matchedFormId); + continue; + } + } else { + APP_LOGW("%{public}s, not exist such form:%{public}lld", __func__, matchedFormId); + continue; + } + + // if set enable flag, should check whether to refresh form + if (!itHostRecord->IsNeedRefresh(matchedFormId)) { + APP_LOGI("%{public}s, host need not refresh", __func__); + continue; + } + + if (IsFormCached(formRecord)) { + APP_LOGI("%{public}s, form cached", __func__); + itHostRecord->OnUpdate(matchedFormId, formRecord); + itHostRecord->SetNeedRefresh(matchedFormId, false); + } else { + APP_LOGI("%{public}s, form no cache", __func__); + refreshForms.emplace_back(matchedFormId); + continue; + } + } + APP_LOGI("%{public}s end.", __func__); + return ERR_OK; + } + } + APP_LOGE("%{public}s, can't find target client", __func__); + return ERR_FORM_INVALID_PARAM; +} +/** + * @brief Find matched form id. + * @param formId The form id. + * @return Matched form id. + */ +int64_t FormDataMgr::FindMatchedFormId(const int64_t formId) +{ + if ((formId & 0xffffffff00000000L) != 0) { + return formId; + } + std::lock_guard lock(formRecordMutex_); + std::map::iterator itFormRecord; + for (itFormRecord = formRecords_.begin(); itFormRecord != formRecords_.end();itFormRecord++) { + if ((itFormRecord->first & 0x00000000ffffffffL) == (formId & 0x00000000ffffffffL)) { + return itFormRecord->first; + } + } + return formId; +} + +/** + * @brief Clear host data by uId. + * @param uId The caller uId. + */ +void FormDataMgr::ClearHostDataByUId(const int uId) +{ + std::lock_guard lock(formHostRecordMutex_); + std::vector::iterator itHostRecord; + for (itHostRecord = clientRecords_.begin(); itHostRecord != clientRecords_.end();) { + if (itHostRecord->GetCallerUid() == uId) { + itHostRecord->CleanResource(); + itHostRecord = clientRecords_.erase(itHostRecord); + } else { + itHostRecord++; + } + } +} +/** + * @brief Get no host temp forms. + * @param uid The caller uid. + * @param noHostTempFormsMap no host temp forms. + * @param foundFormsMap Form Id list. + */ +void FormDataMgr::GetNoHostTempForms(const int uid, std::map> &noHostTempFormsMap, +std::map &foundFormsMap) +{ + std::lock_guard lock(formRecordMutex_); + std::map::iterator itFormRecord; + for (itFormRecord = formRecords_.begin(); itFormRecord != formRecords_.end();itFormRecord++) { + if (itFormRecord->second.formTempFlg) { + auto itUid = std::find(itFormRecord->second.formUserUids.begin(), itFormRecord->second.formUserUids.end(), + uid); + if (itUid != itFormRecord->second.formUserUids.end()) { + itFormRecord->second.formUserUids.erase(itUid); + if (itFormRecord->second.formUserUids.empty()) { + FormIdKey formIdKey; + formIdKey.bundleName = itFormRecord->second.bundleName; + formIdKey.abilityName = itFormRecord->second.abilityName; + auto itIdsSet = noHostTempFormsMap.find(formIdKey); + if (itIdsSet == noHostTempFormsMap.end()) { + std::set formIdsSet; + formIdsSet.emplace(itFormRecord->second.formId); + noHostTempFormsMap.emplace(formIdKey, formIdsSet); + } else { + itIdsSet->second.emplace(itFormRecord->second.formId); + } + } + } else { + foundFormsMap.emplace(itFormRecord->second.formId, false); + } + } + } +} +/** + * @brief Parse update config. + * @param record The form record. + * @param info The form item info. + */ +void FormDataMgr::ParseUpdateConfig(FormRecord &record, const FormItemInfo &info) const +{ + int configDuration = info.GetUpdateDuration(); + if (configDuration > 0) { + ParseIntervalConfig(record, configDuration); + } else { + ParseAtTimerConfig(record, info); + } +} + +/** + * @brief Parse update interval config. + * @param record The form record. + * @param configDuration interval duration. + */ +void FormDataMgr::ParseIntervalConfig(FormRecord &record, const int configDuration) const +{ + APP_LOGI("%{public}s, configDuration:%{public}d", __func__, configDuration); + if (configDuration <= Constants::MIN_CONFIG_DURATION) { + record.updateDuration = Constants::MIN_PERIOD; + } else if (configDuration >= Constants::MAX_CONFIG_DURATION) { + record.updateDuration = Constants::MAX_PERIOD; + } else { + record.updateDuration = configDuration * Constants::TIME_CONVERSION; + } + APP_LOGI("%{public}s end", __func__); +} +/** + * @brief Parse at time config. + * @param record The form record. + * @param info form item info. + */ +void FormDataMgr::ParseAtTimerConfig(FormRecord record, const FormItemInfo &info) const { + record.isEnableUpdate = false; + record.updateDuration = 0; + std::string configAtTime = info.GetScheduledUpdateTime(); + APP_LOGI("%{public}s, parseAsUpdateAt updateAt:%{public}s", __func__, configAtTime.c_str()); + if (configAtTime.empty()) { + return; + } + + std::vector temp = FormUtil::StringSplit(configAtTime, Constants::TIME_DELIMETER); + if (temp.size() != Constants::UPDATE_AT_CONFIG_COUNT) { + APP_LOGE("%{public}s, invalid config", __func__); + return; + } + int hour = -1; + int min = -1; + try { + hour = std::stoi(temp[0]); + min = std::stoi(temp[1]); + } catch (const std::exception& e) { + APP_LOGE("%{public}s, failed to stoi.", __func__); + } + + if (hour < Constants::MIN_TIME || hour > Constants::MAX_HOUR || min < Constants::MIN_TIME || min > + Constants::MAX_MININUTE) { + APP_LOGE("%{public}s, time is invalid", __func__); + return; + } + record.updateAtHour = hour; + record.updateAtMin = min; + record.isEnableUpdate = true; +} +/** + * @brief handle update form flag. + * @param formIDs The id of the forms. + * @param callerToken Caller ability token. + * @param flag form flag. + * @return Returns ERR_OK on success, others on failure. + */ +bool FormDataMgr::IsFormCached(const FormRecord record) +{ + if (record.versionUpgrade) { + return false; + } + return FormCacheMgr::GetInstance().IsExist(record.formId); +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/formmgr/src/form_db_cache.cpp b/services/formmgr/src/form_db_cache.cpp new file mode 100644 index 0000000000..74175adba1 --- /dev/null +++ b/services/formmgr/src/form_db_cache.cpp @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2021 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 "app_log_wrapper.h" +#include "appexecfwk_errors.h" +#include "form_bms_helper.h" +#include "form_db_cache.h" +#include "form_db_info.h" + +namespace OHOS { +namespace AppExecFwk { +FormDbCache::FormDbCache() +{ + APP_LOGI("FormDbCache is created"); + dataStorage_ = std::make_unique(); + formDBInfos_.clear(); +} + +FormDbCache::~FormDbCache() +{ + APP_LOGI("FormDbCache is destroyed"); +} + +/** + * @brief Load form data from DB to DbCache when starting. + * @return Void. + */ +void FormDbCache::Start() +{ + APP_LOGI("%{public}s called.", __func__); + std::lock_guard lock(formDBInfosMutex_); + std::vector innerFormInfos; + innerFormInfos.clear(); + if (dataStorage_->LoadFormData(innerFormInfos) != ERR_OK) { + APP_LOGE("%{public}s, LoadFormData failed.", __func__); + return; + } + + for (unsigned int i = 0; i < innerFormInfos.size(); i++) { + FormDBInfo formDBInfo = innerFormInfos.at(i).GetFormDBInfo(); + formDBInfos_.emplace_back(formDBInfo); + } +} + +// void FormDbCache::Stop() +// { +// APP_LOGI("stop"); +// dataStorage_->Stop(); +// } + +/** + * @brief Save or update form data to DbCache and DB. + * @param formDBInfo Form data. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormDbCache::SaveFormInfo(const FormDBInfo &formDBInfo) +{ + APP_LOGI("%{public}s called, formId:%{public}lld", __func__, formDBInfo.formId); + std::lock_guard lock(formDBInfosMutex_); + auto iter = find(formDBInfos_.begin(), formDBInfos_.end(), formDBInfo); + if (iter != formDBInfos_.end()) { + if (iter->Compare(formDBInfo) == false) { + APP_LOGW("%{public}s, need update, formId[%{public}lld].", __func__, formDBInfo.formId); + *iter = formDBInfo; + InnerFormInfo innerFormInfo(formDBInfo); + return dataStorage_->ModifyStorageFormInfo(innerFormInfo); + } else { + APP_LOGW("%{public}s, already exist, formId[%{public}lld].", __func__, formDBInfo.formId); + return ERR_OK; + } + } else { + formDBInfos_.emplace_back(formDBInfo); + InnerFormInfo innerFormInfo(formDBInfo); + return dataStorage_->SaveStorageFormInfo(innerFormInfo); + } +} + +/** + * @brief Save or update form data to DbCache and DB. + * @param formDBInfo Form data. + * @return Returns ERR_OK on success, others on failure.(NoLock) + */ +ErrCode FormDbCache::SaveFormInfoNolock(const FormDBInfo &formDBInfo) +{ + APP_LOGI("%{public}s called, formId:%{public}lld", __func__, formDBInfo.formId); + auto iter = find(formDBInfos_.begin(), formDBInfos_.end(), formDBInfo); + if (iter != formDBInfos_.end()) { + if (iter->Compare(formDBInfo) == false) { + APP_LOGW("%{public}s, need update, formId[%{public}lld].", __func__, formDBInfo.formId); + *iter = formDBInfo; + InnerFormInfo innerFormInfo(formDBInfo); + return dataStorage_->ModifyStorageFormInfo(innerFormInfo); + } else { + APP_LOGW("%{public}s, already exist, formId[%{public}lld].", __func__, formDBInfo.formId); + return ERR_OK; + } + } else { + formDBInfos_.emplace_back(formDBInfo); + InnerFormInfo innerFormInfo(formDBInfo); + return dataStorage_->SaveStorageFormInfo(innerFormInfo); + } +} + +/** + * @brief Delete form data in DbCache and DB with formId. + * @param formId form data Id. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormDbCache::DeleteFormInfo(int64_t formId) +{ + std::lock_guard lock(formDBInfosMutex_); + FormDBInfo tmpForm; + tmpForm.formId = formId; + auto iter = find(formDBInfos_.begin(), formDBInfos_.end(), tmpForm); + if (iter == formDBInfos_.end()) { + APP_LOGW("%{public}s, not find formId[%{public}lld]", __func__, formId); + } else { + formDBInfos_.erase(iter); + } + if (dataStorage_->DeleteStorageFormInfo(std::to_string(formId)) == ERR_OK) { + return ERR_OK; + } else { + return ERR_APPEXECFWK_FORM_JSON_DELETE_FAIL; + } +} +/** + * @brief Delete form data in DbCache and DB with formId. + * @param formId form data Id. + * @param removedDBForms Removed db form infos + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormDbCache::DeleteFormInfoByBundleName(const std::string &bundleName, std::vector &removedDBForms) +{ + std::lock_guard lock(formDBInfosMutex_); + std::vector::iterator itRecord; + for (itRecord = formDBInfos_.begin(); itRecord != formDBInfos_.end();) { + if (bundleName == itRecord->bundleName) { + int64_t formId = itRecord->formId; + if (dataStorage_->DeleteStorageFormInfo(std::to_string(formId)) == ERR_OK) { + removedDBForms.emplace_back(*itRecord); + itRecord = formDBInfos_.erase(itRecord); + } else { + itRecord++; + } + } else { + itRecord++; + } + } + return ERR_OK; +} +// bool FormDbCache::BatchDeleteForms(std::vector formIds) +// { +// std::lock_guard lock(formDBInfosMutex_); +// for (const auto& formId : formIds) { +// FormDBInfo tmpForm; +// tmpForm.formId_ = formId; +// auto iter = find(formDBInfos_.begin(), formDBInfos_.end(), tmpForm); +// if (iter != formDBInfos_.end()) { +// formDBInfos_.erase(iter); +// } +// } +// return dataStorage_->BatchDeleteForms(formIds); +// } + +/** + * @brief Get all form data from DbCache. + * @param formDBInfos Storage all DbCache. + * @return Void. + */ +void FormDbCache::GetAllFormInfo(std::vector &formDBInfos) +{ + APP_LOGI("%{public}s called.", __func__); + std::lock_guard lock(formDBInfosMutex_); + formDBInfos = formDBInfos_; +} + +/** + * @brief Get record from DB cache with formId + * @param formId Form data Id + * @param record Form data + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormDbCache::GetDBRecord(const int64_t formId, FormRecord &record) const +{ + std::lock_guard lock(formDBInfosMutex_); + for (const FormDBInfo &dbInfo : formDBInfos_) { + if (dbInfo.formId == formId) { + record.formName = dbInfo.formName; + record.bundleName = dbInfo.bundleName; + record.moduleName = dbInfo.moduleName; + record.abilityName = dbInfo.abilityName; + record.formUserUids = dbInfo.formUserUids; + return ERR_OK; + } + } + APP_LOGE("%{public}s, not find formId[%{public}lld]", __func__, formId); + return ERR_APPEXECFWK_FORM_DBCACHE_FIND_FAIL; +} +/** + * @brief Get record from DB cache with formId + * @param formId Form data Id + * @param record Form db data + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormDbCache::GetDBRecord(const int64_t formId, FormDBInfo &record) const +{ + std::lock_guard lock(formDBInfosMutex_); + for (const FormDBInfo &dbInfo : formDBInfos_) { + if (dbInfo.formId == formId) { + record = dbInfo; + return ERR_OK; + } + } + APP_LOGE("%{public}s, not find formId[%{public}lld]", __func__, formId); + return ERR_APPEXECFWK_FORM_DBCACHE_FIND_FAIL; +} +/** + * @brief Use record save or update DB data and DB cache with formId + * @param formId Form data Id + * @param record Form data + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormDbCache::UpdateDBRecord(const int64_t formId, const FormRecord &record) const +{ + FormDBInfo formDBInfo(formId, record); + return FormDbCache::GetInstance().SaveFormInfo(formDBInfo); + // FormBmsHelper::GetInstance().NotifyModuleNotRemovable(formDBInfo.bundleName, formDBInfo.moduleName); +} +/** + * @brief Get no host db record. + * @param uid The caller uid. + * @param noHostFormDBList no host db record list. + * @param foundFormsMap Form Id list. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormDbCache::GetNoHostDBForms(const int uid, std::map> &noHostFormDBList, +std::map &foundFormsMap) +{ + std::lock_guard lock(formDBInfosMutex_); + for (FormDBInfo& dbInfo : formDBInfos_) { + if (dbInfo.Contains(uid)) { + dbInfo.Remove(uid); + if (dbInfo.formUserUids.empty()) { + FormIdKey formIdKey; + formIdKey.bundleName = dbInfo.bundleName; + formIdKey.abilityName = dbInfo.abilityName; + auto itIdsSet = noHostFormDBList.find(formIdKey); + if (itIdsSet == noHostFormDBList.end()) { + std::set formIdsSet; + formIdsSet.emplace(dbInfo.formId); + noHostFormDBList.emplace(formIdKey, formIdsSet); + } else { + itIdsSet->second.emplace(dbInfo.formId); + } + } else { + foundFormsMap.emplace(dbInfo.formId, false); + SaveFormInfoNolock(dbInfo); + FormBmsHelper::GetInstance().NotifyModuleNotRemovable(dbInfo.bundleName, dbInfo.moduleName); + } + } + } + return ERR_OK; +} +/** + * @brief Get match count by bundleName and moduleName. + * @param bundleName BundleName. + * @param moduleName ModuleName. + * @return Returns match count. + */ +int FormDbCache::GetMatchCount(const std::string &bundleName, const std::string &moduleName) +{ + int32_t matchCount {0}; + std::vector formDBInfos; + std::lock_guard lock(formDBInfosMutex_); + for (FormDBInfo &dbInfo : formDBInfos_) { + if (dbInfo.bundleName == bundleName && dbInfo.moduleName == moduleName) { + ++matchCount; + } + } + return matchCount; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/formmgr/src/form_db_info.cpp b/services/formmgr/src/form_db_info.cpp new file mode 100644 index 0000000000..4846b9bf79 --- /dev/null +++ b/services/formmgr/src/form_db_info.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2021 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 "app_log_wrapper.h" +#include "form_db_info.h" +namespace OHOS { +namespace AppExecFwk { +namespace { +const std::string FORM_ID = "formId"; +const std::string FORM_NAME = "formName"; +const std::string BUNDLE_NAME = "bundleName"; +const std::string MODULE_NAME = "moduleName"; +const std::string ABILITY_NAME = "abilityName"; +const std::string FORM_USER_UIDS = "formUserUids"; +} + +// void to_json(nlohmann::json &jsonObject, const FormDBInfo &info) +// { +// jsonObject = nlohmann::json{ +// {FORM_ID, info.formId}, +// {USER_ID, info.userId}, +// {BUNDLE_NAME, info.bundleName}, +// {MODULE_NAME, info.moduleName}, +// {ABILITY_NAME, info.abilityName}, +// {FORM_USER_UIDS, info.formUserUids} +// }; +// } + +/** + * @brief Transform the InnerFormInfo object to json. + * @param jsonObject Indicates the obtained json object. + * @return + */ +void InnerFormInfo::ToJson(nlohmann::json &jsonObject) const +{ + jsonObject[FORM_ID] = formDBInfo_.formId; + jsonObject[FORM_NAME] = formDBInfo_.formName; + jsonObject[BUNDLE_NAME] = formDBInfo_.bundleName; + jsonObject[MODULE_NAME] = formDBInfo_.moduleName; + jsonObject[ABILITY_NAME] = formDBInfo_.abilityName; + jsonObject[FORM_USER_UIDS] = formDBInfo_.formUserUids; +} + +// void from_json(const nlohmann::json &jsonObject, FormDBInfo &info) +// { +// const auto &jsonObjectEnd = jsonObject.end(); +// if (jsonObject.find(FORM_ID) != jsonObjectEnd) { +// info.formId = jsonObject.at(FORM_ID).get(); +// } + +// if (jsonObject.find(USER_ID) != jsonObjectEnd) { +// info.userId = jsonObject.at(USER_ID).get(); +// } + +// if (jsonObject.find(BUNDLE_NAME) != jsonObjectEnd) { +// info.bundleName = jsonObject.at(BUNDLE_NAME).get(); +// } + +// if (jsonObject.find(MODULE_NAME) != jsonObjectEnd) { +// info.moduleName = jsonObject.at(MODULE_NAME).get(); +// } + +// if (jsonObject.find(ABILITY_NAME) != jsonObjectEnd) { +// info.abilityName = jsonObject.at(ABILITY_NAME).get(); +// } + +// if (jsonObject.find(FORM_USER_UIDS) != jsonObjectEnd) { +// info.formUserUids = jsonObject.at(FORM_USER_UIDS).get>(); +// } +// } + +/** + * @brief Transform the json object to InnerFormInfo object. + * @param jsonObject Indicates the obtained json object. + * @return + */ +bool InnerFormInfo::FromJson(const nlohmann::json &jsonObject) +{ + // try { + formDBInfo_.formId = jsonObject.at(FORM_ID).get(); + formDBInfo_.formName = jsonObject.at(FORM_NAME).get(); + formDBInfo_.bundleName = jsonObject.at(BUNDLE_NAME).get(); + formDBInfo_.moduleName = jsonObject.at(MODULE_NAME).get(); + formDBInfo_.abilityName = jsonObject.at(ABILITY_NAME).get(); + formDBInfo_.formUserUids = jsonObject.at(FORM_USER_UIDS).get>(); + + // } catch (nlohmann::detail::parse_error &exception) { + // APP_LOGE("%{public}s, has a parse_error:%{public}s", __func__, exception.what()); + // return false; + // } catch (nlohmann::detail::type_error &exception) { + // APP_LOGE("%{public}s, has a type_error:%{public}s.", __func__, exception.what()); + // return false; + // } catch (nlohmann::detail::out_of_range &exception) { + // APP_LOGE("%{public}s, has an out_of_range exception:%{public}s.", __func__, exception.what()); + // return false; + // } catch(...) { + // APP_LOGE("%{public}s, other exception", __func__); + // return false; + // } + return true; +} + +void InnerFormInfo::AddUserUid(const int callingUid) +{ + // std::lock_guard lock(mutex_); + auto iter = std::find(formDBInfo_.formUserUids.begin(), formDBInfo_.formUserUids.end(), callingUid); + if (iter == formDBInfo_.formUserUids.end()) { + formDBInfo_.formUserUids.push_back(callingUid); + } +} + +bool InnerFormInfo::DeleteUserUid(const int callingUid) +{ + // std::lock_guard lock(mutex_); + auto iter = std::find(formDBInfo_.formUserUids.begin(), formDBInfo_.formUserUids.end(), callingUid); + if (iter == formDBInfo_.formUserUids.end()) { + return false; + } + formDBInfo_.formUserUids.erase(iter); + return true; +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/formmgr/src/form_delete_connection.cpp b/services/formmgr/src/form_delete_connection.cpp new file mode 100755 index 0000000000..098e911591 --- /dev/null +++ b/services/formmgr/src/form_delete_connection.cpp @@ -0,0 +1,56 @@ + +/* + * Copyright (c) 2021 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 "appexecfwk_errors.h" +#include "app_log_wrapper.h" +#include "form_constants.h" +#include "form_delete_connection.h" +#include "form_supply_callback.h" +#include "form_task_mgr.h" +#include "ipc_types.h" +#include "message_parcel.h" +#include "want.h" + +namespace OHOS { +namespace AppExecFwk { +FormDeleteConnection::FormDeleteConnection(const int64_t formId) + :formId_(formId) +{ +} +/** + * @brief OnAbilityConnectDone, AbilityMs notify caller ability the result of connect. + * @param element service ability's ElementName. + * @param remoteObject the session proxy of service ability. + * @param resultCode ERR_OK on success, others on failure. + */ +void FormDeleteConnection::OnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) +{ + APP_LOGI("%{public}s called.", __func__); + if (resultCode != ERR_OK) { + APP_LOGE("%{public}s, abilityName:%{public}s, formId:%{public}lld, resultCode:%{public}d", + __func__, element.GetAbilityName().c_str(), formId_, resultCode); + return; + } + FormSupplyCallback::GetInstance()->AddConnection(this); + + Want want; + want.SetParam(Constants::FORM_CONNECT_ID, this->GetConnectId()); + APP_LOGD("%{public}s, connectId :%{public}ld", __func__, this->GetConnectId()); + FormTaskMgr::GetInstance().PostDeleteTask(formId_, want, remoteObject); +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/formmgr/src/form_dump_mgr.cpp b/services/formmgr/src/form_dump_mgr.cpp new file mode 100644 index 0000000000..0f89ca359d --- /dev/null +++ b/services/formmgr/src/form_dump_mgr.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2021 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 "app_log_wrapper.h" +#include "form_cache_mgr.h" +#include "form_dump_mgr.h" + +namespace OHOS { +namespace AppExecFwk { +const std::string LINE_SEPARATOR = "\n"; + +FormDumpMgr::FormDumpMgr(){} +FormDumpMgr::~FormDumpMgr(){} +/** + * @brief Dump all of form storage infos. + * @param storageInfos Form storage infos + * @param formInfos Form storage dump info. + */ +void FormDumpMgr::DumpStorageFormInfos(const std::vector &storageInfos, std::string &formInfos) const +{ + for (const auto &info : storageInfos) { + formInfos += " FormId #" + std::to_string(info.formId); + formInfos += " formName [" + info.formName + "]"; + formInfos += " bundleName [" + info.bundleName + "]"; + formInfos += " moduleName [" + info.moduleName + "]"; + formInfos += " abilityName [" + info.abilityName + "]"; + formInfos += " formUserUids ["; + for (auto &uId : info.formUserUids) { + formInfos += " Uid [" + std::to_string(uId) + "]"; + } + formInfos += "]" + LINE_SEPARATOR; + } +} +/** + * @brief Dump form infos. + * @param formRecordInfos Form record infos. + * @param formInfos Form dump infos. + */ +void FormDumpMgr::DumpFormInfos(const std::vector &formRecordInfos, std::string &formInfos) const +{ + APP_LOGI("%{public}s called.", __func__); + for (const auto &info : formRecordInfos) { + formInfos += " FormId [" + std::to_string(info.formId) + "]"; + formInfos += " formName [" + info.formName + "]"; + formInfos += " bundleName [" + info.bundleName + "]"; + formInfos += " moduleName [" + info.moduleName + "]"; + formInfos += " abilityName [" + info.abilityName + "]"; + formInfos += " isInited [" + std::to_string(info.isInited) + "]"; + formInfos += " needRefresh [" + std::to_string(info.needRefresh) + "]"; + formInfos += " isEnableUpdate [" + std::to_string(info.isEnableUpdate) + "]"; + formInfos += " isCountTimerRefresh [" + std::to_string(info.isCountTimerRefresh) + "]"; + formInfos += " specification [" + std::to_string(info.specification) + "]"; + formInfos += " updateDuration [" + std::to_string(info.updateDuration) + "]"; + formInfos += " updateAtHour [" + std::to_string(info.updateAtHour) + "]"; + formInfos += " updateAtMin [" + std::to_string(info.updateAtMin) + "]"; + formInfos += " formTempFlg [" + std::to_string(info.formTempFlg) + "]"; + formInfos += " formVisibleNotify [" + std::to_string(info.formVisibleNotify) + "]"; + formInfos += " formVisibleNotifyState [" + std::to_string(info.formVisibleNotifyState) + "]"; + + if (info.hapSourceDirs.size() > 0) { + formInfos += " hapSourceDirs ["; + for (auto &hapDir : info.hapSourceDirs) { + formInfos += " hapSourceDir [" + hapDir + "]"; + } + formInfos += "]"; + } + + if (info.formUserUids.size() > 0) { + formInfos += " formUserUids ["; + for (auto &uId : info.formUserUids) { + formInfos += " Uid [" + std::to_string(uId) + "]"; + } + formInfos += "]"; + } + + // formCacheData + std::string strCacheData; + if (FormCacheMgr::GetInstance().GetData(info.formId, strCacheData)) { + formInfos += " formCacheData ["; + formInfos += strCacheData; + formInfos += "]" + LINE_SEPARATOR; + } + } + + APP_LOGI("%{public}s success. Form infos:%{public}s", __func__, formInfos.c_str()); +} +/** + * @brief Dump form infos. + * @param formRecordInfo Form Host record info. + * @param formInfo Form dump info. + */ +void FormDumpMgr::DumpFormHostInfo(const FormHostRecord &formHostRecord, std::string &formInfo) const +{ + APP_LOGI("%{public}s called.", __func__); + formInfo += " ================FormHostRecord================="; + formInfo += " callerUid [" + std::to_string(formHostRecord.GetCallerUid()) + "]"; + formInfo += " hostBundleName [" + formHostRecord.GetHostBundleName() + "]"; + APP_LOGI("%{public}s success. Host Form infos:%{public}s", __func__, formInfo.c_str()); +} + +/** + * @brief Dump form infos. + * @param formRecordInfo Form record info. + * @param formInfo Form dump info. + */ +void FormDumpMgr::DumpFormInfo(const FormRecord &formRecordInfo, std::string &formInfo) const +{ + APP_LOGI("%{public}s called.", __func__); + formInfo += " ================FormRecord================="; + formInfo += " FormId [" + std::to_string(formRecordInfo.formId) + "]"; + formInfo += " formName [" + formRecordInfo.formName + "]"; + formInfo += " bundleName [" + formRecordInfo.bundleName + "]"; + formInfo += " moduleName [" + formRecordInfo.moduleName + "]"; + formInfo += " abilityName [" + formRecordInfo.abilityName + "]"; + formInfo += " isInited [" + std::to_string(formRecordInfo.isInited) + "]"; + formInfo += " needRefresh [" + std::to_string(formRecordInfo.needRefresh) + "]"; + formInfo += " isEnableUpdate [" + std::to_string(formRecordInfo.isEnableUpdate) + "]"; + formInfo += " isCountTimerRefresh [" + std::to_string(formRecordInfo.isCountTimerRefresh) + "]"; + formInfo += " specification [" + std::to_string(formRecordInfo.specification) + "]"; + formInfo += " updateDuration [" + std::to_string(formRecordInfo.updateDuration) + "]"; + formInfo += " updateAtHour [" + std::to_string(formRecordInfo.updateAtHour) + "]"; + formInfo += " updateAtMin [" + std::to_string(formRecordInfo.updateAtMin) + "]"; + formInfo += " formTempFlg [" + std::to_string(formRecordInfo.formTempFlg) + "]"; + formInfo += " formVisibleNotify [" + std::to_string(formRecordInfo.formVisibleNotify) + "]"; + formInfo += " formVisibleNotifyState [" + std::to_string(formRecordInfo.formVisibleNotifyState) + "]"; + + if (formRecordInfo.hapSourceDirs.size() > 0) { + formInfo += " hapSourceDirs ["; + for (auto &hapDir : formRecordInfo.hapSourceDirs) { + formInfo += " hapSourceDir [" + hapDir + "]"; + } + formInfo += "]"; + } + + if (formRecordInfo.formUserUids.size() > 0) { + formInfo += " formUserUids ["; + for (auto &uId : formRecordInfo.formUserUids) { + formInfo +=" Uid [" + std::to_string(uId) + "]"; + } + formInfo += "]"; + } + + // formCacheData + std::string strCacheData; + if (FormCacheMgr::GetInstance().GetData(formRecordInfo.formId, strCacheData)) { + formInfo += " formCacheData ["; + formInfo += strCacheData; + formInfo += "]" + LINE_SEPARATOR; + } + + APP_LOGI("%{public}s success. Form infos:%{public}s", __func__, formInfo.c_str()); +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/formmgr/src/form_event_notify_connection.cpp b/services/formmgr/src/form_event_notify_connection.cpp new file mode 100644 index 0000000000..cea26ab8e3 --- /dev/null +++ b/services/formmgr/src/form_event_notify_connection.cpp @@ -0,0 +1,60 @@ + +/* + * Copyright (c) 2021 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 "appexecfwk_errors.h" +#include "app_log_wrapper.h" +#include "form_constants.h" +#include "form_event_notify_connection.h" +#include "form_supply_callback.h" +#include "form_task_mgr.h" +#include "ipc_types.h" +#include "message_parcel.h" +#include "want.h" + +namespace OHOS { +namespace AppExecFwk { +FormEventNotifyConnection::FormEventNotifyConnection(const std::vector formEvents, +const int32_t formVisibleType) + :formEvents_(formEvents), + formVisibleType_(formVisibleType) +{ +} +/** + * @brief OnAbilityConnectDone, AbilityMs notify caller ability the result of connect. + * + * @param element Service ability's ElementName. + * @param remoteObject The session proxy of service ability. + * @param resultCode ERR_OK on success, others on failure. + * @return none. + */ +void FormEventNotifyConnection::OnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) +{ + APP_LOGI("%{public}s called.", __func__); + + if (resultCode != ERR_OK) { + APP_LOGE("%{public}s, abilityName:%{public}s, resultCode:%{public}d", + __func__, element.GetAbilityName().c_str(), resultCode); + return; + } + FormSupplyCallback::GetInstance()->AddConnection(this); + + Want want; + want.SetParam(Constants::FORM_CONNECT_ID, this->GetConnectId()); + FormTaskMgr::GetInstance().PostEventNotifyTask(formEvents_, formVisibleType_, want, remoteObject); +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/formmgr/src/form_host_callback.cpp b/services/formmgr/src/form_host_callback.cpp new file mode 100644 index 0000000000..41dab8f27d --- /dev/null +++ b/services/formmgr/src/form_host_callback.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2021 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 "appexecfwk_errors.h" +#include "app_log_wrapper.h" +#include "form_host_callback.h" +#include "form_host_interface.h" +#include "form_task_mgr.h" +#include "string_ex.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @brief Request to give back a Form. + * @param formId The Id of the forms to create. + * @param record Form record. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ +void FormHostCallback::OnAcquired(const int64_t formId, const FormRecord& record, +const sptr &callerToken) +{ + APP_LOGD("FormHostCallback OnAcquired, formId:%{public}lld", formId); + FormTaskMgr::GetInstance().PostAcquireTaskToHost(formId, record, callerToken); +} + + +/** +* @brief Form is updated. +* @param formId The Id of the form to update. +* @param record Form record. +* @param callerToken Caller ability token. +* @return Returns ERR_OK on success, others on failure. +*/ +void FormHostCallback::OnUpdate(const int64_t formId, const FormRecord &record, const sptr &callerToken) +{ + APP_LOGI("%{public}s start.", __func__); + + // check formId + if (formId < 0) { + APP_LOGE("%{public}s: OnUpdate invalid param, formId:%{public}lld.", __func__, formId); + return; + } + + if (callerToken == nullptr) { + APP_LOGE("%{public}s: callerToken can not be NULL", __func__); + return; + } + + // post updateTask to host + FormTaskMgr::GetInstance().PostUpdateTaskToHost(formId, record, callerToken); +} + +/** + * @brief Form provider is uninstalled + * @param formIds The Id list of the forms. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ +void FormHostCallback::OnUninstall(std::vector &formIds, const sptr &callerToken) +{ + // check formId + if (formIds.size() <= 0) { + APP_LOGE("%{public}s: OnUninstall invalid param, formIds is empty.", __func__); + return; + } + + if (callerToken == nullptr) { + APP_LOGE("%{public}s: callerToken can not be NULL", __func__); + return; + } + // post updateTask to host + FormTaskMgr::GetInstance().PostUninstallTaskToHost(formIds, callerToken); +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/formmgr/src/form_host_record.cpp b/services/formmgr/src/form_host_record.cpp new file mode 100644 index 0000000000..7b276a1c8b --- /dev/null +++ b/services/formmgr/src/form_host_record.cpp @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2021 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 "form_host_record.h" +#include "form_task_mgr.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @brief Add form id. + * @param formId The Id of the form. + */ +void FormHostRecord::AddForm(int64_t formId) +{ + if (forms_.find(formId) != forms_.end()) { + return; + } + forms_[formId] = true; +} +/** + * @brief Delete form id. + * @param formId The Id of the form. + */ +void FormHostRecord::DelForm(int64_t formId) +{ + forms_.erase(formId); +} +/** + * @brief forms_ is empty or not. + * @return forms_ is empty or not. + */ +bool FormHostRecord::IsEmpty() const +{ + return forms_.empty(); +} +/** + * @brief formId is in forms_ or not. + * @param formId The Id of the form. + * @return formId is in forms_ or not. + */ +bool FormHostRecord::Contains(int64_t formId) const +{ + return forms_.find(formId) != forms_.end(); +} + +/** + * @brief Set refresh enable flag. + * @param formId The Id of the form. + * @param flag True for enbale, false for disable. + */ +void FormHostRecord::SetEnableRefresh(int64_t formId, bool flag) +{ + if (forms_.find(formId) == forms_.end()) { + return; + } + forms_[formId] = flag; +} +/** + * @brief Refresh enable or not. + * @param formId The Id of the form. + * @return true on enbale, false on disable.. + */ +bool FormHostRecord::IsEnableRefresh(int64_t formId) const +{ + auto result = forms_.find(formId); + if (result != forms_.end()) { + return result->second; + } + return false; +} +/** + * @brief Set need refresh enable flag. + * @param formId The Id of the form. + * @param flag True for enbale, false for disable. + */ +void FormHostRecord::SetNeedRefresh(int64_t formId, bool flag) +{ + needRefresh_[formId] = flag; +} +/** + * @brief Need Refresh enable or not. + * @param formId The Id of the form. + * @return true on enbale, false on disable.. + */ +bool FormHostRecord::IsNeedRefresh(int64_t formId) const +{ + auto result = needRefresh_.find(formId); + if (result != needRefresh_.end()) { + return result->second; + } + return false; +} +/** + * @brief Get clientStub_. + * @return clientStub_. + */ +sptr FormHostRecord::GetClientStub() const +{ + return clientStub_; +} + +/** + * @brief Send form data to form host. + * @param id The Id of the form. + * @param record Form record. + */ +void FormHostRecord::OnAcquire(int64_t id, const FormRecord &record) +{ + APP_LOGD("FormHostRecord OnAcquire"); + if (clientImpl_ == nullptr) { + APP_LOGE("%{public}s: clientImpl_ can not be NULL", __func__); + return; + } + + clientImpl_->OnAcquired(id, record, clientStub_); +} + +/** + * @brief Update form data to form host. + * @param id The Id of the form. + * @param record Form record. + */ +void FormHostRecord::OnUpdate(int64_t id, const FormRecord &record) +{ + APP_LOGI("%{public}s start.", __func__); + + if (clientImpl_ == nullptr) { + APP_LOGE("%{public}s: clientImpl_ can not be null.", __func__); + return; + } + + clientImpl_->OnUpdate(id, record, clientStub_); +} + +/** + * @brief Send form uninstall message to form host. + * @param id The Id of the form. + * @param record Form record. + */ +void FormHostRecord::OnFormUninstalled(std::vector &formIds) +{ + APP_LOGI("%{public}s start.", __func__); + + if (clientImpl_ == nullptr) { + APP_LOGE("%{public}s: clientImpl_ can not be null.", __func__); + return; + } + clientImpl_->OnUninstall(formIds, clientStub_); +} +/** + * @brief Release resource. + * @param id The Id of the form. + * @param record Form record. + */ +void FormHostRecord::CleanResource() +{ + if (clientStub_ != nullptr && deathRecipient_ != nullptr) { + clientStub_->RemoveDeathRecipient(deathRecipient_); + clientStub_ = nullptr; + deathRecipient_ = nullptr; + } +} +/** + * @brief Set value of callerUid_. + * @param callerUid Caller uid. + */ +void FormHostRecord::SetCallerUid(const int callerUid) +{ + callerUid_ = callerUid; +} +/** + * @brief Set value of clientStub_. + * @param clientStub remote object. + */ +void FormHostRecord::SetClientStub(const sptr &clientStub) +{ + clientStub_ = clientStub; +} +/** + * @brief Set value of clientImpl_. + * @param clientImpl Form host callback object. + */ +void FormHostRecord::SetClientImpl(const std::shared_ptr &clientImpl) +{ + clientImpl_ = clientImpl; +} +/** + * @brief Get deathRecipient_. + * @return deathRecipient_. + */ +sptr FormHostRecord::GetDeathRecipient() const +{ + return deathRecipient_; +} +/** + * @brief Set value of deathRecipient_. + * @param clientImpl DeathRecipient object. + */ +void FormHostRecord::SetDeathRecipient(const sptr &deathRecipient) +{ + deathRecipient_ = deathRecipient; +} +/** + * @brief Add deathRecipient object to clientStub_. + * @param deathRecipient DeathRecipient object. + */ +void FormHostRecord::AddDeathRecipient(const sptr &deathRecipient) +{ + clientStub_->AddDeathRecipient(deathRecipient); +} + +/** + * @brief Create form host record. + * @param info The form item info. + * @param callback remote object. + * @param callingUid Calling uid. + */ +FormHostRecord FormHostRecord::CreateRecord(const FormItemInfo &info, const sptr &callback, +int callingUid) +{ + FormHostRecord record; + record.SetHostBundleName(info.GetHostBundleName()); + record.SetCallerUid(callingUid); + record.SetClientStub(callback); + record.SetClientImpl(std::make_shared()); + record.SetDeathRecipient(new FormHostRecord::ClientDeathRecipient()); + record.AddDeathRecipient(record.GetDeathRecipient()); + + return record; +} + +/** + * @brief handle remote object died event. + * @param remote remote object. + */ +void FormHostRecord::ClientDeathRecipient::OnRemoteDied(const wptr &remote) +{ + APP_LOGD("Form remote died"); + FormTaskMgr::GetInstance().PostHostDiedTask(remote.promote()); +} + +/** + * @brief Get hostBundleName_. + * @return hostBundleName_. + */ +std::string FormHostRecord::GetHostBundleName() const +{ + return hostBundleName_; +} +/** + * @brief Set hostBundleName_. + * @param hostBandleName Host bundle name. + */ +void FormHostRecord::SetHostBundleName(const std::string &hostBundleName) +{ + hostBundleName_ = hostBundleName; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/formmgr/src/form_item_info.cpp b/services/formmgr/src/form_item_info.cpp new file mode 100644 index 0000000000..b686c4f61d --- /dev/null +++ b/services/formmgr/src/form_item_info.cpp @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2021 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 "app_log_wrapper.h" +#include "form_item_info.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @brief Get formId_. + * @return formId_. + */ +int64_t FormItemInfo::GetFormId() const +{ + return formId_; +} +/** + * @brief Get packageName_. + * @return packageName_. + */ +std::string FormItemInfo::GetPackageName() const +{ + return packageName_; +} +/** + * @brief Get providerBundleName_. + * @return providerBundleName_. + */ +std::string FormItemInfo::GetProviderBundleName() const +{ + return providerBundleName_; +} +/** + * @brief Get hostBundleName_. + * @return hostBundleName_. + */ +std::string FormItemInfo::GetHostBundleName() const +{ + return hostBundleName_; +} +/** + * @brief Get moduleName_. + * @return moduleName_. + */ +std::string FormItemInfo::GetModuleName() const +{ + return moduleName_; +} +/** + * @brief Get abilityName_. + * @return abilityName_. + */ +std::string FormItemInfo::GetAbilityName() const +{ + return abilityName_; +} +/** + * @brief Get formName_. + * @return formName_. + */ +std::string FormItemInfo::GetFormName() const +{ + return formName_; +} +/** + * @brief Get jsComponentName_. + * @return jsComponentName_. + */ +std::string FormItemInfo::GetJsComponentName() const +{ + return jsComponentName_; +} +/** + * @brief Get abilityModuleName_. + * @return abilityModuleName_. + */ +std::string FormItemInfo::GetAbilityModuleName() const +{ + return abilityModuleName_; +} +/** + * @brief Get specificationId_. + * @return specificationId_. + */ +int FormItemInfo::GetSpecificationId() const +{ + return specificationId_; +} + +/** + * @brief Obtains the updageFlag. + * @return Returns updageFlag. + */ +bool FormItemInfo::IsEnableUpdateFlag() const +{ + return updateFlag_; +} +/** + * @brief Get updateDuration_. + * @return updateDuration_. + */ +int FormItemInfo::GetUpdateDuration() const +{ + return updateDuration_; +} +/** + * @brief Get scheduledUpdateTime_. + * @return scheduledUpdateTime_. + */ +std::string FormItemInfo::GetScheduledUpdateTime() const +{ + return scheduledUpdateTime_; +} + +/** + * @brief Get hapSourceDirs_. + * @param dirs Hap source dirs. + * @return Returns true on success, false on failure. + */ +bool FormItemInfo::GetHapSourceDirs(std::vector &dirs) const +{ + if (hapSourceDirs_.size() > 0) { + dirs.assign(hapSourceDirs_.begin(), hapSourceDirs_.end()); + return true; + } + return false; +} +/** + * @brief Set value of hapSourceDirs_. + * @param hapSourceDirs Hap source dirs. + */ +void FormItemInfo::SetHapSourceDirs(const std::vector &hapSourceDirs) +{ + hapSourceDirs_ = hapSourceDirs; +} +/** + * @brief Obtains the temporaryFlag. + * @return Returns temporaryFlag. + */ +bool FormItemInfo::IsTemporaryForm() const +{ + return temporaryFlag_; +} + +/** + * @brief Obtains the hap source by ability module name. + * @param moduleName ability module name + * @return Returns hap source. + */ +std::string FormItemInfo::GetHapSourceByModuleName(const std::string &moduleName) const +{ + auto iter = moduleInfoMap_.find(moduleName); + if (iter != moduleInfoMap_.end()) { + return iter->second; + } + return ""; +} +/** + * @brief Check if item valid or not. + * @return Valid or not + */ +bool FormItemInfo::IsValidItem() const +{ + if (providerBundleName_.empty() || moduleName_.empty() + || abilityName_.empty() || formName_.empty()) { + return false; + } + return true; +} +/** + * @brief Check if item match or not. + * @return Match or not + */ +bool FormItemInfo::IsMatch(const FormRecord &record) const +{ + APP_LOGD("match data"); + APP_LOGD("FormRecord.bundleName : %{public}s", record.bundleName.c_str()); + APP_LOGD("FormRecord.moduleName : %{public}s", record.moduleName.c_str()); + APP_LOGD("FormRecord.abilityName : %{public}s", record.abilityName.c_str()); + APP_LOGD("FormRecord.formName : %{public}s", record.formName.c_str()); + APP_LOGD("FormRecord.specification : %{public}d", record.specification); + + APP_LOGD("FormItemInfo.providerBundleName_ : %{public}s", providerBundleName_.c_str()); + APP_LOGD("FormItemInfo.moduleName : %{public}s", moduleName_.c_str()); + APP_LOGD("FormItemInfo.abilityName : %{public}s", abilityName_.c_str()); + APP_LOGD("FormItemInfo.formName : %{public}s", formName_.c_str()); + APP_LOGD("FormItemInfo.specification : %{public}d", specificationId_); + + return (record.bundleName == providerBundleName_) && (record.moduleName == moduleName_) + && (record.abilityName == abilityName_) && (record.formName == formName_) + && (record.specification == specificationId_); +} +/** + * @brief Check if form config same or not. + * @return Same or not + */ +bool FormItemInfo::IsSameFormConfig(const FormRecord &record) const +{ + return (record.bundleName == providerBundleName_) && (record.moduleName == moduleName_) + && (record.abilityName == abilityName_) && (record.formName == formName_); +} + +/** + * @brief Check if visible notify or not. + * @return visible notify or not + */ +bool FormItemInfo::IsFormVisibleNotify() const +{ + return formVisibleNotify_; +} +/** + * @brief Equal or not. + * @param left left string. + * @param right right string. + * @return Equal or not + */ +bool FormItemInfo::IsEqual(const std::string &left, const std::string &right) +{ + return left == right; +} +/** + * @brief Set value of formId_. + * @param formId Form Id. + */ +void FormItemInfo::SetFormId(int64_t formId) +{ + formId_ = formId; +} +/** + * @brief Set value of packageName_. + * @param packageName Package name. + */ +void FormItemInfo::SetPackageName(const std::string &packageName) +{ + packageName_ = packageName; +} +/** + * @brief Set value of providerBundleName_. + * @param providerBundleName Provider bundle Name. + */ +void FormItemInfo::SetProviderBundleName(const std::string &providerBundleName) +{ + providerBundleName_ = providerBundleName; +} +/** + * @brief Set value of hostBundleName_. + * @param hostBundleName Host bundle Name. + */ +void FormItemInfo::SetHostBundleName(const std::string &hostBundleName) +{ + hostBundleName_ = hostBundleName; +} +/** + * @brief Set value of moduleName_. + * @param moduleName Module Name. + */ +void FormItemInfo::SetModuleName(const std::string &moduleName) +{ + moduleName_ = moduleName; +} +/** + * @brief Set value of abilityName_. + * @param abilityName Ability name. + */ +void FormItemInfo::SetAbilityName(const std::string &abilityName) +{ + abilityName_ = abilityName; +} +/** + * @brief Set value of formName_. + * @param formName Form name. + */ +void FormItemInfo::SetFormName(const std::string &formName) +{ + formName_ = formName; +} +/** + * @brief Set value of jsComponentName_. + * @param jsComponentName Js component name. + */ +void FormItemInfo::SetJsComponentName(const std::string &jsComponentName) +{ + jsComponentName_ = jsComponentName; +} +/** + * @brief Set value of abilityModuleName_. + * @param abilityModuleName ability module name_. + */ +void FormItemInfo::SetAbilityModuleName(const std::string &abilityModuleName) +{ + abilityModuleName_ = abilityModuleName; +} +/** + * @brief Set value of specificationId_. + * @param specificationId Specification id. + */ +void FormItemInfo::SetSpecificationId(const int specificationId) +{ + specificationId_ = specificationId; +} +/** + * @brief Set value of updateFlag_. + * @param IsEnableUpdateFlag Enable update flag or not. + */ +void FormItemInfo::SetEnableUpdateFlag(bool IsEnableUpdateFlag) +{ + updateFlag_ = IsEnableUpdateFlag; +} +/** + * @brief Set value of updateDuration_. + * @param updateDuration Update duration. + */ +void FormItemInfo::SetUpdateDuration(int updateDuration) +{ + updateDuration_ = updateDuration; +} +/** + * @brief Set value of scheduledUpdateTime_. + * @param scheduledUpdateTime Scheduled update time. + */ +void FormItemInfo::SetScheduledUpdateTime(const std::string &scheduledUpdateTime) +{ + scheduledUpdateTime_ = scheduledUpdateTime; +} +/** + * @brief Add hap source dir. + * @param hapSourceDir Hap source dir. + */ +void FormItemInfo::AddHapSourceDirs(const std::string &hapSourceDir) +{ + hapSourceDirs_.emplace_back(hapSourceDir); +} +/** + * @brief Set value of temporaryFlag_. + * @param temporaryFlag Temporary flag. + */ +void FormItemInfo::SetTemporaryFlag(bool temporaryFlag) +{ + temporaryFlag_ = temporaryFlag; +} +/** + * @brief Add module info. + * @param moduleName Module name. + * @param moduleSourceDir Module source dir. + */ +void FormItemInfo::AddModuleInfo(const std::string &moduleName, const std::string &moduleSourceDir) +{ + moduleInfoMap_.emplace(std::make_pair(moduleName, moduleSourceDir)); +} +/** + * @brief Set value of formVisibleNotify_. + * @param isFormVisibleNotify visible notify or not. + */ +void FormItemInfo::SetFormVisibleNotify(bool isFormVisibleNotify) +{ + formVisibleNotify_ = isFormVisibleNotify; +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/formmgr/src/form_mgr_adapter.cpp b/services/formmgr/src/form_mgr_adapter.cpp new file mode 100644 index 0000000000..dbf738eca6 --- /dev/null +++ b/services/formmgr/src/form_mgr_adapter.cpp @@ -0,0 +1,1399 @@ +/* + * Copyright (c) 2021 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 "appexecfwk_errors.h" +#include "app_log_wrapper.h" +#include "form_acquire_connection.h" +#include "form_ams_helper.h" +#include "form_bms_helper.h" +#include "form_cache_mgr.h" +#include "form_cast_temp_connection.h" +#include "form_constants.h" +#include "form_data_mgr.h" +#include "form_delete_connection.h" +#include "form_db_cache.h" +#include "form_db_info.h" +#include "form_dump_mgr.h" +#include "form_event_notify_connection.h" +#include "form_mgr_adapter.h" +#include "form_provider_info.h" +#include "form_provider_mgr.h" +#include "form_refresh_connection.h" +#include "form_timer_mgr.h" +#include "if_system_ability_manager.h" +#include "ipc_skeleton.h" +#include "iservice_registry.h" +#include "ohos_account_kits.h" +#include "power_mgr_client.h" +#include "system_ability_definition.h" + +namespace OHOS { +namespace AppExecFwk { +// /** +// * @brief Get moduleName from packageName and abilityName. +// * @param packageName Package name. +// * @param abilityName Ability name. +// * @return ModuleName. +// */ +// std::string GetFullClassName(const std::string& packageName, const std::string& abilityName) +// { +// std::string fullName; +// if (!abilityName.empty() && abilityName[0] == '.') { +// fullName = packageName + abilityName; +// } else { +// fullName = abilityName; +// } +// return fullName; +// } + +/** + * @brief Add form with want, send want to form manager service. + * @param formId The Id of the forms to add. + * @param want The want of the form to add. + * @param callerToken Caller ability token. + * @param formInfo Form info. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrAdapter::AddForm(const int64_t formId, const Want &want, const sptr &callerToken, +FormJsInfo &formInfo) +{ + if (formId < 0 || callerToken == nullptr) { + APP_LOGE("%{public}s fail, callerToken can not be NULL", __func__); + return ERR_APPEXECFWK_FORM_INVALID_PARAM; + } + + // check form count limit + bool tempFormFlag = want.GetBoolParam(Constants::PARAM_FORM_TEMPORARY_KEY, false); + int callingUid = IPCSkeleton::GetCallingUid(); + int checkCode; + if (tempFormFlag) { + if (formId > 0) { + APP_LOGE("%{public}s fail, temp form id is invalid, formId:%{public}lld", __func__, formId); + return ERR_APPEXECFWK_FORM_INVALID_PARAM; + } + checkCode = FormDataMgr::GetInstance().CheckTempEnoughForm(); + } else { + checkCode = FormDataMgr::GetInstance().CheckEnoughForm(callingUid); + } + if (checkCode != 0) { + APP_LOGE("%{public}s fail, too much forms in system", __func__); + return checkCode; + } + + // get from comfig info + FormItemInfo formItemInfo; + int32_t errCode = GetFormConfigInfo(want, formItemInfo); + formItemInfo.SetFormId(formId); + if (errCode != ERR_OK) { + APP_LOGE("%{public}s fail, get form config info failed.", __func__); + return errCode; + } + if (!formItemInfo.IsValidItem()) { + APP_LOGE("%{public}s fail, input param itemInfo is invalid", __func__); + return ERR_APPEXECFWK_FORM_GET_INFO_FAILED; + } + if (!FormDataMgr::GetInstance().GenerateUdidHash()) { + APP_LOGE("%{public}s fail, generate udid hash failed", __func__); + return ERR_APPEXECFWK_FORM_COMMON_CODE; + } + + WantParams wantParams = want.GetParams(); + if (formId > 0) { + return AllotFormById(formItemInfo, callerToken, wantParams, formInfo); + } else { + return AllotFormByInfo(formItemInfo, callerToken, wantParams, formInfo); + } +} + +/** + * @brief Delete forms with formIds, send formIds to form manager service. + * @param formId The Id of the forms to delete. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrAdapter::DeleteForm(const int64_t formId, const sptr &callerToken) +{ + if (formId <= 0 || callerToken == nullptr) { + APP_LOGE("%{public}s, deleteForm invalid param", __func__); + return ERR_FORM_INVALID_PARAM; + } + + int64_t matchedFormId = FormDataMgr::GetInstance().FindMatchedFormId(formId); + if (FormDataMgr::GetInstance().ExistTempForm(matchedFormId)) { + // delete temp form if receive delete form call + return HandleDeleteTempForm(matchedFormId, callerToken); + } + return HandleDeleteForm(matchedFormId, callerToken); +} + +/** + * @brief Release forms with formIds, send formIds to form Mgr service. + * @param formId The Id of the forms to release. + * @param callerToken Caller ability token. + * @param delCache Delete Cache or not. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrAdapter::ReleaseForm(const int64_t formId, const sptr &callerToken, const bool delCache) +{ + APP_LOGI("%{public}s called.", __func__); + + if (formId <= 0 || callerToken == nullptr) { + APP_LOGE("%{public}s, releaseForm invalid param", __func__); + return ERR_FORM_INVALID_PARAM; + } + + int64_t matchedFormId = FormDataMgr::GetInstance().FindMatchedFormId(formId); + if (FormDataMgr::GetInstance().ExistTempForm(matchedFormId)) { + // delete temp form if receive release form call + return HandleDeleteTempForm(matchedFormId, callerToken); + } + + if (delCache) { + if (ErrCode result = HandleReleaseForm(matchedFormId, callerToken); result != ERR_OK) { + APP_LOGE("%{public}s, release form error.", __func__); + return result; + } + } + + if (!FormDataMgr::GetInstance().DeleteHostRecord(callerToken, matchedFormId)) { + APP_LOGE("%{public}s, failed to remove host record", __func__); + return ERR_APPEXECFWK_FORM_COMMON_CODE; + } + if (!FormTimerMgr::GetInstance().RemoveFormTimer(matchedFormId)) { + APP_LOGE("%{public}s, remove timer error", __func__); + return ERR_DELETE_FORM_TIMER; + } + return ERR_OK; +} + +/** + * @brief Handle release form. + * @param formId The form id. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormMgrAdapter::HandleReleaseForm(const int64_t formId, const sptr &callerToken) +{ + APP_LOGI("%{public}s called.", __func__); + if (!FormDataMgr::GetInstance().ExistFormRecord(formId)) { + APP_LOGE("%{public}s, not exist such db or temp form:%{public}lld", __func__, formId); + return ERR_NOT_EXIST_ID; + } + + FormHostRecord hostRecord; + bool hasHostRec = FormDataMgr::GetInstance().GetMatchedHostClient(callerToken, hostRecord); + bool isSelfId = hasHostRec && hostRecord.Contains(formId); + if (!isSelfId) { + APP_LOGE("%{public}s, not self form:%{public}lld", __func__, formId); + return ERR_OPERATION_FORM_NOT_SELF; + } + + APP_LOGD("%{public}s, release formRecords, formId: %{public}lld", __func__, formId); + FormDataMgr::GetInstance().DeleteFormUserUid(formId, IPCSkeleton::GetCallingUid()); + if (!FormDataMgr::GetInstance().HasFormUserUids(formId)) { + FormDataMgr::GetInstance().DeleteFormRecord(formId); + if (!FormTimerMgr::GetInstance().RemoveFormTimer(formId)) { + APP_LOGE("%{public}s, remove timer error", __func__); + return ERR_DELETE_FORM_TIMER; + } + } + return ERR_OK; +} + +/** + * @brief Handle delete form. + * @param formId The form id. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormMgrAdapter::HandleDeleteForm(const int64_t formId, const sptr &callerToken) +{ + FormRecord dbRecord; + if (FormDbCache::GetInstance().GetDBRecord(formId, dbRecord) != ERR_OK) { + APP_LOGE("%{public}s, not exist such db or temp form:%{public}lld", __func__, formId); + return ERR_NOT_EXIST_ID; + } + + int callingUid = IPCSkeleton::GetCallingUid(); + bool isSelfDbFormId = (std::find(dbRecord.formUserUids.begin(), dbRecord.formUserUids.end(), callingUid) != + dbRecord.formUserUids.end()) ? true : false; + + if (!isSelfDbFormId) { + APP_LOGE("%{public}s, not self form:%{public}lld", __func__, formId); + return ERR_OPERATION_FORM_NOT_SELF; + } + + if (ErrCode result = HandleDeleteFormCache(dbRecord, callingUid, formId); result != ERR_OK) { + return result; + } + + if (!FormDataMgr::GetInstance().DeleteHostRecord(callerToken, formId)) { + APP_LOGE("%{public}s, failed to remove host record", __func__); + return ERR_APPEXECFWK_FORM_COMMON_CODE; + } + + return ERR_OK; +} + +/** + * @brief Handle delete temp form. + * @param formId The form id. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormMgrAdapter::HandleDeleteTempForm(const int64_t formId, const sptr &callerToken) +{ + APP_LOGI("%{public}s called.", __func__); + + int uid = IPCSkeleton::GetCallingUid(); + FormRecord record; + bool isFormRecExist = FormDataMgr::GetInstance().GetFormRecord(formId, record); + bool isSelfTempFormId = false; + if (isFormRecExist && record.formTempFlg) { + isSelfTempFormId = (std::find(record.formUserUids.begin(), record.formUserUids.end(), uid) != + record.formUserUids.end()) ? true : false; + } + if (!isSelfTempFormId) { + APP_LOGE("%{public}s, not self form:%{public}lld", __func__, formId); + return ERR_OPERATION_FORM_NOT_SELF; + } + + FormDataMgr::GetInstance().DeleteFormUserUid(formId, uid); + if (!FormDataMgr::GetInstance().HasFormUserUids(formId)) { + int result = FormProviderMgr::GetInstance().NotifyProviderFormDelete(formId, record); + if (result != ERR_OK) { + APP_LOGE("%{public}s, failed!", __func__); + FormDataMgr::GetInstance().AddFormUserUid(formId, uid); + return result; + } + FormDataMgr::GetInstance().DeleteTempForm(formId); + FormDataMgr::GetInstance().DeleteFormRecord(formId); + if (!FormCacheMgr::GetInstance().DeleteData(formId)) { + APP_LOGE("%{public}s, failed to remove cache data", __func__); + return ERR_APPEXECFWK_FORM_COMMON_CODE; + } + } + + if (!FormDataMgr::GetInstance().DeleteHostRecord(callerToken, formId)) { + APP_LOGE("%{public}s, failed to remove host record", __func__); + return ERR_APPEXECFWK_FORM_COMMON_CODE; + } + + APP_LOGD("%{public}s, record.formUserUids size: %{public}d", __func__, record.formUserUids.size()); + return ERR_OK; +} + +/** + * @brief Handle delete form cache. + * @param dbRecord Form storage information. + * @param uid calling user id. + * @param formId The form id. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormMgrAdapter::HandleDeleteFormCache(FormRecord &dbRecord, const int uid, const int64_t formId) +{ + APP_LOGD("%{public}s, delete formDBRecords, formId: %{public}lld", __func__, formId); + auto iter = std::find(dbRecord.formUserUids.begin(), dbRecord.formUserUids.end(), uid); + if (iter != dbRecord.formUserUids.end()) { + dbRecord.formUserUids.erase(iter); + } + + ErrCode result = ERR_OK; + if (dbRecord.formUserUids.empty()) { + result = FormProviderMgr::GetInstance().NotifyProviderFormDelete(formId, dbRecord); + if (result != ERR_OK) { + APP_LOGE("%{public}s, failed to notify provider form delete", __func__); + return result; + } + if (!FormDataMgr::GetInstance().DeleteFormRecord(formId)) { + APP_LOGE("%{public}s, failed to remove cache data", __func__); + return ERR_APPEXECFWK_FORM_COMMON_CODE; + } + if (result = FormDbCache::GetInstance().DeleteFormInfo(formId); result != ERR_OK) { + APP_LOGE("%{public}s, failed to remove db data", __func__); + return result; + } + + int32_t matchCount = FormDbCache::GetInstance().GetMatchCount(dbRecord.bundleName, dbRecord.moduleName); + if (matchCount == 0) { + FormBmsHelper::GetInstance().NotifyModuleRemovable(dbRecord.bundleName, dbRecord.moduleName); + } + + if (!FormCacheMgr::GetInstance().DeleteData(formId)) { + APP_LOGE("%{public}s, failed to remove cache data", __func__); + return ERR_APPEXECFWK_FORM_COMMON_CODE; + } + if (!FormTimerMgr::GetInstance().RemoveFormTimer(formId)) { + APP_LOGE("%{public}s, remove timer error", __func__); + return ERR_DELETE_FORM_TIMER; + } + return ERR_OK; + } + + if (result = FormDbCache::GetInstance().UpdateDBRecord(formId, dbRecord); result != ERR_OK) { + return result; + } + + APP_LOGD("%{public}s, dbRecord.formUserUids size: %{public}d", __func__, dbRecord.formUserUids.size()); + FormBmsHelper::GetInstance().NotifyModuleNotRemovable(dbRecord.bundleName, dbRecord.moduleName); + if (!FormDataMgr::GetInstance().DeleteFormUserUid(formId, uid)) { + APP_LOGE("%{public}s, failed to remove form user uid", __func__); + return ERR_APPEXECFWK_FORM_COMMON_CODE; + } + + return result; +} + + +/** + * @brief Update form with formId, send formId to form manager service. + * @param formId The Id of the form to update. + * @param bundleName Provider ability bundleName. + * @param formProviderData form provider data. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrAdapter::UpdateForm(const int64_t formId, const std::string &bundleName, +const FormProviderData &formProviderData) +{ + APP_LOGI("%{public}s start.", __func__); + + // check formId and bundleName + if (formId <= 0 || bundleName.empty()) { + APP_LOGE("%{public}s error, the passed in formId can't be negative or zero, bundleName is not empty.", + __func__); + return ERR_FORM_INVALID_PARAM; + } + + // get IBundleMgr + sptr iBundleMgr = FormBmsHelper::GetInstance().GetBundleMgr(); + if (iBundleMgr == nullptr) { + APP_LOGE("%{public}s error, failed to get IBundleMgr.", __func__); + return ERR_APPEXECFWK_FORM_GET_BUNDLE_FAILED; + } + + // check bundle uid for permission + int32_t userId {0}; + int32_t callingUid = IPCSkeleton::GetCallingUid(); + int32_t bundleUid = iBundleMgr->GetUidByBundleName(bundleName, userId); + if (bundleUid != callingUid) { + APP_LOGE("%{public}s error, permission denied, the updated form is not your own.", __func__); + return ERR_FORM_INVALID_PARAM; + } + + // find matched formId + int64_t matchedFormId = FormDataMgr::GetInstance().FindMatchedFormId(formId); + + // check exist and get the formRecord + FormRecord formRecord; + if (!FormDataMgr::GetInstance().GetFormRecord(matchedFormId, formRecord)) { + APP_LOGE("%{public}s error, not exist such form:%{public}lld.", __func__, matchedFormId); + return ERR_NOT_EXIST_ID; + } + + // check then form under current user + if (!FormDataMgr::GetInstance().IsCallingUidValid(formRecord.formUserUids)) { + APP_LOGE("%{public}s error, not under current user, formId:%{public}lld.", __func__, matchedFormId); + return ERR_NOT_EXIST_ID; + } + + // check bundleName match + if (formRecord.bundleName.compare(bundleName) != 0) { + APP_LOGE("%{public}s error, not match bundleName:%{public}s.", __func__, bundleName.c_str()); + return ERR_FORM_INVALID_PARAM; + } + + // update Form + return FormProviderMgr::GetInstance().UpdateForm(matchedFormId, formRecord, formProviderData); +} + +/** + * @brief Request form with formId and want, send formId and want to form manager service. + * @param formId The Id of the form to update. + * @param callerToken Caller ability token. + * @param want The want of the form to request. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrAdapter::RequestForm(const int64_t formId, const sptr &callerToken, const Want &want) +{ + APP_LOGI("%{public}s called.", __func__); + + if (callerToken == nullptr) { + APP_LOGE("%{public}s fail, callerToken can not be NULL.", __func__); + return ERR_APPEXECFWK_FORM_INVALID_PARAM; + } + + int64_t matchedFormId = FormDataMgr::GetInstance().FindMatchedFormId(formId); + + if (!FormDataMgr::GetInstance().ExistFormRecord(matchedFormId)) { + APP_LOGE("%{public}s fail, not exist such formId:%{public}lld.", __func__, matchedFormId); + return ERR_NOT_EXIST_ID; + } + + FormHostRecord formHostRecord; + bool isHostExist = FormDataMgr::GetInstance().GetMatchedHostClient(callerToken, formHostRecord); + if (!isHostExist) { + APP_LOGE("%{public}s fail, cannot find target client.", __func__); + return ERR_FORM_INVALID_PARAM; + } + + if (!formHostRecord.Contains(matchedFormId)) { + APP_LOGE("%{public}s fail, form is not self-owned.", __func__); + return ERR_OPERATION_FORM_NOT_SELF; + } + + APP_LOGI("%{public}s, find target client.", __func__); + return FormProviderMgr::GetInstance().RefreshForm(matchedFormId, want); +} + +/** + * @brief Form visible/invisible notify, send formIds to form manager service. + * + * @param formIds The vector of form Ids. + * @param callerToken Caller ability token. + * @param formVisibleType The form visible type, including FORM_VISIBLE and FORM_INVISIBLE. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormMgrAdapter::NotifyWhetherVisibleForms(const std::vector &formIds, +const sptr &callerToken, + const int32_t formVisibleType) +{ + APP_LOGI("%{public}s called.", __func__); + + if (callerToken == nullptr) { + APP_LOGE("%{public}s fail, callerToken can not be NULL.", __func__); + return ERR_APPEXECFWK_FORM_INVALID_PARAM; + } + + sptr iBundleMgr = FormBmsHelper::GetInstance().GetBundleMgr(); + if (iBundleMgr == nullptr) { + APP_LOGE("%{public}s fail, failed to get IBundleMgr.", __func__); + return ERR_APPEXECFWK_FORM_GET_BUNDLE_FAILED; + } + + int64_t matchedFormId; + std::map> eventMaps; + for (int64_t formId : formIds) { + if (formId <= 0) { + APP_LOGW("%{public}s, formId %{public}lld is less than 0", __func__, formId); + continue; + } + matchedFormId = FormDataMgr::GetInstance().FindMatchedFormId(formId); + FormRecord formRecord; + if (!FormDataMgr::GetInstance().GetFormRecord(matchedFormId, formRecord)) { + APP_LOGW("%{public}s fail, not exist such form, formId:%{public}lld.", __func__, matchedFormId); + continue; + } + + FormHostRecord formHostRecord; + bool hasFormHostRecord = FormDataMgr::GetInstance().GetMatchedHostClient(callerToken, formHostRecord); + if (!(hasFormHostRecord && formHostRecord.Contains(matchedFormId))) { + APP_LOGW("%{public}s fail, form is not belong to self, formId:%{public}lld.", __func__, matchedFormId); + continue; + } + + formRecord.formVisibleNotifyState = formVisibleType; + if (!FormDataMgr::GetInstance().UpdateFormRecord(matchedFormId, formRecord)) { + APP_LOGW("%{public}s fail, set formVisibleNotifyState error, formId:%{public}lld.", + __func__, matchedFormId); + continue; + } + + // If the form need refrsh flag is true and form visibleType is FORM_VISIBLE, refresh the form host. + if (formRecord.needRefresh && formVisibleType == Constants::FORM_VISIBLE) { + std::string cacheData; + // If the form has business cache, refresh the form host. + if (FormCacheMgr::GetInstance().GetData(matchedFormId, cacheData)) { + formRecord.formProviderInfo.SetFormDataString(cacheData); + formHostRecord.OnUpdate(matchedFormId, formRecord); + } + } + + // If the form provider is system app and the config item 'formVisibleNotify' is true, + // notify the form provider that the current form is visible. + BundleInfo bundleInfo; + if (iBundleMgr->GetBundleInfo(formRecord.bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo)) { + APP_LOGD("%{public}s, get bundle uid success", __func__); + if (!iBundleMgr->CheckIsSystemAppByUid(bundleInfo.uid)) { + APP_LOGW("%{public}s fail, form provider is not system app, formId:%{public}lld.", __func__, matchedFormId); + continue; + } + } else { + APP_LOGW("%{public}s fail, can not get bundleInfo's uid", __func__); + continue; + } + if (!formRecord.formVisibleNotify) { + APP_LOGW("%{public}s fail, the config item 'formVisibleNotify' is false, formId:%{public}lld.", + __func__, matchedFormId); + continue; + } + + std::string providerKey = formRecord.bundleName + Constants::NAME_DELIMITER + formRecord.abilityName; + auto iter = eventMaps.find(providerKey); + if (iter == eventMaps.end()) { + std::vector formEventsByProvider {matchedFormId}; + eventMaps.insert(std::make_pair(providerKey, formEventsByProvider)); + } else { + iter->second.emplace_back(matchedFormId); + } + } + + for (auto iter = eventMaps.begin(); iter != eventMaps.end(); iter++) { + if (HandleEventNotify(iter->first, iter->second, formVisibleType) != ERR_OK) { + APP_LOGW("%{public}s fail, HandleEventNotify error, key is %{public}s.", __func__, iter->first.c_str()); + } + } + + return ERR_OK; +} + +/** + * @brief Temp form to normal form. + * @param formId The Id of the form. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrAdapter::CastTempForm(const int64_t formId, const sptr &callerToken) +{ + if (formId <= 0 || callerToken == nullptr) { + APP_LOGE("%{public}s, invalid param", __func__); + return ERR_FORM_INVALID_PARAM; + } + + int64_t matchedFormId = FormDataMgr::GetInstance().FindMatchedFormId(formId); + if (!FormDataMgr::GetInstance().ExistFormRecord(matchedFormId) || + !FormDataMgr::GetInstance().ExistTempForm(matchedFormId)) { + APP_LOGE("%{public}s, not exist such temp form:%{public}lld", __func__, matchedFormId); + return ERR_NOT_EXIST_ID; + } + + FormHostRecord record; + bool hasHostRec = FormDataMgr::GetInstance().GetFormHostRecord(matchedFormId, record); + if (!hasHostRec || !record.Contains(matchedFormId)) { + APP_LOGE("%{public}s, not self form:%{public}lld", __func__, matchedFormId); + return ERR_OPERATION_FORM_NOT_SELF; + } + + int callingUid = IPCSkeleton::GetCallingUid(); + int checkCode = FormDataMgr::GetInstance().CheckEnoughForm(callingUid); + if (checkCode != 0) { + APP_LOGE("%{public}s, %{public}lld failed,because if too mush forms", __func__, matchedFormId); + return checkCode; + } + + FormRecord formRecord; + if (!FormDataMgr::GetInstance().GetFormRecord(matchedFormId, formRecord)) { + APP_LOGE("%{public}s fail, not exist such form:%{public}lld.", __func__, matchedFormId); + return ERR_NOT_EXIST_ID; + } + int bindSupplierCheckCode = HandleCastTempForm(matchedFormId, formRecord); + if (bindSupplierCheckCode != 0) { + APP_LOGE("%{public}s, cast temp form bindSupplier failed", __func__); + return bindSupplierCheckCode; + } + + if (!FormDataMgr::GetInstance().DeleteTempForm(matchedFormId)) { + APP_LOGE("%{public}s fail, delete temp form error, formId:%{public}lld.", __func__, matchedFormId); + return ERR_APPEXECFWK_FORM_INFO_NOT_EXIST; + } + if (!FormDataMgr::GetInstance().ModifyFormTempFlg(matchedFormId, false)) { + APP_LOGE("%{public}s fail, modify form temp flag error, formId:%{public}lld.", __func__, matchedFormId); + return ERR_APPEXECFWK_FORM_INFO_NOT_EXIST; + } + if (!FormDataMgr::GetInstance().AddFormUserUid(matchedFormId, callingUid)) { + APP_LOGE("%{public}s fail, add form user uid error, formId:%{public}lld.", __func__, matchedFormId); + return ERR_APPEXECFWK_FORM_INFO_NOT_EXIST; + } + if (std::find(formRecord.formUserUids.begin(), formRecord.formUserUids.end(), + callingUid) == formRecord.formUserUids.end()) { + formRecord.formUserUids.emplace_back(callingUid); + } + if (ErrCode errorCode = FormDbCache::GetInstance().UpdateDBRecord(matchedFormId, formRecord); errorCode != ERR_OK) { + APP_LOGE("%{public}s fail, update db record error, formId:%{public}lld.", __func__, matchedFormId); + return errorCode; + } + + // start timer + return AddFormTimer(formRecord); +} +/** + * @brief Handle cast temp form. + * @param formId The form id. + * @param record Form information. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormMgrAdapter::HandleCastTempForm(const int64_t formId, const FormRecord &record) +{ + APP_LOGD("%{public}s, cast temp form to normal form, notify supplier, package:%{public}s, class:%{public}s", + __func__, record.bundleName.c_str(), record.abilityName.c_str()); + sptr castTempConnection = new FormCastTempConnection(formId); + + Want want; + want.AddFlags(Want::FLAG_ABILITY_FORM_ENABLED); + want.SetElementName(record.bundleName, record.abilityName); + return FormAmsHelper::GetInstance().ConnectServiceAbility(want, castTempConnection); +} +/** + * @brief Dump all of form storage infos. + * @param formInfos All of form storage infos. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrAdapter::DumpStorageFormInfos(std::string &formInfos) const +{ + std::vector formDBInfos; + FormDbCache::GetInstance().GetAllFormInfo(formDBInfos); + if(formDBInfos.size() > 0) { + std::sort(formDBInfos.begin(), formDBInfos.end(), [] (FormDBInfo &formDBInfoA, FormDBInfo &formDBInfoB) -> bool { + return formDBInfoA.formId < formDBInfoB.formId; + }); + FormDumpMgr::GetInstance().DumpStorageFormInfos(formDBInfos, formInfos); + return ERR_OK; + } else { + return ERR_APPEXECFWK_FORM_INFO_NOT_EXIST; + } +} +/** + * @brief Dump form info by a bundle name. + * @param bundleName The bundle name of form provider. + * @param formInfos Form infos. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrAdapter::DumpFormInfoByBundleName(const std::string &bundleName, std::string &formInfos) const +{ + APP_LOGI("%{public}s called.", __func__); + std::vector formRecordInfos; + if (FormDataMgr::GetInstance().GetFormRecord(bundleName, formRecordInfos)) { + FormDumpMgr::GetInstance().DumpFormInfos(formRecordInfos, formInfos); + return ERR_OK; + } else { + return ERR_APPEXECFWK_FORM_INFO_NOT_EXIST; + } +} +/** + * @brief Dump form info by a bundle name. + * @param formId The id of the form. + * @param formInfo Form info. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrAdapter::DumpFormInfoByFormId(const std::int64_t formId, std::string &formInfo) const +{ + APP_LOGI("%{public}s called.", __func__); + int reply = ERR_APPEXECFWK_FORM_INFO_NOT_EXIST; + + FormRecord formRecord; + if (FormDataMgr::GetInstance().GetFormRecord(formId, formRecord)) { + FormDumpMgr::GetInstance().DumpFormInfo(formRecord, formInfo); + reply = ERR_OK; + } + + FormHostRecord formHostRecord; + if (FormDataMgr::GetInstance().GetFormHostRecord(formId, formHostRecord)) { + FormDumpMgr::GetInstance().DumpFormHostInfo(formHostRecord, formInfo); + reply = ERR_OK; + } + + return reply; +} +/** + * @brief Get form configure info. + * @param want The want of the request. + * @param formItemInfo Form configure info. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormMgrAdapter::GetFormConfigInfo(const Want &want, FormItemInfo &formConfigInfo) +{ + APP_LOGD("GetFormConfigInfo start."); + BundleInfo bundleInfo; + std::string packageName; + + ErrCode errCode = GetBundleInfo(want, bundleInfo, packageName); + if (errCode != ERR_OK) { + APP_LOGE("addForm find bundle info failed"); + return errCode; + } + + FormInfo formInfo; + errCode = GetFormInfo(want, formInfo); + if (errCode != ERR_OK) { + APP_LOGE("addForm can not find target form info"); + return errCode; + } + + errCode = GetFormItemInfo(want, bundleInfo, formInfo, formConfigInfo); + if (errCode != ERR_OK) { + APP_LOGE("get form item info failed."); + return errCode; + } + formConfigInfo.SetPackageName(packageName); + + APP_LOGD("GetFormConfigInfo end."); + return ERR_OK; +} +/** + * @brief Allocate form by formId. + * @param info Form configure info. + * @param callerToken Caller ability token. + * @param wantParams WantParams of the request. + * @param formInfo Form info for form host. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormMgrAdapter::AllotFormById(const FormItemInfo &info, const sptr &callerToken, +const WantParams &wantParams, FormJsInfo &formInfo) +{ + int64_t formId = PaddingUDIDHash(info.GetFormId()); + FormRecord record; + bool hasRecord = FormDataMgr::GetInstance().GetFormRecord(formId, record); + if (hasRecord && record.formTempFlg) { + APP_LOGE("%{public}s, addForm can not acquire temp form when select form id", __func__); + return ERR_APPEXECFWK_FORM_COMMON_CODE; + } + + if (hasRecord && FormDataMgr::GetInstance().IsCallingUidValid(record.formUserUids)) { + if (!info.IsMatch(record)) { + APP_LOGE("%{public}s, formId and item info not match:%{public}lld", __func__, formId); + return ERR_CFG_NOT_MATCH_ID; + } + return AddExistFormRecord(info, callerToken, record, formId, wantParams); + } + + // find in db but not in cache + FormRecord dbRecord; + ErrCode getDbRet = FormDbCache::GetInstance().GetDBRecord(formId, dbRecord); + if (getDbRet == ERR_OK && FormDataMgr::GetInstance().IsCallingUidValid(dbRecord.formUserUids)) { + return AddNewFormRecord(info, formId, callerToken, wantParams, formInfo); + } + + APP_LOGI("%{public}s, addForm no such form %{public}lld", __func__, formId); + + // delete form data in provider + FormRecord delRecord; + delRecord.bundleName = info.GetProviderBundleName(); + delRecord.abilityName = info.GetAbilityName(); + FormProviderMgr::GetInstance().NotifyProviderFormDelete(formId, delRecord); + + return ERR_NOT_EXIST_ID; +} +int64_t FormMgrAdapter::PaddingUDIDHash(const int64_t formId) const +{ + // Compatible with int form id. + if ((formId & 0xffffffff00000000L) == 0) { + return FormDataMgr::GetInstance().GetUdidHash() | formId; + } + return formId; +} +ErrCode FormMgrAdapter::AddExistFormRecord(const FormItemInfo &info, const sptr &callerToken, + const FormRecord &record, const int64_t formId, const WantParams &wantParams) +{ + APP_LOGI("%{public}s call, formId:%{public}lld", __func__, formId); + // allot form host record + int callingUid = IPCSkeleton::GetCallingUid(); + bool isCreated = FormDataMgr::GetInstance().AllotFormHostRecord(info, callerToken, formId, callingUid); + if (!isCreated) { + APP_LOGE("%{public}s fail, AllotFormHostRecord failed when no matched formRecord", __func__); + return ERR_APPEXECFWK_FORM_COMMON_CODE; + } + + FormRecord newRecord(record); + if (newRecord.needRefresh) { + newRecord.isInited = false; + FormDataMgr::GetInstance().SetFormCacheInited(formId, false); + // acquire formInfo from provider + ErrCode errorCode = AcquireProviderFormInfoAsync(formId, info, wantParams); + if (errorCode != ERR_OK) { + APP_LOGE("%{public}s fail, AcquireProviderFormInfoAsync failed", __func__); + return errorCode; + } + } + + // Add new form user uid. + FormDataMgr::GetInstance().AddFormUserUid(formId, callingUid); + if (std::find(newRecord.formUserUids.begin(), newRecord.formUserUids.end(), callingUid) == + newRecord.formUserUids.end()) { + newRecord.formUserUids.emplace_back(callingUid); + } + + // start update timer + if (ErrCode errorCode = AddFormTimer(newRecord); errorCode != ERR_OK) { + return errorCode; + } + + if (!newRecord.formTempFlg) { + return FormDbCache::GetInstance().UpdateDBRecord(formId, newRecord); + } + return ERR_OK; +} +/** + * @brief Allocate form by form configure info. + * @param info Form configure info. + * @param callerToken Caller ability token. + * @param wantParams WantParams of the request. + * @param formInfo Form info for form host. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormMgrAdapter::AllotFormByInfo(const FormItemInfo &info, const sptr &callerToken, +const WantParams &wantParams, FormJsInfo &formInfo) +{ + // generate formId + int64_t newFormId = FormDataMgr::GetInstance().GenerateFormId(); + if (newFormId < 0) { + APP_LOGE("%{public}s fail, generateFormId no invalid formId", __func__); + return ERR_APPEXECFWK_FORM_COMMON_CODE; + } + APP_LOGD("newFormId:%{public}lld", newFormId); + + return AddNewFormRecord(info, newFormId, callerToken, wantParams, formInfo); +} + +/** + * @brief Add new form record. + * @param info Form configure info. + * @param formId The form id. + * @param callerToken Caller ability token. + * @param wantParams WantParams of the request. + * @param formInfo Form info for form host. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormMgrAdapter::AddNewFormRecord(const FormItemInfo &info, const int64_t formId, + const sptr &callerToken, const WantParams &wantParams, FormJsInfo &formInfo) +{ + APP_LOGI("%{public}s start", __func__); + FormItemInfo newInfo(info); + newInfo.SetFormId(formId); + // allot form host record + int callingUid = IPCSkeleton::GetCallingUid(); + if (!FormDataMgr::GetInstance().AllotFormHostRecord(newInfo, callerToken, formId, callingUid)) { + APP_LOGE("%{public}s fail, AllotFormHostRecord failed when no matched formRecord", __func__); + return ERR_APPEXECFWK_FORM_COMMON_CODE; + } + + // allot form record + FormRecord formRecord = FormDataMgr::GetInstance().AllotFormRecord(newInfo, callingUid); + + // acquire formInfo from provider + if (ErrCode errorCode = AcquireProviderFormInfoAsync(formId, newInfo, wantParams); errorCode != ERR_OK) { + APP_LOGE("%{public}s fail, AcquireProviderFormInfoAsync failed", __func__); + return errorCode; + } + + // create form info for js + FormDataMgr::GetInstance().CreateFormInfo(formId, formRecord, formInfo); + + // storage info + if (!newInfo.IsTemporaryForm()) { + if (ErrCode errorCode = FormDbCache::GetInstance().UpdateDBRecord(formId, formRecord); errorCode != ERR_OK) { + return errorCode; + } + } + + // start update timer + return AddFormTimer(formRecord); +} + +/** + * @brief Add form timer. + * @param formRecord Form information. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormMgrAdapter::AddFormTimer(const FormRecord &formRecord) +{ + APP_LOGI("%{public}s start", __func__); + if (formRecord.isEnableUpdate && !formRecord.formTempFlg) { + bool timerRet = false; + if (formRecord.updateDuration > 0) { + timerRet = FormTimerMgr::GetInstance().AddFormTimer(formRecord.formId, formRecord.updateDuration); + } else { + timerRet = FormTimerMgr::GetInstance().AddFormTimer(formRecord.formId, formRecord.updateAtHour, + formRecord.updateAtMin); + } + if (!timerRet) { + APP_LOGE("%{public}s fail, add form timer failed", __func__); + return ERR_APPEXECFWK_FORM_COMMON_CODE; + } + } + APP_LOGI("%{public}s end", __func__); + return ERR_OK; +} + +/** + * @brief Send event notify to form provider. The event notify type include FORM_VISIBLE and FORM_INVISIBLE. + * + * @param providerKey The provider key string which consists of the provider bundle name and ability name. + * @param formIdsByProvider The vector of form Ids which have the same provider. + * @param formVisibleType The form visible type, including FORM_VISIBLE and FORM_INVISIBLE. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormMgrAdapter::HandleEventNotify(const std::string &providerKey, const std::vector &formIdsByProvider, + const int32_t formVisibleType) +{ + APP_LOGI("%{public}s called.", __func__); + + sptr formEventNotifyConnection = new FormEventNotifyConnection(formIdsByProvider, + formVisibleType); + Want connectWant; + connectWant.AddFlags(Want::FLAG_ABILITY_FORM_ENABLED); + size_t position = providerKey.find(Constants::NAME_DELIMITER); + connectWant.SetElementName(providerKey.substr(0, position), + providerKey.substr(position + Constants::NAME_DELIMITER.size())); + + ErrCode errorCode = FormAmsHelper::GetInstance().ConnectServiceAbility(connectWant, formEventNotifyConnection); + if (errorCode != ERR_OK) { + APP_LOGE("%{public}s fail, ConnectServiceAbility failed.", __func__); + return errorCode; + } + + return ERR_OK; +} + +/** + * @brief Acquire form data from form provider. + * @param formId The Id of the form. + * @param info Form configure info. + * @param wantParams WantParams of the request. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormMgrAdapter::AcquireProviderFormInfoAsync(const int64_t formId, const FormItemInfo &info, +const WantParams &wantParams) +{ + if (formId <= 0) { + APP_LOGE("%{public}s fail, formId should be greater than 0", __func__); + return ERR_APPEXECFWK_FORM_INVALID_PARAM; + } + + sptr formAcquireConnection + = new FormAcquireConnection(formId, info, wantParams); + Want want; + want.SetElementName(info.GetProviderBundleName(), info.GetAbilityName()); + want.AddFlags(Want::FLAG_ABILITY_FORM_ENABLED); + return FormAmsHelper::GetInstance().ConnectServiceAbility(want, formAcquireConnection); +} + +/** + * @brief Get bundle info. + * @param want The want of the request. + * @param bundleInfo Bundle info. + * @param packageName Package name. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormMgrAdapter::GetBundleInfo(const AAFwk::Want &want, BundleInfo &bundleInfo, std::string &packageName) +{ + APP_LOGD("GetBundleMgr start."); + std::string bundleName = want.GetElement().GetBundleName(); + std::string abilityName = want.GetElement().GetAbilityName(); + std::string deviceId = want.GetElement().GetDeviceID(); + std::string moduleName = want.GetStringParam(Constants::PARAM_MODULE_NAME_KEY); + if (bundleName.empty() || abilityName.empty() || moduleName.empty()) { + APP_LOGE("GetBundleInfo bundleName or abilityName or moduleName is invalid"); + return ERR_APPEXECFWK_FORM_INVALID_PARAM; + } + + sptr iBundleMgr = FormBmsHelper::GetInstance().GetBundleMgr(); + if (iBundleMgr == nullptr) { + APP_LOGE("GetBundleMgr, failed to get IBundleMgr."); + return ERR_APPEXECFWK_FORM_GET_BUNDLE_FAILED; + } + + if (iBundleMgr->GetBundleInfo(bundleName, AppExecFwk::BundleFlag::GET_BUNDLE_WITH_ABILITIES, bundleInfo) != true) { + APP_LOGE("GetBundleInfo, failed to get bundle info."); + return ERR_APPEXECFWK_FORM_GET_INFO_FAILED; + } + + bool moduleExist = false; + for (const auto &moduleInfo : bundleInfo.moduleNames) { + APP_LOGD("bundleInfo.moduleNames, module name:%{public}s", moduleInfo.c_str()); + if (moduleInfo.compare(moduleName) == 0) { + moduleExist = true; + break; + } + } + if (!moduleExist) { + APP_LOGE("GetBundleInfo no such module, name:%{public}s", moduleName.c_str()); + return ERR_APPEXECFWK_FORM_NO_SUCH_MODULE; + } + + for (const auto &abilityInfo : bundleInfo.abilityInfos) { + // if (abilityInfo.moduleName.compare(GetFullClassName(abilityInfo.package, abilityName)) == 0) { + // packageName = abilityInfo.package; + // break; + // } + if (abilityInfo.deviceId == deviceId) { + packageName = abilityInfo.package; + break; + } + } + + if (packageName.empty()) { + APP_LOGE("GetBundleInfo can not find target ability %{public}s", abilityName.c_str()); + return ERR_APPEXECFWK_FORM_NO_SUCH_ABILITY; + } + APP_LOGD("GetBundleMgr end."); + return ERR_OK; +} +/** + * @brief Get form info. + * @param want The want of the request. + * @param packageName Package name. + * @param formInfo Form info. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormMgrAdapter::GetFormInfo(const AAFwk::Want &want, FormInfo &formInfo) +{ + APP_LOGD("GetFormInfo start."); + std::string bundleName = want.GetElement().GetBundleName(); + std::string abilityName = want.GetElement().GetAbilityName(); + std::string moduleName = want.GetStringParam(Constants::PARAM_MODULE_NAME_KEY); + if (bundleName.empty() || abilityName.empty() || moduleName.empty()) { + APP_LOGE("addForm bundleName or abilityName or moduleName is invalid"); + return ERR_APPEXECFWK_FORM_INVALID_PARAM; + } + sptr iBundleMgr = FormBmsHelper::GetInstance().GetBundleMgr(); + if (iBundleMgr == nullptr) { + APP_LOGE("GetFormInfo, failed to get IBundleMgr."); + return ERR_APPEXECFWK_FORM_GET_BUNDLE_FAILED; + } + + std::vector formInfos; + if (iBundleMgr->GetFormsInfoByModule(bundleName, moduleName, formInfos) == false) { + APP_LOGE("GetFormsInfoByModule, failed to get form config info."); + return ERR_APPEXECFWK_FORM_GET_INFO_FAILED; + } + + std::string formName = want.GetStringParam(Constants::PARAM_FORM_NAME_KEY); + if (formName.empty()) { + for (const auto &form : formInfos) { + if (form.defaultFlag) { + formInfo = form; + APP_LOGD("GetFormInfo end."); + return ERR_OK; + } + } + } else { + for (const auto &form : formInfos) { + if (form.name == formName) { + formInfo = form; + APP_LOGD("GetFormInfo end."); + return ERR_OK; + } + } + } + APP_LOGE("failed to get form info failed."); + return ERR_APPEXECFWK_FORM_GET_INFO_FAILED; +} +/** + * @brief Get form configure info. + * @param want The want of the request. + * @param bundleInfo Bundle info. + * @param formInfo Form info. + * @param formItemInfo Form configure info. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormMgrAdapter::GetFormItemInfo(const AAFwk::Want &want, const BundleInfo &bundleInfo, + const FormInfo &formInfo, FormItemInfo &formItemInfo) +{ + APP_LOGD("GetFormItemInfo start."); + int32_t dimensionId = want.GetIntParam(Constants::PARAM_FORM_DIMENSION_KEY, formInfo.defaultDimension); + if (!IsDimensionValid(formInfo, dimensionId)) { + APP_LOGE("addForm, dimension is not valid"); + return ERR_APPEXECFWK_FORM_NO_SUCH_DIMENSION; + } + + // int32_t orientation = want.GetIntParam(Constants::PARAM_FORM_ORIENTATION_KEY, Constants::ORIENTATION_PORTRAIT); + // if (orientation != Constants::ORIENTATION_PORTRAIT && orientation != Constants::ORIENTATION_LANDSCAPE) { + // orientation = Constants::ORIENTATION_PORTRAIT; + // } + + if (ErrCode ret = CreateFormItemInfo(bundleInfo, formInfo, formItemInfo); ret != ERR_OK) { + return ret; + } + // formItemInfo.SetFormId(formId); + // formItemInfo.orientation_ = orientation; + formItemInfo.SetSpecificationId(dimensionId); + formItemInfo.SetTemporaryFlag(want.GetBoolParam(Constants::PARAM_FORM_TEMPORARY_KEY, false)); + + APP_LOGD("GetFormItemInfo end."); + return ERR_OK; +} +/** + * @brief Dimension valid check. + * @param formInfo Form info. + * @param dimensionId Dimension id. + * @return Returns true on success, false on failure. + */ +bool FormMgrAdapter::IsDimensionValid(const FormInfo &formInfo, int dimensionId) const +{ + if (formInfo.supportDimensions.empty()) { + APP_LOGE("Js form, no support dimension."); + return false; + } + + for (size_t i = 0; i < formInfo.supportDimensions.size() && i < Constants::MAX_LAYOUT; i++) { + int supportDimensionId = formInfo.supportDimensions[i]; + if (supportDimensionId == dimensionId) { + return true; + } + } + + APP_LOGE("No matched dimension found."); + return false; +} +/** + * @brief Create form configure info. + * @param bundleInfo Bundle info. + * @param formInfo Form info. + * @param itemInfo Form configure info. + */ +ErrCode FormMgrAdapter::CreateFormItemInfo(const BundleInfo &bundleInfo, const FormInfo &formInfo, +FormItemInfo &itemInfo) +{ + itemInfo.SetProviderBundleName(bundleInfo.name); + sptr iBundleMgr = FormBmsHelper::GetInstance().GetBundleMgr(); + if (iBundleMgr == nullptr) { + APP_LOGE("GetFormInfo, failed to get IBundleMgr."); + return ERR_APPEXECFWK_FORM_GET_BUNDLE_FAILED; + } + std::string hostBundleName {}; + if (!iBundleMgr->GetBundleNameForUid(IPCSkeleton::GetCallingUid(), hostBundleName)) { + APP_LOGE("GetFormsInfoByModule, failed to get form config info."); + return ERR_APPEXECFWK_FORM_GET_INFO_FAILED; + } + itemInfo.SetHostBundleName(hostBundleName); + itemInfo.SetAbilityName(formInfo.abilityName); + itemInfo.SetModuleName(formInfo.name); // formInfo.moduleName: bundleMagr do not set + itemInfo.SetFormName(formInfo.name); + itemInfo.SetEnableUpdateFlag(formInfo.updateEnabled); + itemInfo.SetUpdateDuration(formInfo.updateDuration); + itemInfo.SetScheduledUpdateTime(formInfo.scheduledUpateTime); + itemInfo.SetJsComponentName(formInfo.jsComponentName); + itemInfo.SetFormVisibleNotify(formInfo.formVisibleNotify); + + for (const auto &abilityInfo : bundleInfo.abilityInfos) { + if (abilityInfo.name == formInfo.abilityName) { + itemInfo.SetAbilityModuleName(abilityInfo.moduleName); + } + } + + for (const auto &item : bundleInfo.applicationInfo.moduleInfos) { + if (formInfo.moduleName == item.moduleName) { + itemInfo.AddHapSourceDirs(item.moduleSourceDir); + } + itemInfo.AddModuleInfo(item.moduleName, item.moduleSourceDir); + } + return ERR_OK; +} + +/** + * @brief set next refresh time. + * @param formId The id of the form. + * @param nextTime next refresh time. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrAdapter::SetNextRefreshTime(const int64_t formId, const int64_t nextTime) +{ + APP_LOGI("%{public}s begin here, formId:%{public}lld,nextTime:%{public}lld", __func__, formId, nextTime); + if (formId <= 0) { + APP_LOGE("%{public}s form formId or bundleName is invalid", __func__); + return ERR_FORM_INVALID_PARAM; + } + int64_t matchedFormId = FormDataMgr::GetInstance().FindMatchedFormId(formId); + + std::string bundleName; + if (!GetBundleName(bundleName)) { + return ERR_APPEXECFWK_FORM_INFO_NOT_EXIST; + } + + FormRecord formRecord; + if (!FormDataMgr::GetInstance().GetFormRecord(matchedFormId, formRecord)) { + APP_LOGE("%{public}s, not found in formrecord.", __func__); + return ERR_APPEXECFWK_FORM_INFO_NOT_EXIST; + } + // check bundleName + if (bundleName != formRecord.bundleName) { + APP_LOGE("%{public}s, not match bundleName:%{public}s", __func__, bundleName.c_str()); + return ERR_OPERATION_FORM_NOT_SELF; + } + + return SetNextRefreshtTimeLocked(matchedFormId, nextTime); +} + +/** + * @brief get bundleName. + * @param bundleName for output. + * @return Returns true on success, others on failure. + */ +bool FormMgrAdapter::GetBundleName(std::string &bundleName) +{ + sptr iBundleMgr = FormBmsHelper::GetInstance().GetBundleMgr(); + if (iBundleMgr == nullptr) { + APP_LOGE("%{public}s, failed to get IBundleMgr.", __func__); + return false; + } + + int32_t uid = IPCSkeleton::GetCallingUid(); + if (!iBundleMgr->CheckIsSystemAppByUid(uid)) { + APP_LOGE("%{public}s fail, form is not system app. uid:%{public}d", __func__, uid); + return false; + } + + bool result = iBundleMgr->GetBundleNameForUid(uid, bundleName); + if (!result || bundleName.empty()) { + APP_LOGE("%{public}s failed, cannot get bundle name by uid:%{public}d", __func__, uid); + return false; + } + return true; +} + +/** + * @brief set next refresht time locked. + * @param formId The form's id. + * @param nextTime next refresh time. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrAdapter::SetNextRefreshtTimeLocked(const int64_t formId, const int64_t nextTime) +{ + APP_LOGE("SetNextRefreshtTimeLocked."); + int32_t timerRefreshedCount = FormTimerMgr::GetInstance().GetRefreshCount(formId); + if (timerRefreshedCount >= Constants::LIMIT_COUNT) { + APP_LOGE("%{public}s, already refresh times:%{public}d", __func__, timerRefreshedCount); + FormTimerMgr::GetInstance().MarkRemind(formId); + return ERR_MAX_REFRESH; + } + + if (!FormTimerMgr::GetInstance().SetNextRefreshTime(formId, nextTime)) { + APP_LOGE("%{public}s failed", __func__); + return ERR_CODE_COMMON; + } + + return ERR_OK; +} + +/** + * @brief set next refresht time locked. + * @param formId The form's id. + * @param bundleName Provider ability bundleName. + * @return Returns true or false. + */ +bool FormMgrAdapter::IsUpdateValid(const int64_t formId, const std::string &bundleName) +{ + if (formId <= 0 || bundleName.empty()) { + return false; + } + return true; +} + +/** + * @brief enable update form. + * @param formIDs The id of the forms. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrAdapter::EnableUpdateForm(const std::vector formIDs, const sptr &callerToken) +{ + APP_LOGI("enableUpdateForm"); + return HandleUpdateFormFlag(formIDs, callerToken, true); +} + +/** + * @brief disable update form. + * @param formIDs The id of the forms. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrAdapter::DisableUpdateForm(const std::vector formIDs, const sptr &callerToken) +{ + APP_LOGI("disableUpdateForm"); + return HandleUpdateFormFlag(formIDs, callerToken, false); +} + +/** + * @brief Process js message event. + * @param formId Indicates the unique id of form. + * @param want information passed to supplier. + * @param callerToken Caller ability token. + * @return Returns true if execute success, false otherwise. + */ +int FormMgrAdapter::MessageEvent(const int64_t formId, const Want &want, const sptr &callerToken) +{ + APP_LOGI("%{public}s called.", __func__); + if (formId <= 0) { + APP_LOGE("%{public}s form formId or bundleName is invalid", __func__); + return ERR_APPEXECFWK_FORM_INVALID_PARAM; + } + + if (callerToken == nullptr) { + APP_LOGE("%{public}s failed, callerToken can not be NULL", __func__); + return ERR_APPEXECFWK_FORM_INVALID_PARAM; + } + + if (!want.HasParameter(Constants::PARAM_MESSAGE_KEY)) { + APP_LOGE("%{public}s failed, message info is not exist", __func__); + return ERR_APPEXECFWK_FORM_INVALID_PARAM; + } + + int64_t matchedFormId = FormDataMgr::GetInstance().FindMatchedFormId(formId); + FormRecord record; + bool bGetRecord = FormDataMgr::GetInstance().GetFormRecord(matchedFormId, record); + if (!bGetRecord) { + APP_LOGE("%{public}s fail, not exist such form:%{public}lld", __func__, matchedFormId); + return ERR_APPEXECFWK_FORM_INFO_NOT_EXIST; + } + + FormHostRecord formHostRecord; + bool isHostExist = FormDataMgr::GetInstance().GetMatchedHostClient(callerToken, formHostRecord); + if (!isHostExist) { + APP_LOGE("%{public}s failed, cannot find target client.", __func__); + return ERR_APPEXECFWK_FORM_HOST_INFO_NOT_EXIST; + } + + if (!formHostRecord.Contains(matchedFormId)) { + APP_LOGE("%{public}s failed, form is not self-owned.", __func__); + return ERR_OPERATION_FORM_NOT_SELF; + } + + APP_LOGI("%{public}s, find target client.", __func__); + return FormProviderMgr::GetInstance().MessageEvent(matchedFormId, record, want); +} + +int FormMgrAdapter::HandleUpdateFormFlag(std::vector formIds, const sptr &callerToken, +bool flag) +{ + APP_LOGI("%{public}s called.", __func__); + if (formIds.empty() || callerToken == nullptr) { + APP_LOGE("%{public}s, invalid param", __func__); + return ERR_FORM_INVALID_PARAM; + } + std::vector refreshForms; + int errCode = FormDataMgr::GetInstance().UpdateHostFormFlag(formIds, callerToken, flag, refreshForms); + if (errCode == ERR_OK && refreshForms.size() > 0) { + for (const int64_t id : refreshForms) { + APP_LOGI("%{public}s, formRecord need refresh: %{public}lld", __func__, id); + Want want; + FormProviderMgr::GetInstance().RefreshForm(id, want); + } + } + return errCode; +} + +/** + * @brief handle update form flag. + * @param formIDs The id of the forms. + * @param callerToken Caller ability token. + * @param flag form flag. + * @return Returns ERR_OK on success, others on failure. + */ +bool FormMgrAdapter::IsFormCached(const FormRecord record) { + if (record.versionUpgrade) { + return false; + } + return true; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/formmgr/src/form_mgr_service.cpp b/services/formmgr/src/form_mgr_service.cpp new file mode 100644 index 0000000000..8eb194ba67 --- /dev/null +++ b/services/formmgr/src/form_mgr_service.cpp @@ -0,0 +1,388 @@ +/* + * Copyright (c) 2021 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 +#include +#include + +#include "appexecfwk_errors.h" +#include "app_log_wrapper.h" +#include "form_bms_helper.h" +#include "form_constants.h" +#include "form_data_mgr.h" +#include "form_db_cache.h" +#include "form_mgr_service.h" +#include "form_task_mgr.h" +#include "form_timer_mgr.h" +#include "ipc_skeleton.h" +#include "iservice_registry.h" +#include "permission/permission_kit.h" +#include "permission/permission.h" +#include "string_ex.h" +#include "system_ability_definition.h" + +namespace OHOS { +namespace AppExecFwk { +using namespace std::chrono; +using PermissionKit = OHOS::Security::Permission::PermissionKit; +using PermissionState = OHOS::Security::Permission::PermissionState; + +const bool REGISTER_RESULT = + SystemAbility::MakeAndRegisterAbility(DelayedSingleton::GetInstance().get()); + +const std::string NAME_FORM_MGR_SERVICE = "FormMgrService"; + +FormMgrService::FormMgrService() + : SystemAbility(FORM_MGR_SERVICE_ID, true), + state_(ServiceRunningState::STATE_NOT_START), + runner_(nullptr), + handler_(nullptr), + formMgrAdapter_(std::make_unique()) +{ +} + +FormMgrService::~FormMgrService() +{} + +bool FormMgrService::IsReady() const +{ + if (state_ != ServiceRunningState::STATE_RUNNING) { + return false; + } + if (!handler_) { + APP_LOGE("%{public}s fail, handler is null", __func__); + return false; + } + + return true; +} + +/** + * @brief Add form with want, send want to form manager service. + * @param formId The Id of the forms to add. + * @param want The want of the form to add. + * @param callerToken Caller ability token. + * @param formInfo Form info. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrService::AddForm(const int64_t formId, const Want &want, const sptr &callerToken, +FormJsInfo &formInfo) +{ + if (!CheckFormPermission()) { + APP_LOGE("%{public}s fail, add form permission denied", __func__); + return ERR_APPEXECFWK_FORM_PERMISSION_DENY; + } + return formMgrAdapter_->AddForm(formId, want, callerToken, formInfo); +} + +/** + * @brief Delete forms with formIds, send formIds to form manager service. + * @param formId The Id of the forms to delete. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrService::DeleteForm(const int64_t formId, const sptr &callerToken) +{ + if (!CheckFormPermission()) { + APP_LOGE("%{public}s fail, delete form permission denied", __func__); + return ERR_APPEXECFWK_FORM_PERMISSION_DENY; + } + + return formMgrAdapter_->DeleteForm(formId, callerToken); +} + +/** + * @brief Release forms with formIds, send formIds to form manager service. + * @param formId The Id of the forms to release. + * @param callerToken Caller ability token. + * @param delCache Delete Cache or not. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrService::ReleaseForm(const int64_t formId, const sptr &callerToken, const bool delCache) +{ + if (!CheckFormPermission()) { + APP_LOGE("%{public}s fail, release form permission denied", __func__); + return ERR_APPEXECFWK_FORM_PERMISSION_DENY; + } + + return formMgrAdapter_->ReleaseForm(formId, callerToken, delCache); +} + +/** + * @brief Update form with formId, send formId to form manager service. + * @param formId The Id of the form to update. + * @param bundleName Provider ability bundleName. + * @param formBindingData Form binding data. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrService::UpdateForm(const int64_t formId, const std::string &bundleName, +const FormProviderData &formBindingData) +{ + if (!CheckFormPermission()) { + APP_LOGE("%{public}s fail, update form permission denied", __func__); + return ERR_APPEXECFWK_FORM_PERMISSION_DENY; + } + return formMgrAdapter_->UpdateForm(formId, bundleName, formBindingData); +} + +/** + * @brief Request form with formId and want, send formId and want to form manager service. + * @param formId The Id of the form to update. + * @param callerToken Caller ability token. + * @param want The want of the form to add. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrService::RequestForm(const int64_t formId, const sptr &callerToken, const Want &want) +{ + APP_LOGI("%{public}s called.", __func__); + + if (!CheckFormPermission()) { + APP_LOGE("%{public}s fail, request form permission denied", __func__); + return ERR_APPEXECFWK_FORM_PERMISSION_DENY; + } + + return formMgrAdapter_->RequestForm(formId, callerToken, want); +} + +/** + * @brief set next refresh time. + * @param formId The id of the form. + * @param bundleManager the bundle manager ipc object. + * @param nextTime next refresh time. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrService::SetNextRefreshTime(const int64_t formId, const int64_t nextTime) +{ + APP_LOGI("%{public}s called.", __func__); + + return formMgrAdapter_->SetNextRefreshTime(formId, nextTime); +} + + +/** + * @brief Form visible/invisible notify, send formIds to form manager service. + * @param formIds The Id list of the forms to notify. + * @param callerToken Caller ability token. + * @param formVisibleType The form visible type, including FORM_VISIBLE and FORM_INVISIBLE. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrService::NotifyWhetherVisibleForms(const std::vector &formIds, +const sptr &callerToken, const int32_t formVisibleType) +{ + if (!CheckFormPermission()) { + APP_LOGE("%{public}s fail, event notify visible permission denied", __func__); + return ERR_APPEXECFWK_FORM_PERMISSION_DENY; + } + + return formMgrAdapter_->NotifyWhetherVisibleForms(formIds, callerToken, formVisibleType); +} + +/** + * @brief temp form to normal form. + * @param formId The Id of the form. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrService::CastTempForm(const int64_t formId, const sptr &callerToken) +{ + if (!CheckFormPermission()) { + APP_LOGE("%{public}s fail, cast temp form permission denied", __func__); + return ERR_APPEXECFWK_FORM_PERMISSION_DENY; + } + + return formMgrAdapter_->CastTempForm(formId, callerToken); +} + +/** + * @brief lifecycle update. + * @param formIds formIds of hostclient. + * @param callerToken Caller ability token. + * @param updateType update type,enable or disable. + * @return Returns true on success, false on failure. + */ +int FormMgrService::LifecycleUpdate(const std::vector &formIds, const sptr &callerToken, +const int32_t updateType) +{ + APP_LOGI("lifecycleUpdate."); + + if (!CheckFormPermission()) { + APP_LOGE("%{public}s fail, delete form permission denied", __func__); + return ERR_APPEXECFWK_FORM_PERMISSION_DENY; + } + + if (updateType == ENABLE_FORM_UPDATE) { + return formMgrAdapter_->EnableUpdateForm(formIds, callerToken); + } else { + return formMgrAdapter_->DisableUpdateForm(formIds, callerToken); + } +} +/** + * @brief Dump all of form storage infos. + * @param formInfos All of form storage infos. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrService::DumpStorageFormInfos(std::string &formInfos) +{ + return formMgrAdapter_->DumpStorageFormInfos(formInfos); +} +/** + * @brief Dump form info by a bundle name. + * @param bundleName The bundle name of form provider. + * @param formInfos Form infos. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrService::DumpFormInfoByBundleName(const std::string &bundleName, std::string &formInfos) +{ + return formMgrAdapter_->DumpFormInfoByBundleName(bundleName, formInfos); +} +/** + * @brief Dump form info by a bundle name. + * @param formId The id of the form. + * @param formInfo Form info. + * @return Returns ERR_OK on success, others on failure. + */ +int FormMgrService::DumpFormInfoByFormId(const std::int64_t formId, std::string &formInfo) +{ + return formMgrAdapter_->DumpFormInfoByFormId(formId, formInfo); +} +/** + * @brief Process js message event. + * @param formId Indicates the unique id of form. + * @param want information passed to supplier. + * @param callerToken Caller ability token. + * @return Returns true if execute success, false otherwise. + */ +int FormMgrService::MessageEvent(const int64_t formId, const Want &want, const sptr &callerToken) +{ + APP_LOGI("%{public}s called.", __func__); + + if (!CheckFormPermission()) { + APP_LOGE("%{public}s fail, request form permission denied", __func__); + return ERR_APPEXECFWK_FORM_PERMISSION_DENY; + } + + return formMgrAdapter_->MessageEvent(formId, want, callerToken); +} +/** + * @brief Start envent for the form manager service. + */ +void FormMgrService::OnStart() +{ + if (state_ == ServiceRunningState::STATE_RUNNING) { + APP_LOGW("%{public}s fail, Failed to start service since it's already running", __func__); + return; + } + + APP_LOGI("Form Mgr Service start..."); + ErrCode errCode = Init(); + if (errCode != ERR_OK) { + APP_LOGE("%{public}s fail, Failed to init, errCode: %{public}08x", __func__, errCode); + return; + } + + state_ = ServiceRunningState::STATE_RUNNING; + + APP_LOGI("Form Mgr Service start success."); +} +/** + * @brief Stop envent for the form manager service. + */ +void FormMgrService::OnStop() +{ + APP_LOGI("stop service"); + + state_ = ServiceRunningState::STATE_NOT_START; + + if (handler_) { + handler_.reset(); + } + + if (runner_) { + runner_.reset(); + } +} +/** + * @brief initialization of form manager service. + */ +ErrCode FormMgrService::Init() +{ + runner_ = EventRunner::Create(NAME_FORM_MGR_SERVICE); + if (!runner_) { + APP_LOGE("%{public}s fail, Failed to init due to create runner error", __func__); + return ERR_INVALID_OPERATION; + } + handler_ = std::make_shared(runner_); + if (!handler_) { + APP_LOGE("%{public}s fail, Failed to init due to create handler error", __func__); + return ERR_INVALID_OPERATION; + } + FormTaskMgr::GetInstance().SetEventHandler(handler_); + /* Publish service maybe failed, so we need call this function at the last, + * so it can't affect the TDD test program */ + bool ret = Publish(DelayedSingleton::GetInstance().get()); + if (!ret) { + APP_LOGE("%{public}s fail, FormMgrService::Init Publish failed!", __func__); + return ERR_INVALID_OPERATION; + } + + FormDbCache::GetInstance().Start(); + + APP_LOGI("init success"); + return ERR_OK; +} +/** + * @brief Permission check by callingUid. + * @param formId the id of the form. + * @return Returns true on success, false on failure. + */ +bool FormMgrService::CheckFormPermission() +{ + sptr iBundleMgr = FormBmsHelper::GetInstance().GetBundleMgr(); + if (iBundleMgr == nullptr) { + APP_LOGE("%{public}s, failed to get IBundleMgr.", __func__); + return false; + } + + int32_t uid = IPCSkeleton::GetCallingUid(); + if (!iBundleMgr->CheckIsSystemAppByUid(uid)) { + APP_LOGE("%{public}s fail, form is not system app. uid:%{public}d", __func__, uid); + return false; + } + + std::string bundleName; + bool result = iBundleMgr->GetBundleNameForUid(uid, bundleName); + if (!result || bundleName.empty()) { + APP_LOGE("%{public}s failed, cannot get bundle name by uid:%{public}d", __func__, uid); + return false; + } + + return CheckFormPermission(bundleName); +} + +bool FormMgrService::CheckFormPermission(const std::string &bundleName) const +{ + if (bundleName.empty()) { + APP_LOGE("%{public}s fail, bundleName can not be empty", __func__); + return false; + } + int result = PermissionKit::VerifyPermission(bundleName, Constants::PERMISSION_REQUIRE_FORM, 0); + if (result != PermissionState::PERMISSION_GRANTED) { + APP_LOGW("permission = %{public}s, bundleName = %{public}s, result = %{public}d", + Constants::PERMISSION_REQUIRE_FORM.c_str(), bundleName.c_str(), result); + } + return result == PermissionState::PERMISSION_GRANTED; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/formmgr/src/form_msg_event_connection.cpp b/services/formmgr/src/form_msg_event_connection.cpp new file mode 100644 index 0000000000..513b44865c --- /dev/null +++ b/services/formmgr/src/form_msg_event_connection.cpp @@ -0,0 +1,64 @@ + +/* + * Copyright (c) 2021 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 "appexecfwk_errors.h" +#include "app_log_wrapper.h" +#include "form_constants.h" +#include "form_msg_event_connection.h" +#include "form_supply_callback.h" +#include "form_task_mgr.h" +#include "ipc_types.h" +#include "message_parcel.h" +#include "want.h" + +namespace OHOS { +namespace AppExecFwk { +FormMsgEventConnection::FormMsgEventConnection(const int64_t formId, const Want& want) + :formId_(formId), + want_(want) +{ +} +/** + * @brief OnAbilityConnectDone, AbilityMs notify caller ability the result of connect. + * + * @param element Service ability's ElementName. + * @param remoteObject The session proxy of service ability. + * @param resultCode ERR_OK on success, others on failure. + * @return none. + */ +void FormMsgEventConnection::OnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) +{ + APP_LOGI("%{public}s called.", __func__); + + if (resultCode != ERR_OK) { + APP_LOGE("%{public}s, abilityName:%{public}s, formId:%{public}lld, resultCode:%{public}d", + __func__, element.GetAbilityName().c_str(), formId_, resultCode); + return; + } + FormSupplyCallback::GetInstance()->AddConnection(this); + + if (want_.HasParameter(Constants::PARAM_MESSAGE_KEY)) { + std::string message = want_.GetStringParam(Constants::PARAM_MESSAGE_KEY); + Want eventWant = Want(want_); + eventWant.SetParam(Constants::FORM_CONNECT_ID, this->GetConnectId()); + FormTaskMgr::GetInstance().PostFormEventTask(formId_, message, eventWant, remoteObject); + } else { + APP_LOGE("%{public}s error, message info is not exist", __func__); + } +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/formmgr/src/form_provider_mgr.cpp b/services/formmgr/src/form_provider_mgr.cpp new file mode 100644 index 0000000000..3ef53c1d9d --- /dev/null +++ b/services/formmgr/src/form_provider_mgr.cpp @@ -0,0 +1,369 @@ +/* + * Copyright (c) 2021 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 "appexecfwk_errors.h" +#include "app_log_wrapper.h" +#include "form_ams_helper.h" +#include "form_batch_delete_connection.h" +#include "form_cache_mgr.h" +#include "form_constants.h" +#include "form_data_mgr.h" +#include "form_delete_connection.h" +#include "form_msg_event_connection.h" +#include "form_provider_mgr.h" +#include "form_record.h" +#include "form_refresh_connection.h" +#include "form_timer_mgr.h" +#include "power_mgr_client.h" + +namespace OHOS { +namespace AppExecFwk { +FormProviderMgr::FormProviderMgr(){} +FormProviderMgr::~FormProviderMgr(){} +/** + * @brief handle for acquire back from ams. + * @param formId The id of the form. + * @param formProviderInfo provider form info. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormProviderMgr::AcquireForm(const int64_t formId, const FormProviderInfo &formProviderInfo) +{ + APP_LOGD("%{public}s start, formId:%{public}lld", __func__, formId); + + if (formId <= 0) { + APP_LOGE("%{public}s fail, formId should be greater than 0", __func__); + return ERR_FORM_INVALID_PARAM; + } + + FormRecord formRecord; + bool isGetFormRecord = FormDataMgr::GetInstance().GetFormRecord(formId, formRecord); + if (!isGetFormRecord) { + APP_LOGE("%{public}s fail, not exist such form, formId:%{public}lld", __func__, formId); + return ERR_APPEXECFWK_FORM_INFO_NOT_EXIST; + } + + FormHostRecord clientHost; + bool isGetFormHostRecord = FormDataMgr::GetInstance().GetFormHostRecord(formId, clientHost); + if (!isGetFormHostRecord) { + APP_LOGE("%{public}s fail, clientHost is null", __func__); + return ERR_APPEXECFWK_FORM_HOST_INFO_NOT_EXIST; + } + + if (formRecord.isInited) { + if (IsFormCached(formRecord)) { + if (clientHost.Contains(formId)) { + formRecord.formProviderInfo = formProviderInfo; + clientHost.OnAcquire(formId, formRecord); + } + } else { + Want want; + RefreshForm(formId, want); + } + return ERR_OK; + } + formRecord.isInited = true; + formRecord.needRefresh = false; + FormDataMgr::GetInstance().SetFormCacheInited(formId, true); + + if (clientHost.Contains(formId)) { + formRecord.formProviderInfo = formProviderInfo; + clientHost.OnAcquire(formId, formRecord); + } + + // we do not cache when data size is over 1k + std::string jsonData = formProviderInfo.GetFormDataString(); // get json data + APP_LOGD("%{public}s , jsonData is %{public}s.", __func__, jsonData.c_str()); + if (jsonData.size() <= Constants::MAX_FORM_DATA_SIZE) { + APP_LOGW("%{public}s, acquire js card, cache the card", __func__); + FormCacheMgr::GetInstance().AddData(formId, formProviderInfo.GetFormDataString()); + } + return ERR_OK; +} + +/** + * @brief Refresh form. + * + * @param formId The form id. + * @param want The want of the form to request. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormProviderMgr::RefreshForm(const int64_t formId, const Want &want) +{ + APP_LOGI("%{public}s called, formId:%{public}lld.", __func__, formId); + FormRecord record; + bool bGetRecord = FormDataMgr::GetInstance().GetFormRecord(formId, record); + if (!bGetRecord) { + APP_LOGE("%{public}s fail, not exist such form:%{public}lld", __func__, formId); + return ERR_APPEXECFWK_FORM_INFO_NOT_EXIST; + } + + bool isTimerRefresh = want.GetBoolParam(Constants::KEY_IS_TIMER, false); + Want newWant(want); + newWant.RemoveParam(Constants::KEY_IS_TIMER); + + if (isTimerRefresh) { + FormDataMgr::GetInstance().SetCountTimerRefresh(formId, true); + } + + bool screenOnFlag = PowerMgr::PowerMgrClient::GetInstance().IsScreenOn(); + if (!screenOnFlag) { + FormDataMgr::GetInstance().SetNeedRefresh(formId, true); + APP_LOGE("%{public}s fail, screen off, set refresh flag, do not refresh now", __func__); + return ERR_OK; + } + + bool needRefresh = FormDataMgr::GetInstance().IsEnableRefresh(formId); + if (!needRefresh) { + FormDataMgr::GetInstance().SetNeedRefresh(formId, true); + APP_LOGE("%{public}s fail, no one needReresh, set refresh flag, do not refresh now", __func__); + return ERR_OK; + } + + FormRecord refreshRecord = GetFormAbilityInfo(record); + refreshRecord.isInited = record.isInited; + refreshRecord.versionUpgrade = record.versionUpgrade; + refreshRecord.isCountTimerRefresh = isTimerRefresh; + return ConnectAmsForRefresh(formId, refreshRecord, newWant, isTimerRefresh); +} + +/** + * @brief Connect ams for refresh form + * + * @param formId The form id. + * @param record Form data. + * @param want The want of the form. + * @param isTimerRefresh The flag of timer refresh. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormProviderMgr::ConnectAmsForRefresh(const int64_t formId, const FormRecord &record, const Want &want, +const bool isTimerRefresh) +{ + APP_LOGD("%{public}s called, bundleName:%{public}s, abilityName:%{public}s.", + __func__, record.bundleName.c_str(), record.abilityName.c_str()); + + sptr formRefreshConnection = new FormRefreshConnection(formId, want); + Want connectWant; + connectWant.AddFlags(Want::FLAG_ABILITY_FORM_ENABLED); + connectWant.SetElementName(record.bundleName, record.abilityName); + + if (isTimerRefresh) { + if (!FormTimerMgr::GetInstance().IsLimiterEnableRefresh(formId)) { + APP_LOGE("%{public}s, timer refresh, already limit.", __func__); + return ERR_APPEXECFWK_FORM_SUPPLIER_DEL_FAIL; + } + } + + ErrCode errorCode = FormAmsHelper::GetInstance().ConnectServiceAbility(connectWant, formRefreshConnection); + if (errorCode != ERR_OK) { + APP_LOGE("%{public}s, ConnectServiceAbility failed.", __func__); + return errorCode; + } + + if (record.isCountTimerRefresh) { + IncreaseTimerRefreshCount(formId); + } + + return ERR_OK; +} + +/** + * @brief Notify provider form delete. + * @param formId The form id. + * @param record Form information. + * @return Function result and has other host flag. + */ +ErrCode FormProviderMgr::NotifyProviderFormDelete(const int64_t formId, const FormRecord &formRecord) +{ + if (formRecord.abilityName.empty()) { + APP_LOGE("%{public}s, formRecord.abilityName is empty.", __func__); + return ERR_CODE_COMMON; + } + + if (formRecord.bundleName.empty()) { + APP_LOGE("%{public}s, formRecord.bundleName is empty.", __func__); + return ERR_CODE_COMMON; + } + + APP_LOGD("%{public}s, connectAbility,bundleName:%{public}s, abilityName:%{public}s", + __func__, formRecord.bundleName.c_str(), formRecord.abilityName.c_str()); + sptr formDeleteConnection = new FormDeleteConnection(formId); + Want want; + want.SetElementName(formRecord.bundleName, formRecord.abilityName); + want.SetFlags(Want::FLAG_ABILITY_FORM_ENABLED); + return FormAmsHelper::GetInstance().ConnectServiceAbility(want, formDeleteConnection); +} + +/** + * @brief Notify provider forms batch delete. + * @param bundleName BundleName. + * @param bundleName AbilityName. + * @param formIds form id list. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormProviderMgr::NotifyProviderFormsBatchDelete(const std::string &bundleName, const std::string &abilityName, +const std::set &formIds) +{ + if (abilityName.empty()) { + APP_LOGE("%{public}s error, abilityName is empty.", __func__); + return ERR_APPEXECFWK_FORM_INVALID_PARAM; + } + + if (bundleName.empty()) { + APP_LOGE("%{public}s error, bundleName is empty.", __func__); + return ERR_APPEXECFWK_FORM_INVALID_PARAM; + } + + APP_LOGD("%{public}s, bundleName:%{public}s, abilityName:%{public}s", __func__, bundleName.c_str(), + abilityName.c_str()); + sptr batchDeleteConnection = new FormBatchDeleteConnection(formIds); + Want want; + want.AddFlags(Want::FLAG_ABILITY_FORM_ENABLED); + want.SetElementName(bundleName, abilityName); + + ErrCode errorCode = FormAmsHelper::GetInstance().ConnectServiceAbility(want, batchDeleteConnection); + if (errorCode != ERR_OK) { + APP_LOGE("%{public}s, ConnectServiceAbility failed.", __func__); + return errorCode; + } + return ERR_OK; +} +/** + * @brief Update form. + * @param formId The form's id. + + * @param formProviderData form provider data. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormProviderMgr::UpdateForm(const int64_t formId, const FormProviderInfo &formProviderInfo) +{ + // check exist and get the formRecord + FormRecord formRecord; + if (!FormDataMgr::GetInstance().GetFormRecord(formId, formRecord)) { + APP_LOGE("%{public}s error, not exist such form:%{public}lld.", __func__, formId); + return ERR_NOT_EXIST_ID; + } + return UpdateForm(formId, formRecord, formProviderInfo.GetFormData()); +} +/** + * handle for update form event from provider. + * + * @param formId The id of the form. + * @param formRecord The form's record. + * @param formProviderData provider form info. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormProviderMgr::UpdateForm(const int64_t formId, FormRecord &formRecord, +const FormProviderData &formProviderData) +{ + APP_LOGI("%{public}s start", __func__); + + if (formRecord.versionUpgrade) { + formRecord.formProviderInfo.SetFormData(formProviderData); + } else { + nlohmann::json addJsonData = formProviderData.GetData(); + formRecord.formProviderInfo.MergeData(addJsonData); + } + + // formRecord init + formRecord.isInited = true; + formRecord.needRefresh = false; + FormDataMgr::GetInstance().SetFormCacheInited(formId, true); + + // update form for host clients + FormDataMgr::GetInstance().UpdateHostNeedRefresh(formId, true); + + bool screenOnFlag = PowerMgr::PowerMgrClient::GetInstance().IsScreenOn(); + if (screenOnFlag) { + if (FormDataMgr::GetInstance().UpdateHostForm(formId, formRecord)) { + FormDataMgr::GetInstance().SetVersionUpgrade(formId, false); + } + } + // check if cache data size is less than 1k or not + std::string jsonData = formRecord.formProviderInfo.GetFormDataString(); // get json data + APP_LOGD("%{public}s , jsonData is %{public}s.", __func__, jsonData.c_str()); + if (jsonData.size() <= Constants::MAX_FORM_DATA_SIZE) { + APP_LOGI("%{public}s, updateJsForm, data is less than 1k, cache data.", __func__); + FormCacheMgr::GetInstance().AddData(formId, jsonData); + } + + // the update form is successfully + return ERR_OK; +} +/** + * @brief Process js message event. + * @param formId Indicates the unique id of form. + * @param record Form record. + * @param want information passed to supplier. + * @return Returns true if execute success, false otherwise. + */ +int FormProviderMgr::MessageEvent(const int64_t formId, const FormRecord &record, const Want &want) +{ + APP_LOGI("%{public}s called, formId:%{public}lld.", __func__, formId); + + bool screenOnFlag = PowerMgr::PowerMgrClient::GetInstance().IsScreenOn(); + if (!screenOnFlag) { + APP_LOGW("%{public}s fail, screen off now", __func__); + return ERR_APPEXECFWK_FORM_COMMON_CODE; + } + + sptr formMsgEventConnection = new FormMsgEventConnection(formId, want); + Want connectWant; + connectWant.AddFlags(Want::FLAG_ABILITY_FORM_ENABLED); + connectWant.SetElementName(record.bundleName, record.abilityName); + + ErrCode errorCode = FormAmsHelper::GetInstance().ConnectServiceAbility(connectWant, formMsgEventConnection); + if (errorCode != ERR_OK) { + APP_LOGE("%{public}s, ConnectServiceAbility failed.", __func__); + return errorCode; + } + + return ERR_OK; +} + +/** + * @brief Increase the timer refresh count. + * + * @param formId The form id. + */ +void FormProviderMgr::IncreaseTimerRefreshCount(const int64_t formId) +{ + FormRecord record; + if (FormDataMgr::GetInstance().GetFormRecord(formId, record)) { + APP_LOGE("%{public}s failed, not exist such form:%{public}lld.", __func__, formId); + return; + } + + if (record.isCountTimerRefresh) { + FormDataMgr::GetInstance().SetCountTimerRefresh(formId, false); + FormTimerMgr::GetInstance().IncreaseRefreshCount(formId); + } +} +FormRecord FormProviderMgr::GetFormAbilityInfo(const FormRecord &record) const +{ + FormRecord newRecord; + newRecord.bundleName = record.bundleName; + newRecord.abilityName = record.abilityName; + + return newRecord; +} + +bool FormProviderMgr::IsFormCached(const FormRecord &record) +{ + if (record.versionUpgrade) { + return false; + } + return FormCacheMgr::GetInstance().IsExist(record.formId); +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/formmgr/src/form_refresh_connection.cpp b/services/formmgr/src/form_refresh_connection.cpp new file mode 100644 index 0000000000..e2dd344968 --- /dev/null +++ b/services/formmgr/src/form_refresh_connection.cpp @@ -0,0 +1,70 @@ + +/* + * Copyright (c) 2021 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 "appexecfwk_errors.h" +#include "app_log_wrapper.h" +#include "form_constants.h" +#include "form_refresh_connection.h" +#include "form_supply_callback.h" +#include "form_task_mgr.h" +#include "ipc_types.h" +#include "message_parcel.h" +#include "want.h" + +namespace OHOS { +namespace AppExecFwk { +FormRefreshConnection::FormRefreshConnection(const int64_t formId, const Want& want) + :formId_(formId), + want_(want) +{ +} +/** + * @brief OnAbilityConnectDone, AbilityMs notify caller ability the result of connect. + * + * @param element Service ability's ElementName. + * @param remoteObject The session proxy of service ability. + * @param resultCode ERR_OK on success, others on failure. + * @return none. + */ +void FormRefreshConnection::OnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) +{ + APP_LOGI("%{public}s called.", __func__); + + if (resultCode != ERR_OK) { + APP_LOGE("%{public}s, abilityName:%{public}s, formId:%{public}lld, resultCode:%{public}d", + __func__, element.GetAbilityName().c_str(), formId_, resultCode); + return; + } + FormSupplyCallback::GetInstance()->AddConnection(this); + + if (want_.HasParameter(Constants::PARAM_MESSAGE_KEY)) { + std::string message = want_.GetStringParam(Constants::PARAM_MESSAGE_KEY); + // FormTaskMgr::GetInstance()->FireFormEvent(formId, message, BuildDefaultWant(null, this), remoteObject); + } else if (want_.HasParameter(Constants::RECREATE_FORM_KEY)) { + Want cloneWant = Want(want_); + cloneWant.RemoveParam(Constants::RECREATE_FORM_KEY); + cloneWant.SetParam(Constants::ACQUIRE_TYPE, Constants::ACQUIRE_TYPE_RECREATE_FORM); + cloneWant.SetParam(Constants::FORM_CONNECT_ID, this->GetConnectId()); + FormTaskMgr::GetInstance().PostAcquireTask(formId_, cloneWant, remoteObject); + } else { + Want want; + want.SetParam(Constants::FORM_CONNECT_ID, this->GetConnectId()); + FormTaskMgr::GetInstance().PostRefreshTask(formId_, want, remoteObject); + } +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/formmgr/src/form_refresh_limiter.cpp b/services/formmgr/src/form_refresh_limiter.cpp new file mode 100644 index 0000000000..425b723e72 --- /dev/null +++ b/services/formmgr/src/form_refresh_limiter.cpp @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2021 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 "app_log_wrapper.h" +#include "form_constants.h" +#include "form_refresh_limiter.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @brief Add form limit info by formId. + * @param formId The id of the form. + * @return Returns true on success, false on failure. + */ +bool FormRefreshLimiter::AddItem(const int64_t formId) +{ + APP_LOGI("%{public}s start", __func__); + std::lock_guard lock(limiterMutex_); + auto info = limiterMap_.find(formId); + if (info == limiterMap_.end()) { + LimitInfo limitInfo; + std::pair::iterator, bool> retVal = + limiterMap_.emplace(formId, limitInfo); + APP_LOGI("%{public}s end", __func__); + return retVal.second; + } else { + APP_LOGI("%{public}s end, already exist", __func__); + return true; + } +} +/** + * @brief Delete form limit info by formId. + * @param formId The form id. + */ +void FormRefreshLimiter::DeleteItem(const int64_t formId) +{ + APP_LOGI("%{public}s start", __func__); + std::lock_guard lock(limiterMutex_); + auto info = limiterMap_.find(formId); + if (info != limiterMap_.end()) { + limiterMap_.erase(formId); + } + APP_LOGI("%{public}s end", __func__); +} +/** + * @brief Reset limit info. + */ +void FormRefreshLimiter::ResetLimit() +{ + APP_LOGI("%{public}s start", __func__); + std::lock_guard lock(limiterMutex_); + for (auto &infoPair : limiterMap_) { + infoPair.second.refreshCount = 0; + infoPair.second.isReported = false; + infoPair.second.remindFlag = false; + } + APP_LOGI("%{public}s end", __func__); +} +/** + * @brief Refresh enable or not. + * @param formId The form id. + * @return Returns ERR_OK on success, others on failure. + */ +bool FormRefreshLimiter::IsEnableRefresh(const int64_t formId) +{ + APP_LOGI("%{public}s start", __func__); + bool isEnable = false; + std::lock_guard lock(limiterMutex_); + auto info = limiterMap_.find(formId); + if (info != limiterMap_.end()) { + if (info->second.refreshCount < Constants::LIMIT_COUNT) { + isEnable = true; + } + + if (info->second.refreshCount == Constants::LIMIT_COUNT && !info->second.isReported) { + info->second.isReported = true; + APP_LOGI("report refresh to 50 count,formId:%{public}lld", formId); + } + } + APP_LOGI("%{public}s end", __func__); + return isEnable; +} +/** + * @brief Get refresh count. + * @param formId The form id. + * @return refresh count. + */ +int FormRefreshLimiter::GetRefreshCount(const int64_t formId) const +{ + APP_LOGI("%{public}s start", __func__); + // -1 means not added or already removed. + std::lock_guard lock(limiterMutex_); + auto info = limiterMap_.find(formId); + if (info != limiterMap_.end()) { + return info->second.refreshCount; + } + + APP_LOGI("%{public}s end", __func__); + return -1; +} +/** + * @brief Increase refresh count. + * @param formId The form id. + */ +void FormRefreshLimiter::Increase(const int64_t formId) +{ + APP_LOGI("%{public}s start", __func__); + std::lock_guard lock(limiterMutex_); + auto info = limiterMap_.find(formId); + if (info != limiterMap_.end()) { + info->second.refreshCount++; + APP_LOGI("increase,formId:%{public}lld, count:%{public}d", formId, info->second.refreshCount); + if (info->second.refreshCount == Constants::LIMIT_COUNT && !info->second.isReported) { + info->second.isReported = true; + APP_LOGI("report refresh to 50 count,formId:%{public}lld", formId); + } + } + APP_LOGI("%{public}s end", __func__); +} +/** + * @brief Mark remind flag. + * @param formId The form id. + */ +void FormRefreshLimiter::MarkRemind(const int64_t formId) +{ + APP_LOGI("%{public}s start", __func__); + std::lock_guard lock(limiterMutex_); + auto info = limiterMap_.find(formId); + if (info != limiterMap_.end()) { + if (info->second.refreshCount >= Constants::LIMIT_COUNT) { + info->second.remindFlag = true; + } + } + APP_LOGI("%{public}s end", __func__); +} +/** + * @brief Get remind list. + * @return remind list. + */ +std::vector FormRefreshLimiter::GetRemindList() const +{ + APP_LOGI("%{public}s start", __func__); + std::vector result; + std::lock_guard lock(limiterMutex_); + for (auto &infoPair : limiterMap_) { + if (infoPair.second.remindFlag) { + result.emplace_back(infoPair.first); + } + } + APP_LOGI("%{public}s end", __func__); + return result; +} +/** + * @brief Get remind list and reset limit. + * @return remind list. + */ +std::vector FormRefreshLimiter::GetRemindListAndResetLimit() +{ + APP_LOGI("%{public}s start", __func__); + std::vector result; + std::lock_guard lock(limiterMutex_); + for (auto &infoPair : limiterMap_) { + if (infoPair.second.remindFlag) { + result.emplace_back(infoPair.first); + } + + infoPair.second.refreshCount = 0; + infoPair.second.isReported = false; + infoPair.second.remindFlag = false; + } + APP_LOGI("%{public}s end", __func__); + return result; +} +/** + * @brief Get item count. + * @return Item count. + */ +int FormRefreshLimiter::GetItemCount() const +{ + return limiterMap_.size(); +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/formmgr/src/form_storage_mgr.cpp b/services/formmgr/src/form_storage_mgr.cpp new file mode 100644 index 0000000000..43f2b147c9 --- /dev/null +++ b/services/formmgr/src/form_storage_mgr.cpp @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2021 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 +#include +#include +#include +#include + +#include "app_log_wrapper.h" +#include "form_storage_mgr.h" +#include "string_ex.h" + +namespace OHOS { +namespace AppExecFwk { +namespace { +const char* FORM_DB_DATA_BASE_FILE_DIR = "/data/formmgr"; +const int32_t FORM_DB_DATA_BASE_FILE_PATH_LEN = 255; +} + +// bool FormStorageMgr::KeyToDeviceAndName(const std::string &key, std::string &deviceId, std::string &bundleName) const +// { +// bool ret = false; +// std::vector splitStrs; +// const std::string::size_type EXPECT_SPLIT_SIZE = 2; +// OHOS::SplitStr(key, Constants::FILE_UNDERLINE, splitStrs); +// // the expect split size should be 2. +// // key rule is _ +// if (splitStrs.size() == EXPECT_SPLIT_SIZE) { +// deviceId = splitStrs[0]; +// bundleName = splitStrs[1]; +// ret = true; +// } +// APP_LOGD("key = %{private}s, bundleName = %{public}s", key.c_str(), bundleName.c_str()); +// return ret; +// } + +// void FormStorageMgr::DeviceAndNameToKey( +// const std::string &deviceId, const std::string &bundleName, std::string &key) const +// { +// key.append(deviceId); +// key.append(Constants::FILE_UNDERLINE); +// key.append(bundleName); +// APP_LOGD("key = %{private}s, bundleName = %{public}s", key.c_str(), bundleName.c_str()); +// } + +// bool FormStorageMgr::bool LoadAllData(std::map> &infos) const +// { +// bool ret = false; +// APP_LOGI("load all installed bundle data to map"); + +// std::fstream i(Constants::BUNDLE_DATA_BASE_FILE); +// nlohmann::json jParse; +// if (!i.is_open()) { +// APP_LOGE("failed to open bundle database file"); +// // if file not exist, should create file here +// std::ofstream o(Constants::BUNDLE_DATA_BASE_FILE); +// o.close(); +// return false; +// } +// APP_LOGI("open bundle database file success"); +// i.seekg(0, std::ios::end); +// int len = static_cast(i.tellg()); +// if (len > 0) { +// i.seekg(0, std::ios::beg); +// i >> jParse; +// for (auto &app : jParse.items()) { +// std::map deviceMap; +// for (auto &device : app.value().items()) { +// InnerBundleInfo innerBundleInfo; +// ret = innerBundleInfo.FromJson(device.value()); +// deviceMap.emplace(device.key(), innerBundleInfo); +// } +// auto pair = infos.emplace(app.key(), deviceMap); +// ret = pair.second; +// } +// } +// i.close(); +// return ret; +// } + +/** + * @brief Load form data from fileNamePath to innerFormInfos. + * @param fileNamePath load file path. + * @param innerFormInfos Save form data. + * @return Returns true if the data is successfully loaded; returns false otherwise. + */ +static bool LoadFormDataFile(const char* fileNamePath, std::vector &innerFormInfos) +{ + bool ret = false; + std::ifstream i(fileNamePath); + if (!i.is_open()) { + APP_LOGE("%{public}s, failed to open file[%{public}s]", __func__, fileNamePath); + return false; + } + + nlohmann::json jParse; + i.seekg(0, std::ios::end); + int len = static_cast(i.tellg()); + if (len != 0) { + i.seekg(0, std::ios::beg); + i >> jParse; + for (auto &it : jParse.items()) { + InnerFormInfo innerFormInfo; + if (innerFormInfo.FromJson(it.value())) { + innerFormInfos.emplace_back(innerFormInfo); + } else { + APP_LOGE("%{public}s, failed to parse json, formId[%{public}s]", __func__, it.key().c_str()); + } + } + ret = true; + } else { + APP_LOGE("%{public}s, file[%{public}s] is empty", __func__, fileNamePath); + ret = false; + } + i.close(); + return ret; +} + +/** + * @brief Load all form data from DB to innerFormInfos. + * @param innerFormInfos Storage all form data. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormStorageMgr::LoadFormData(std::vector &innerFormInfos) const +{ + APP_LOGI("%{public}s called.", __func__); + DIR *dirptr = opendir(FORM_DB_DATA_BASE_FILE_DIR); + if (dirptr == NULL) { + APP_LOGE("%{public}s, opendir failed, should no formmgr dir", __func__); + return ERR_APPEXECFWK_FORM_JSON_NO_DIR; + } + + struct dirent *ptr; + while ((ptr = readdir(dirptr)) != NULL) { + APP_LOGI("%{public}s, readdir fileName[%{public}s]", __func__, ptr->d_name); + if ((strcmp(ptr->d_name, ".") == 0) || (strcmp(ptr->d_name, "..") == 0)) { + continue; + } + char fileNamePath[FORM_DB_DATA_BASE_FILE_PATH_LEN] = {0}; + sprintf(fileNamePath, "%s/%s", FORM_DB_DATA_BASE_FILE_DIR, ptr->d_name); + if (!LoadFormDataFile(fileNamePath, innerFormInfos)) { + APP_LOGE("%{public}s, LoadFormDataFile failed, file[%{public}s]", __func__, ptr->d_name); + } + } + APP_LOGI("%{public}s, readdir over", __func__); + closedir(dirptr); + return ERR_OK; +} + +/** + * @brief Get form data from DB to innerFormInfo with formId. + * @param innerFormInfo Storage form data. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormStorageMgr::GetStorageFormInfoById(const std::string &formId, InnerFormInfo &innerFormInfo) const +{ + ErrCode ret = ERR_OK; + APP_LOGD("%{public}s called, formId[%{public}s]", __func__, formId.c_str()); + char fileNamePath[FORM_DB_DATA_BASE_FILE_PATH_LEN] = {0}; + sprintf(fileNamePath, "%s/%s.json", FORM_DB_DATA_BASE_FILE_DIR, formId.c_str()); + std::ifstream i(fileNamePath); + nlohmann::json jParse; + if (!i.is_open()) { + APP_LOGE("%{public}s, open failed, should no this file[%{public}s.json]", __func__, formId.c_str()); + return ERR_APPEXECFWK_FORM_JSON_OPEN_FAIL; + } + APP_LOGD("%{public}s, open success file[%{public}s.json]", __func__, formId.c_str()); + i.seekg(0, std::ios::end); + int len = static_cast(i.tellg()); + if (len != 0) { + i.seekg(0, std::ios::beg); + i >> jParse; + auto it = jParse.find(formId); + if (it != jParse.end()) { + if (innerFormInfo.FromJson(it.value()) == false) { + APP_LOGE("%{public}s, fromJson parse failed formId[%{public}s]", __func__, it.key().c_str()); + ret = ERR_APPEXECFWK_FORM_JSON_PARSE_FAIL; + } else { + ret = ERR_OK; + } + } else { + APP_LOGE("%{public}s, not find formId[%{public}s]", __func__, formId.c_str()); + ret = ERR_APPEXECFWK_FORM_JSON_FIND_FAIL; + } + } else { + APP_LOGE("%{public}s, file is empty formId[%{public}s]", __func__, formId.c_str()); + ret = ERR_APPEXECFWK_FORM_JSON_FILE_EMPTY; + } + i.close(); + + return ret; +} + +/** + * @brief Save or update the form data in DB. + * @param innerFormInfo Indicates the InnerFormInfo object to be save. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormStorageMgr::SaveStorageFormInfo(const InnerFormInfo &innerFormInfo) const +{ + APP_LOGI("%{public}s called, formId[%{public}lld]", __func__, innerFormInfo.GetFormId()); + ErrCode ret = ERR_OK; + std::string formId = std::to_string(innerFormInfo.GetFormId()); + + DIR *dirptr = opendir(FORM_DB_DATA_BASE_FILE_DIR); + if (dirptr == NULL) { + APP_LOGW("%{public}s, failed to open dir", __func__); + if (-1 == mkdir(FORM_DB_DATA_BASE_FILE_DIR, S_IRWXU)) { + APP_LOGE("%{public}s, failed to create dir", __func__); + return ERR_APPEXECFWK_FORM_JSON_CREATE_DIR_FAIL; + } + } else { + closedir(dirptr); + } + char tmpFilePath[FORM_DB_DATA_BASE_FILE_PATH_LEN] = {0}; + sprintf(tmpFilePath, "%s/%s.json", FORM_DB_DATA_BASE_FILE_DIR, formId.c_str()); + + std::fstream f(tmpFilePath); + nlohmann::json jParse; + if (!f.is_open()) { + std::ofstream o(tmpFilePath); // if file not exist, should create file here + if (!o.is_open()) { + APP_LOGE("%{public}s, touch new file[%{public}s] failed", __func__, tmpFilePath); + return ERR_APPEXECFWK_FORM_JSON_NEW_FILE_FAIL; + } + o.close(); + APP_LOGI("%{public}s, touch new file[%{public}s.json]", __func__, formId.c_str()); + f.open(tmpFilePath); + } + bool isExist = f.good(); + if (isExist) { + nlohmann::json innerInfo; + innerFormInfo.ToJson(innerInfo); + f.seekg(0, std::ios::end); + int len = static_cast(f.tellg()); + if (len == 0) { + nlohmann::json formRoot; + formRoot[formId] = innerInfo; + f << formRoot << std::endl; + } else { + APP_LOGE("%{public}s, file[%{public}s.json] is not empty", __func__, formId.c_str()); + } + } else { + APP_LOGE("%{public}s, touch new file[%{public}s] failed", __func__, formId.c_str()); + ret = ERR_APPEXECFWK_FORM_JSON_OPEN_FAIL; + } + f.close(); + return ret; +} + +/** + * @brief Modify the form data in DB. + * @param innerFormInfo Indicates the InnerFormInfo object to be Modify. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormStorageMgr::ModifyStorageFormInfo(const InnerFormInfo &innerFormInfo) const +{ + APP_LOGI("%{public}s called, formId[%{public}lld]", __func__, innerFormInfo.GetFormId()); + char fileNamePath[FORM_DB_DATA_BASE_FILE_PATH_LEN] = {0}; + sprintf(fileNamePath, "%s/%lld.json", FORM_DB_DATA_BASE_FILE_DIR, innerFormInfo.GetFormId()); + + std::ofstream o(fileNamePath, std::ios_base::trunc | std::ios_base::out); + if (!o.is_open()) { + APP_LOGE("%{public}s, open failed file[%{public}s]", __func__, fileNamePath); + return ERR_APPEXECFWK_FORM_JSON_OPEN_FAIL; + } + + nlohmann::json innerInfo; + innerFormInfo.ToJson(innerInfo); + nlohmann::json formRoot; + std::string formId = std::to_string(innerFormInfo.GetFormId()); + + formRoot[formId] = innerInfo; + o << formRoot << std::endl; + + o.close(); + return ERR_OK; +} + +/** + * @brief Delete the form data in DB. + * @param formId The form data Id. + * @return Returns ERR_OK on success, others on failure. + */ +ErrCode FormStorageMgr::DeleteStorageFormInfo(const std::string &formId) const +{ + APP_LOGI("%{public}s called, formId[%{public}s]", __func__, formId.c_str()); + char fileNamePath[FORM_DB_DATA_BASE_FILE_PATH_LEN] = {0}; + sprintf(fileNamePath, "%s/%s.json", FORM_DB_DATA_BASE_FILE_DIR, formId.c_str()); + + if (std::remove(fileNamePath) != 0) { + APP_LOGE("%{public}s, delete failed file[%{public}s]", __func__, fileNamePath); + return ERR_APPEXECFWK_FORM_JSON_DELETE_FAIL; + } + + return ERR_OK; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/formmgr/src/form_supply_callback.cpp b/services/formmgr/src/form_supply_callback.cpp new file mode 100644 index 0000000000..690c4d5554 --- /dev/null +++ b/services/formmgr/src/form_supply_callback.cpp @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2021 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 "appexecfwk_errors.h" +#include "app_log_wrapper.h" +#include "form_ams_helper.h" +#include "form_constants.h" +#include "form_provider_mgr.h" +#include "form_supply_callback.h" +#include "form_util.h" +#include "string_ex.h" + +namespace OHOS { +namespace AppExecFwk { +sptr FormSupplyCallback::instance_ = nullptr; +std::mutex FormSupplyCallback::mutex_; + +sptr FormSupplyCallback::GetInstance() +{ + if (instance_ == nullptr) { + std::lock_guard lock_l(mutex_); + if (instance_ == nullptr) { + instance_ = new FormSupplyCallback(); + } + } + return instance_; +} + +/** + * @brief Accept form binding data from form provider. + * @param providerFormInfo Form binding data. + * @param want input data. + * @return Returns ERR_OK on success, others on failure. + */ +int FormSupplyCallback::OnAcquire(const FormProviderInfo &formProviderInfo, const Want &want) +{ + long connectId = want.GetLongParam(Constants::FORM_CONNECT_ID, 0); + int errCode = want.GetIntParam(Constants::PROVIDER_FLAG, ERR_OK); + if (errCode != ERR_OK) { + RemoveConnection(connectId); + return errCode; + } + + int64_t formId = formProviderInfo.GetFormId(); + int type = want.GetIntParam(Constants::ACQUIRE_TYPE, 0); + APP_LOGD("%{public}s come: %{public}lld, %{public}ld, %{public}d", __func__, + formId, connectId, type); + RemoveConnection(connectId); + + switch (type) { + case Constants::ACQUIRE_TYPE_CREATE_FORM: + return FormProviderMgr::GetInstance().AcquireForm(formId, formProviderInfo); + case Constants::ACQUIRE_TYPE_RECREATE_FORM: + return FormProviderMgr::GetInstance().UpdateForm(formId, formProviderInfo); + default: + APP_LOGW("%{public}s warning, onAcquired type: %{public}d", __func__, type); + } + return ERR_APPEXECFWK_FORM_INVALID_PARAM; +} + +/** + * @brief Accept other event. + * @param want input data. + * @return Returns ERR_OK on success, others on failure. + */ +int FormSupplyCallback::OnEventHandle(const Want &want) +{ + long connectId = want.GetLongParam(Constants::FORM_CONNECT_ID, 0); + std::string supplyInfo = want.GetStringParam(Constants::FORM_SUPPLY_INFO); + APP_LOGD("%{public}s come: %{public}ld, %{public}s", __func__, connectId, supplyInfo.c_str()); + RemoveConnection(connectId); + return ERR_OK; +} +/** + * @brief Save ability Connection for the callback. + * @param connection ability connection. + */ +void FormSupplyCallback::AddConnection(sptr connection) +{ + std::lock_guard lock_l(conMutex_); + long connectKey = FormUtil::GetCurrentMillisecond(); + while (connections_.find(connectKey) != connections_.end()) { + connectKey++; + } + connection->SetConnectId(connectKey); + connections_.emplace(connectKey, connection); +} + +/** + * @brief Delete ability connection after the callback come. + * @param connectId The ability connection id generated when save. + */ +void FormSupplyCallback::RemoveConnection(long connectId) +{ + std::lock_guard lock_l(conMutex_); + auto conIterator = connections_.find(connectId); + if (conIterator != connections_.end()) { + sptr connection = conIterator->second; + if (connection != nullptr) { + FormAmsHelper::GetInstance().DisConnectServiceAbility(connection); + } + connections_.erase(connectId); + } +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/formmgr/src/form_sys_event_receiver.cpp b/services/formmgr/src/form_sys_event_receiver.cpp new file mode 100644 index 0000000000..a1181cb65a --- /dev/null +++ b/services/formmgr/src/form_sys_event_receiver.cpp @@ -0,0 +1,490 @@ +/* + * Copyright (c) 2021 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 "appexecfwk_errors.h" +#include "app_log_wrapper.h" +#include "bundle_info.h" +#include "common_event_manager.h" +#include "common_event_support.h" +#include "form_bms_helper.h" +#include "form_cache_mgr.h" +#include "form_constants.h" +#include "form_data_mgr.h" +#include "form_db_cache.h" +#include "form_db_info.h" +#include "form_provider_mgr.h" +#include "form_timer_mgr.h" +#include "form_util.h" +#include "form_sys_event_receiver.h" +#include "want.h" + +namespace OHOS { +namespace AppExecFwk { +const std::string KEY_UID = "uid"; +const std::string KEY_BUNDLE_NAME = "bundleName"; +/** + * @brief Receiver Constructor. + * @param subscriberInfo Subscriber info. + */ +FormSysEventReceiver::FormSysEventReceiver(const EventFwk::CommonEventSubscribeInfo &subscriberInfo) + : EventFwk::CommonEventSubscriber(subscriberInfo) +{} +/** + * @brief Receive common event. + * @param eventData Common event data. + */ +void FormSysEventReceiver::OnReceiveEvent(const EventFwk::CommonEventData &eventData) +{ + AAFwk::Want want = eventData.GetWant(); + std::string action = want.GetAction(); + std::string bundleName = want.GetStringParam(KEY_BUNDLE_NAME); + + if (action.empty() || bundleName.empty()) { + APP_LOGE("%{public}s failed, invalid param, action: %{public}s, bundleName: %{public}s", __func__, + action.c_str(), bundleName.c_str()); + return; + } + APP_LOGI("%{public}s, action:%{public}s.", __func__, action.c_str()); + if (action == EventFwk::CommonEventSupport::COMMON_EVENT_ABILITY_REMOVED) { + APP_LOGI("%{public}s, bundle removed, bundleName: %{public}s", __func__, bundleName.c_str()); + HandleProviderRemoved(bundleName); + } else if (action == EventFwk::CommonEventSupport::COMMON_EVENT_ABILITY_UPDATED) { + APP_LOGI("%{public}s, bundle updated, bundleName: %{public}s", __func__, bundleName.c_str()); + HandleProviderUpdated(bundleName); + } else if (action == EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_DATA_CLEARED) { + int uid = want.GetIntParam(KEY_UID, 0); + HandleBundleDataCleared(bundleName, uid); + } else { + APP_LOGW("%{public}s warnning, invalid action.", __func__); + } +} +/** + * @brief Handle provider updated event. + * @param bundleName bundle name. + * @param uid uid. + */ +void FormSysEventReceiver::HandleProviderUpdated(const std::string &bundleName) +{ + std::vector formInfos; + bool bResult = FormDataMgr::GetInstance().GetFormRecord(bundleName, formInfos); + if (!bResult) { + APP_LOGI("%{public}s, no form info.", __func__); + return; + } + + sptr iBundleMgr = FormBmsHelper::GetInstance().GetBundleMgr(); + if (iBundleMgr == nullptr) { + // GetBundleMgr() has error log + return; + } + + std::vector targetForms; + if (!iBundleMgr->GetFormsInfoByApp(bundleName, targetForms)) { + APP_LOGE("%{public}s error, failed to get forms info.", __func__); + return; + } + + if (targetForms.empty()) { + APP_LOGE("%{public}s error, targetForms is empty.", __func__); + return; + } + + std::vector removedForms; + std::vector updatedForms; + + for (FormRecord& formRecord : formInfos) { + APP_LOGI("%{public}s, provider update, formName:%{public}s", __func__, formRecord.formName.c_str()); + int64_t formId = formRecord.formId; + if (ProviderFormUpdated(formId, formRecord, targetForms)) { + updatedForms.emplace_back(formId); + continue; + } + + APP_LOGI("%{public}s, no such form anymore, delete it:%{public}s", __func__, formRecord.formName.c_str()); + if (!formRecord.formTempFlg) { + FormDbCache::GetInstance().DeleteFormInfo(formId); + } else { + FormDataMgr::GetInstance().DeleteTempForm(formId); + } + removedForms.emplace_back(formId); + FormDataMgr::GetInstance().DeleteFormRecord(formId); + } + + if (!removedForms.empty()) { + APP_LOGI("%{public}s, clean removed forms", __func__); + FormDataMgr::GetInstance().CleanHostRemovedForms(removedForms); + } + + APP_LOGI("%{public}s, remove form timer", __func__); + for (const int64_t id : removedForms) { + FormTimerMgr::GetInstance().RemoveFormTimer(id); + } + + APP_LOGI("%{public}s, refresh form", __func__); + Want want; + for (const int64_t id : updatedForms) { + FormProviderMgr::GetInstance().RefreshForm(id, want); + } +} + +void FormSysEventReceiver::HandleProviderRemoved(const std::string &bundleName) +{ + APP_LOGI("GET into HandleProviderRemoved with bundleName : %{public}s", bundleName.c_str()); + // clean removed form in DB + std::set removedForms; + { + std::vector removedDBForm; + FormDbCache::GetInstance().DeleteFormInfoByBundleName(bundleName, removedDBForm); + for (const auto &dbForm : removedDBForm) { + removedForms.emplace(dbForm.formId); + int32_t matchCount = FormDbCache::GetInstance().GetMatchCount(dbForm.bundleName, dbForm.moduleName); + if (matchCount == 0) { + FormBmsHelper::GetInstance().NotifyModuleRemovable(dbForm.bundleName, dbForm.moduleName); + } + } + } + // clean removed form in FormRecords + FormDataMgr::GetInstance().CleanRemovedFormRecords(bundleName, removedForms); + // clean removed temp form in FormRecords + FormDataMgr::GetInstance().CleanRemovedTempFormRecords(bundleName, removedForms); + // clean removed forms in FormHostRecords + std::vector vRemovedForms; + vRemovedForms.assign(removedForms.begin(), removedForms.end()); + FormDataMgr::GetInstance().CleanHostRemovedForms(vRemovedForms); + + // clean removed form timers + for (auto &formId : removedForms) { + FormTimerMgr::GetInstance().RemoveFormTimer(formId); + } +} + +bool FormSysEventReceiver::ProviderFormUpdated(const int64_t formId, const FormRecord &formRecord, +const std::vector &targetForms) +{ + APP_LOGI("%{public}s start", __func__); + if (targetForms.empty()) { + APP_LOGE("%{public}s error, targetForms is empty", __func__); + return false; + } + + FormInfo updatedForm; + bool bGetForm = FormDataMgr::GetInstance().GetUpdatedForm(formRecord, targetForms, updatedForm); + if (bGetForm) { + APP_LOGI("%{public}s, form is still exist,form:%{public}s", __func__, formRecord.formName.c_str()); + // update resource + FormDataMgr::GetInstance().SetNeedRefresh(formId, true); + FormCacheMgr::GetInstance().DeleteData(formId); + + FormBmsHelper::GetInstance().NotifyModuleNotRemovable(formRecord.bundleName, formRecord.moduleName); + FormTimerCfg timerCfg; + GetTimerCfg(updatedForm.updateEnabled, updatedForm.updateDuration, + updatedForm.scheduledUpateTime, timerCfg); + HandleTimerUpdate(formId, formRecord, timerCfg); + FormDataMgr::GetInstance().SetVersionUpgrade(formId, true); + return true; + } + APP_LOGI("%{public}s, no updated form.", __func__); + return false; +} +void FormSysEventReceiver::HandleBundleDataCleared(const std::string &bundleName, const int uid) +{ + APP_LOGD("%{public}s, bundleName:%{public}s, uid:%{public}d", __func__, bundleName.c_str(), uid); + // as provider data is cleared + std::set reCreateForms; + FormDataMgr::GetInstance().GetReCreateFormRecordsByBundleName(bundleName, reCreateForms); + if (reCreateForms.empty()) { + return; + } + for (int64_t formId : reCreateForms) { + ReCreateForm(formId); + } + + // as form host data is cleared + HandleFormHostDataCleared(uid); +} +void FormSysEventReceiver::HandleFormHostDataCleared(const int uid) +{ + APP_LOGD("%{public}s, uid:%{public}d", __func__, uid); + std::map removedFormsMap; + // clear formDBRecord + ClearFormDBRecordData(uid, removedFormsMap); + + // clear temp form + ClearTempFormRecordData(uid, removedFormsMap); + + // clear host data + FormDataMgr::GetInstance().ClearHostDataByUId(uid); + + // delete forms timer + for (const auto &removedForm : removedFormsMap) { + if (removedForm.second) { + FormTimerMgr::GetInstance().RemoveFormTimer(removedForm.first); + } + } +} +void FormSysEventReceiver::ClearFormDBRecordData(const int uid, std::map &removedFormsMap) +{ + std::map foundFormsMap; + std::map> noHostFormDbMap; + FormDbCache::GetInstance().GetNoHostDBForms(uid, noHostFormDbMap, foundFormsMap); + if (foundFormsMap.size() > 0) { + for (const auto &element : foundFormsMap) { + FormDataMgr::GetInstance().DeleteFormUserUid(element.first, uid); + } + } + + APP_LOGD("%{public}s, noHostFormDbMap size:%{public}d", __func__, noHostFormDbMap.size()); + if (noHostFormDbMap.size() > 0) { + BatchDeleteNoHostDBForms(uid, noHostFormDbMap, foundFormsMap); + } + + if (!foundFormsMap.empty()) { + removedFormsMap.insert(foundFormsMap.begin(), foundFormsMap.end()); + } +} +void FormSysEventReceiver::ClearTempFormRecordData(const int uid, std::map &removedFormsMap) +{ + std::map foundFormsMap; + std::map> noHostTempFormsMap; + FormDataMgr::GetInstance().GetNoHostTempForms(uid, noHostTempFormsMap, foundFormsMap); + APP_LOGD("%{public}s, noHostTempFormsMap size:%{public}d", __func__, noHostTempFormsMap.size()); + if (noHostTempFormsMap.size() > 0) { + BatchDeleteNoHostTempForms(uid, noHostTempFormsMap, foundFormsMap); + } + if (!foundFormsMap.empty()) { + removedFormsMap.insert(foundFormsMap.begin(), foundFormsMap.end()); + } +} +void FormSysEventReceiver::BatchDeleteNoHostDBForms(const int uid, std::map> &noHostFormDbMap, std::map &removedFormsMap) +{ + std::set removableModuleSet; + for (const auto &element: noHostFormDbMap) { + std::set formIds = element.second; + FormIdKey formIdKey = element.first; + std::string bundleName = formIdKey.bundleName; + std::string abilityName = formIdKey.abilityName; + int result = FormProviderMgr::GetInstance().NotifyProviderFormsBatchDelete(bundleName, abilityName, formIds); + if (result != ERR_OK) { + APP_LOGE("%{public}s error, NotifyProviderFormsBatchDelete failed! bundleName:%{public}s, abilityName:%{public}s", + __func__, bundleName.c_str(), abilityName.c_str()); + for (int64_t formId : formIds) { + FormDBInfo dbInfo; + int errCode = FormDbCache::GetInstance().GetDBRecord(formId, dbInfo); + if (errCode == ERR_OK) { + dbInfo.formUserUids.emplace_back(uid); + FormDbCache::GetInstance().SaveFormInfo(dbInfo); + } + } + } else { + for (const int64_t formId : formIds) { + removedFormsMap.emplace(formId, true); + FormDBInfo dbInfo; + int errCode = FormDbCache::GetInstance().GetDBRecord(formId, dbInfo); + if (errCode == ERR_OK) { + FormIdKey removableModuleFormIdKey; + removableModuleFormIdKey.bundleName = dbInfo.bundleName; + removableModuleFormIdKey.moduleName = dbInfo.moduleName; + removableModuleSet.emplace(removableModuleFormIdKey); + FormDbCache::GetInstance().DeleteFormInfo(formId); + } + FormDataMgr::GetInstance().DeleteFormRecord(formId); + } + } + } + + for (const FormIdKey &item : removableModuleSet) { + int32_t matchCount = FormDbCache::GetInstance().GetMatchCount(item.bundleName, item.moduleName); + if (matchCount == 0) { + FormBmsHelper::GetInstance().NotifyModuleRemovable(item.bundleName, item.moduleName); + } + } +} +/** + * @brief Delete no host temp forms. + * @param uid The caller uid. + * @param noHostTempFormsMap no host temp forms. + * @param foundFormsMap Form Id list. + */ +void FormSysEventReceiver::BatchDeleteNoHostTempForms(const int uid, std::map> &noHostTempFormsMap, std::map &foundFormsMap) +{ + for (const auto &element : noHostTempFormsMap) { + std::set formIds = element.second; + FormIdKey formIdKey = element.first; + std::string bundleName = formIdKey.bundleName; + std::string abilityName = formIdKey.abilityName; + int result = FormProviderMgr::GetInstance().NotifyProviderFormsBatchDelete(bundleName, abilityName, formIds); + if (result != ERR_OK) { + APP_LOGE("%{public}s error, NotifyProviderFormsBatchDelete failed! bundleName:%{public}s, abilityName:%{public}s", + __func__, bundleName.c_str(), abilityName.c_str()); + for (int64_t formId : formIds) { + FormDataMgr::GetInstance().AddFormUserUid(formId, uid); + } + } else { + for (int64_t formId : formIds) { + foundFormsMap.emplace(formId, true); + FormDataMgr::GetInstance().DeleteFormRecord(formId); + FormDataMgr::GetInstance().DeleteTempForm(formId); + } + } + } +} +void FormSysEventReceiver::ReCreateForm(const int64_t formId) +{ + APP_LOGI("%{public}s start, formId:%{public}lld", __func__, formId); + FormRecord reCreateRecord; + FormRecord record; + bool isGetForm = FormDataMgr::GetInstance().GetFormRecord(formId, record); + if (!isGetForm) { + APP_LOGE("%{public}s error, not exist such form:%{public}lld", __func__, formId); + return; + } + FormCacheMgr::GetInstance().DeleteData(formId); + + reCreateRecord.bundleName = record.bundleName; + reCreateRecord.abilityName = record.abilityName; + reCreateRecord.formName = record.formName; + reCreateRecord.specification = record.specification; + reCreateRecord.formTempFlg = record.formTempFlg; + reCreateRecord.isInited = record.isInited; + reCreateRecord.versionUpgrade = record.versionUpgrade; + + Want want; + FormUtil::CreateFormWant(reCreateRecord.formName, reCreateRecord.specification, reCreateRecord.formTempFlg, want); + want.SetParam(Constants::RECREATE_FORM_KEY, true); + FormProviderMgr::GetInstance().ConnectAmsForRefresh(formId, reCreateRecord, want, false); +} +void FormSysEventReceiver::GetTimerCfg(const bool updateEnabled, const int updateDuration, +const std::string &configUpdateAt, FormTimerCfg& cfg) +{ + APP_LOGI("%{public}s start", __func__); + if (!updateEnabled) { + APP_LOGI("%{public}s, update disable", __func__); + return; + } + + if (updateDuration > 0) { + // interval timer + APP_LOGI("%{public}s,interval timer updateDuration:%{public}d", __func__, updateDuration); + if (updateDuration <= Constants::MIN_CONFIG_DURATION) { + cfg.updateDuration = Constants::MIN_PERIOD; + } else if (updateDuration >= Constants::MAX_CONFIG_DURATION) { + cfg.updateDuration = Constants::MAX_PERIOD; + } else { + cfg.updateDuration = updateDuration * Constants::TIME_CONVERSION; + } + cfg.enableUpdate = true; + return; + } else { + // updateAtTimer + if (configUpdateAt.empty()) { + APP_LOGI("%{public}s, configUpdateAt is empty", __func__); + return; + } + APP_LOGI("%{public}s,update at timer updateAt:%{public}s", __func__, configUpdateAt.c_str()); + + std::vector temp = FormUtil::StringSplit(configUpdateAt, Constants::TIME_DELIMETER); + if (temp.size() != Constants::UPDATE_AT_CONFIG_COUNT) { + APP_LOGE("%{public}s, invalid config", __func__); + return; + } + int hour = -1; + int min = -1; + try { + hour = std::stoi(temp[0]); + min = std::stoi(temp[1]); + } catch (const std::exception& e) { + APP_LOGE("%{public}s, failed to stoi.", __func__); + return; + } + + if (hour < Constants::MIN_TIME || hour > Constants::MAX_HOUR || min < Constants::MIN_TIME || min > + Constants::MAX_MININUTE) { + APP_LOGE("%{public}s, time is invalid", __func__); + return; + } + + cfg.updateAtHour = hour; + cfg.updateAtMin = min; + cfg.enableUpdate = true; + return; + } +} + +void FormSysEventReceiver::HandleTimerUpdate(const int64_t formId, const FormRecord &record, +const FormTimerCfg &timerCfg) +{ + // both disable + if (!record.isEnableUpdate && !timerCfg.enableUpdate) { + return; + } + + // enable to disable + if (record.isEnableUpdate && !timerCfg.enableUpdate) { + FormDataMgr::GetInstance().SetEnableUpdate(formId, false); + FormTimerMgr::GetInstance().RemoveFormTimer(formId); + return; + } + + // disable to enable + if (!record.isEnableUpdate && timerCfg.enableUpdate) { + FormDataMgr::GetInstance().SetUpdateInfo(formId, true, timerCfg.updateDuration, timerCfg.updateAtHour, + timerCfg.updateAtMin); + if (timerCfg.updateDuration > 0) { + APP_LOGI("%{public}s, add interval timer:%{public}lld", __func__, timerCfg.updateDuration); + FormTimerMgr::GetInstance().AddFormTimer(formId, timerCfg.updateDuration); + } else { + APP_LOGI("%{public}s, add at timer:%{public}d, %{public}d", __func__, timerCfg.updateAtHour, + timerCfg.updateAtMin); + FormTimerMgr::GetInstance().AddFormTimer(formId, timerCfg.updateAtHour, timerCfg.updateAtMin); + } + + return; + } + + // both enable + UpdateType type; + if (record.updateDuration > 0) { + if (timerCfg.updateDuration > 0) { + // no change + if (record.updateDuration == timerCfg.updateDuration) { + return; + } + // interval change + type = TYPE_INTERVAL_CHANGE; + } else { + // interval to updateat + type = TYPE_INTERVAL_TO_ATTIME; + } + } else { + if (timerCfg.updateDuration > 0) { + // updateat to interval + type = TYPE_ATTIME_TO_INTERVAL; + } else { + // no change; + if (record.updateAtHour == timerCfg.updateAtHour && record.updateAtMin == timerCfg.updateAtMin) { + return; + } + // updateat change + type = TYPE_ATTIME_CHANGE; + } + } + + FormDataMgr::GetInstance().SetUpdateInfo(formId, true, timerCfg.updateDuration, timerCfg.updateAtHour, + timerCfg.updateAtMin); + FormTimerMgr::GetInstance().UpdateFormTimer(formId, type, timerCfg); +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/formmgr/src/form_task_mgr.cpp b/services/formmgr/src/form_task_mgr.cpp new file mode 100644 index 0000000000..83fe1cd8ba --- /dev/null +++ b/services/formmgr/src/form_task_mgr.cpp @@ -0,0 +1,566 @@ +/* + * Copyright (c) 2021 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 "app_log_wrapper.h" +#include "form_constants.h" +#include "form_data_mgr.h" +#include "form_host_interface.h" +#include "form_item_info.h" +#include "form_provider_interface.h" +#include "form_supply_callback.h" +#include "form_task_mgr.h" +#include "form_util.h" + +namespace OHOS { +namespace AppExecFwk { +FormTaskMgr::FormTaskMgr() {} +FormTaskMgr::~FormTaskMgr() {} +/** + * @brief Acquire form data from form provider(task). + * @param formId The Id of the form. + * @param want The want of the request. + * @param remoteObject Form provider proxy object. + */ +void FormTaskMgr::PostAcquireTask(const int64_t formId, const Want &want, const sptr &remoteObject) +{ + if (eventHandler_ == nullptr) { + APP_LOGE("%{public}s fail, eventhandler invalidate", __func__); + return; + } + std::function acquireProviderFormInfoFunc = std::bind( + &FormTaskMgr::AcquireProviderFormInfo, + this, + formId, + want, + remoteObject); + eventHandler_->PostTask(acquireProviderFormInfoFunc); +} +/** + * @brief Delete form data from form provider(task). + * @param formId The Id of the form. + * @param want The want of the request. + * @param remoteObject Form provider proxy object. + */ +void FormTaskMgr::PostDeleteTask(const int64_t formId, const Want &want, const sptr &remoteObject) +{ + if (eventHandler_ == nullptr) { + APP_LOGE("%{public}s fail, eventhandler invalidate", __func__); + return; + } + std::function notifyFormDeleteFunc = std::bind ( + &FormTaskMgr::NotifyFormDelete, + this, + formId, + want, + remoteObject); + eventHandler_->PostTask(notifyFormDeleteFunc); +} + +/** + * @brief Refresh form data from form provider(task). + * + * @param formId The Id of the form. + * @param want The want of the form. + * @param remoteObject Form provider proxy object. + * @return none. + */ +void FormTaskMgr::PostRefreshTask(const int64_t formId, const Want &want, const sptr &remoteObject) +{ + if (eventHandler_ == nullptr) { + APP_LOGE("%{public}s fail, eventhandler invalidate.", __func__); + return; + } + std::function notifyFormUpdateFunc = std::bind ( + &FormTaskMgr::NotifyFormUpdate, + this, + formId, + want, + remoteObject); + eventHandler_->PostTask(notifyFormUpdateFunc); +} + +/** + * @brief Cast temp form data from form provider(task). + * + * @param formId The Id of the form. + * @param want The want of the form. + * @param remoteObject Form provider proxy object. + * @return none. + */ +void FormTaskMgr::PostCastTempTask(const int64_t formId, const Want &want, const sptr &remoteObject) +{ + if (eventHandler_ == nullptr) { + APP_LOGE("%{public}s fail, eventhandler invalidate", __func__); + return; + } + std::function notifyCastTempFunc = std::bind ( + &FormTaskMgr::NotifyCastTemp, + this, + formId, + want, + remoteObject); + eventHandler_->PostTask(notifyCastTempFunc); +} + +/** + * @brief Post form data to form host(task) when acquire form. + * @param formId The Id of the form. + * @param callingUid Calling uid. + * @param info Form configure info. + * @param wantParams WantParams of the request. + * @param remoteObject Form provider proxx object. + */ +void FormTaskMgr::PostAcquireTaskToHost(const int64_t formId, const FormRecord &record, +const sptr &remoteObject) +{ + if (eventHandler_ == nullptr) { + APP_LOGE("%{public}s fail, eventhandler invalidate", __func__); + return; + } + std::function acquireTaskToHostFunc = std::bind ( + &FormTaskMgr::AcquireTaskToHost, + this, + formId, + record, + remoteObject); + eventHandler_->PostTask(acquireTaskToHostFunc); +} + +/** + * @brief Post form data to form host(task) when update form. + * @param formId The Id of the form. + * @param callingUid Calling uid. + * @param info Form configure info. + * @param wantParams WantParams of the request. + * @param remoteObject Form provider proxx object. + */ +void FormTaskMgr::PostUpdateTaskToHost(const int64_t formId, const FormRecord &record, +const sptr &remoteObject) +{ + APP_LOGI("%{public}s called.", __func__); + + if (eventHandler_ == nullptr) { + APP_LOGE("%{public}s fail, eventhandler invalidate.", __func__); + return; + } + + APP_LOGD("%{public}s, post the task of updateTaskToHostFunc.", __func__); + std::function updateTaskToHostFunc = std::bind ( + &FormTaskMgr::UpdateTaskToHost, + this, + formId, + record, + remoteObject); + eventHandler_->PostTask(updateTaskToHostFunc); +} + +/** + * @brief Acquire form data from form provider. + * @param formId The Id of the form. + * @param info Form configure info. + * @param wantParams WantParams of the request. + * @param remoteObject Form provider proxx object. + */ +/** + * @brief Handel form host died(task). + * @param remoteHost Form host proxy object. + */ +void FormTaskMgr::PostHostDiedTask(const sptr &remoteHost) +{ + if (eventHandler_ == nullptr) { + APP_LOGE("%{public}s fail, eventhandler invalidate", __func__); + return; + } + std::function postTaskFunc = std::bind ( + &FormTaskMgr::HostDied, + this, + remoteHost); + eventHandler_->PostTask(postTaskFunc); +} + +/** + * @brief Post event notify to form provider. + * + * @param formEvent The vector of form ids. + * @param formVisibleType The form visible type, including FORM_VISIBLE and FORM_INVISIBLE. + * @param want The want of the form. + * @param remoteObject The form provider proxy object. + * @return none. + */ +void FormTaskMgr::PostEventNotifyTask(const std::vector &formEvent, const int32_t formVisibleType, +const Want &want, const sptr &remoteObject) +{ + if (eventHandler_ == nullptr) { + APP_LOGE("%{public}s fail, eventhandler invalidate.", __func__); + return; + } + std::function eventNotifyFunc = std::bind ( + &FormTaskMgr::EventNotify, + this, + formEvent, + formVisibleType, + want, + remoteObject); + eventHandler_->PostTask(eventNotifyFunc); +} +/** + * @brief Post provider batch delete. + * @param formIds The Id list. + * @param want The want of the request. + * @param remoteObject Form provider proxy object. + */ +void FormTaskMgr::PostProviderBatchDeleteTask(std::set &formIds, const Want &want, +const sptr &remoteObject) +{ + if (eventHandler_ == nullptr) { + APP_LOGE("%{public}s fail, eventhandler invalidate.", __func__); + return; + } + std::function batchDeleteFunc = std::bind ( + &FormTaskMgr::ProviderBatchDelete, + this, + formIds, + want, + remoteObject); + eventHandler_->PostTask(batchDeleteFunc); +} +/** + * @brief Post message event to form provider. + * @param formId The Id of the from. + * @param message Event message. + * @param want The want of the request. + * @param remoteObject Form provider proxy object. + */ +void FormTaskMgr::PostFormEventTask(const int64_t formId, const std::string &message, const Want &want, +const sptr &remoteObject) +{ + if (eventHandler_ == nullptr) { + APP_LOGE("%{public}s fail, eventhandler invalidate.", __func__); + return; + } + std::function formEventFunc = std::bind ( + &FormTaskMgr::FireFormEvent, + this, + formId, + message, + want, + remoteObject); + eventHandler_->PostTask(formEventFunc); +} + +/** + * @brief Post uninstall message to form host(task). + * @param formIds The Id list of the forms. + * @param remoteObject Form provider proxy object. + */ +void FormTaskMgr::PostUninstallTaskToHost(const std::vector &formIds, const sptr &remoteObject) +{ + APP_LOGI("%{public}s start", __func__); + if (eventHandler_ == nullptr) { + APP_LOGE("%{public}s fail, eventhandler invalidate.", __func__); + return; + } + std::function uninstallFunc = std::bind ( + &FormTaskMgr::FormUninstall, + this, + formIds, + remoteObject); + eventHandler_->PostTask(uninstallFunc); + APP_LOGI("%{public}s end", __func__); +} + +/** + * @brief Acquire form data from form provider. + * @param formId The Id of the from. + * @param want The want of the request. + * @param remoteObject Form provider proxy object. + */ +void FormTaskMgr::AcquireProviderFormInfo(const int64_t formId, const Want &want, +const sptr &remoteObject) +{ + long connectId = want.GetLongParam(Constants::FORM_CONNECT_ID, 0); + sptr formProviderProxy = iface_cast(remoteObject); + if (formProviderProxy == nullptr) { + FormSupplyCallback::GetInstance()->RemoveConnection(connectId); + APP_LOGE("%{public}s fail, Failed to get formProviderProxy", __func__); + return; + } + int error = formProviderProxy->AcquireProviderFormInfo(formId, want, FormSupplyCallback::GetInstance()); + if (error != ERR_OK) { + FormSupplyCallback::GetInstance()->RemoveConnection(connectId); + APP_LOGE("%{public}s fail, Failed to get acquire provider form info", __func__); + } +} + +/** + * @brief Notify form provider for delete form. + * + * @param formId The Id of the from. + * @param want The want of the form. + * @param remoteObject Form provider proxy object. + * @return none. + */ +void FormTaskMgr::NotifyFormDelete(const int64_t formId, const Want &want, const sptr &remoteObject) +{ + long connectId = want.GetLongParam(Constants::FORM_CONNECT_ID, 0); + sptr formProviderProxy = iface_cast(remoteObject); + if (formProviderProxy == nullptr) { + FormSupplyCallback::GetInstance()->RemoveConnection(connectId); + APP_LOGE("%{public}s fail, Failed to get formProviderProxy", __func__); + return; + } + int error = formProviderProxy->NotifyFormDelete(formId, want, FormSupplyCallback::GetInstance()); + if (error != ERR_OK) { + FormSupplyCallback::GetInstance()->RemoveConnection(connectId); + APP_LOGE("%{public}s fail, Failed to get acquire provider form info", __func__); + } +} + +/** + * @brief Notify form provider for updating form. + * + * @param formId The Id of the from. + * @param want The want of the form. + * @param remoteObject Form provider proxy object. + * @return none. + */ +void FormTaskMgr::NotifyFormUpdate(const int64_t formId, const Want &want, const sptr &remoteObject) +{ + APP_LOGI("%{public}s called.", __func__); + + long connectId = want.GetLongParam(Constants::FORM_CONNECT_ID, 0); + sptr formProviderProxy = iface_cast(remoteObject); + if (formProviderProxy == nullptr) { + FormSupplyCallback::GetInstance()->RemoveConnection(connectId); + APP_LOGE("%{public}s fail, failed to get formProviderProxy", __func__); + return; + } + + int error = formProviderProxy->NotifyFormUpdate(formId, want, FormSupplyCallback::GetInstance()); + if (error != ERR_OK) { + FormSupplyCallback::GetInstance()->RemoveConnection(connectId); + APP_LOGE("%{public}s fail, Failed to notify form update.", __func__); + } +} + +/** + * @brief Event notify to form provider. + * + * @param formEvents The vector of form ids. + * @param formVisibleType The form visible type, including FORM_VISIBLE and FORM_INVISIBLE. + * @param want The want of the form. + * @param remoteObject The form provider proxy object. + * @return none. + */ +void FormTaskMgr::EventNotify(const std::vector &formEvents, const int32_t formVisibleType, const Want &want, +const sptr &remoteObject) +{ + APP_LOGI("%{public}s called.", __func__); + + long connectId = want.GetLongParam(Constants::FORM_CONNECT_ID, 0); + sptr formProviderProxy = iface_cast(remoteObject); + if (formProviderProxy == nullptr) { + FormSupplyCallback::GetInstance()->RemoveConnection(connectId); + APP_LOGE("%{public}s fail, failed to get formProviderProxy", __func__); + return; + } + + int error = formProviderProxy->EventNotify(formEvents, formVisibleType, want, FormSupplyCallback::GetInstance()); + if (error != ERR_OK) { + FormSupplyCallback::GetInstance()->RemoveConnection(connectId); + APP_LOGE("%{public}s fail, Failed to send event notify.", __func__); + } +} + +/** + * @brief Notify form provider for cast temp form. + * + * @param formId The Id of the from. + * @param want The want of the form. + * @param remoteObject Form provider proxy object. + * @return none. + */ +void FormTaskMgr::NotifyCastTemp(const int64_t formId, const Want &want, const sptr &remoteObject) +{ + APP_LOGI("%{public}s called.", __func__); + + long connectId = want.GetLongParam(Constants::FORM_CONNECT_ID, 0); + sptr formProviderProxy = iface_cast(remoteObject); + if (formProviderProxy == nullptr) { + FormSupplyCallback::GetInstance()->RemoveConnection(connectId); + APP_LOGE("%{public}s fail, failed to get formProviderProxy", __func__); + return; + } + + int error = formProviderProxy->NotifyFormCastTempForm(formId, want, FormSupplyCallback::GetInstance()); + if (error != ERR_OK) { + FormSupplyCallback::GetInstance()->RemoveConnection(connectId); + APP_LOGE("%{public}s fail, Failed to get acquire provider form info", __func__); + } +} + +/** + * @brief Post form data to form host when acquire form. + * @param formId The Id of the form. + * @param callingUid Calling uid. + * @param info Form configure info. + * @param wantParams WantParams of the request. + * @param remoteObject Form provider proxx object. + */ +void FormTaskMgr::AcquireTaskToHost(const int64_t formId, const FormRecord &record, +const sptr &remoteObject) +{ + APP_LOGI("FormTaskMgr AcquireTaskToHost, formId:%{public}lld", formId); + + sptr remoteFormHost = iface_cast(remoteObject); + if (remoteFormHost == nullptr) { + APP_LOGE("%{public}s fail, Failed to get form host proxy", __func__); + return; + } + + APP_LOGD("FormTaskMgr remoteFormHost OnAcquired"); + remoteFormHost->OnAcquired(CreateFormJsInfo(formId, record)); +} + +/** + * @brief Post form data to form host when update form. + * @param formId The Id of the form. + * @param callingUid Calling uid. + * @param info Form configure info. + * @param wantParams WantParams of the request. + * @param remoteObject Form provider proxx object. + */ +void FormTaskMgr::UpdateTaskToHost(const int64_t formId, const FormRecord &record, +const sptr &remoteObject) +{ + APP_LOGI("%{public}s start.", __func__); + + sptr remoteFormHost = iface_cast(remoteObject); + if (remoteFormHost == nullptr) { + APP_LOGE("%{public}s fail, Failed to get form host proxy.", __func__); + return; + } + + APP_LOGD("%{public}s, FormTaskMgr remoteFormHost OnUpdate.", __func__); + remoteFormHost->OnUpdate(CreateFormJsInfo(formId, record)); + + APP_LOGI("%{public}s end.", __func__); +} + +/** + * @brief Handle form host died. + * @param remoteHost Form host proxy object. + */ +void FormTaskMgr::HostDied(const sptr &remoteHost) +{ + APP_LOGI("%{public}s, remote client died event", __func__); + if (remoteHost == nullptr) { + APP_LOGI("%{public}s, remote client died, invalid param", __func__); + return; + } + FormDataMgr::GetInstance().HandleHostDied(remoteHost); +} +/** + * @brief Post provider batch delete. + * @param formIds The Id list. + * @param want The want of the request. + * @param remoteObject Form provider proxy object. + */ +void FormTaskMgr::ProviderBatchDelete(std::set &formIds, const Want &want, +const sptr &remoteObject) +{ + APP_LOGI("%{public}s called.", __func__); + long connectId = want.GetLongParam(Constants::FORM_CONNECT_ID, 0); + sptr formProviderProxy = iface_cast(remoteObject); + if (formProviderProxy == nullptr) { + FormSupplyCallback::GetInstance()->RemoveConnection(connectId); + APP_LOGE("%{public}s fail, Failed to get formProviderProxy", __func__); + return; + } + std::vector vFormIds; + vFormIds.assign(formIds.begin(), formIds.end()); + int error = formProviderProxy->NotifyFormsDelete(vFormIds, want, FormSupplyCallback::GetInstance()); + if (error != ERR_OK) { + FormSupplyCallback::GetInstance()->RemoveConnection(connectId); + APP_LOGE("%{public}s failed", __func__); + } +} +/** + * @brief Fire message event to form provider. + * @param formId The Id of the from. + * @param message Event message. + * @param want The want of the request. + * @param remoteObject Form provider proxy object. + */ +void FormTaskMgr::FireFormEvent(const int64_t formId, const std::string &message, const Want &want, + const sptr &remoteObject) +{ + APP_LOGI("%{public}s start", __func__); + long connectId = want.GetLongParam(Constants::FORM_CONNECT_ID, 0); + sptr formProviderProxy = iface_cast(remoteObject); + if (formProviderProxy == nullptr) { + FormSupplyCallback::GetInstance()->RemoveConnection(connectId); + APP_LOGE("%{public}s, Failed to get formProviderProxy", __func__); + return; + } + + int error = formProviderProxy->FireFormEvent(formId, message, want, FormSupplyCallback::GetInstance()); + if (error != ERR_OK) { + FormSupplyCallback::GetInstance()->RemoveConnection(connectId); + APP_LOGE("%{public}s, Failed to fire message event to form provider", __func__); + } + APP_LOGI("%{public}s end", __func__); +} + +/** + * @brief Handle uninstall message. + * @param formIds The Id list of the forms. + * @param remoteObject Form provider proxy object. + */ +void FormTaskMgr::FormUninstall(const std::vector &formIds, + const sptr &remoteObject) +{ + APP_LOGI("%{public}s start", __func__); + sptr remoteFormHost = iface_cast(remoteObject); + if (remoteFormHost == nullptr) { + APP_LOGE("%{public}s fail, Failed to get form host proxy.", __func__); + return; + } + + remoteFormHost->OnUninstall(formIds); + + APP_LOGI("%{public}s end", __func__); +} + +/** + * @brief Create form data for form host. + * @param formId The Id of the form. + * @param record Form record. + * @return Form data. + */ +FormJsInfo FormTaskMgr::CreateFormJsInfo(const int64_t formId, const FormRecord &record) +{ + FormJsInfo form; + form.formId = formId; + form.bundleName = record.bundleName; + form.abilityName = record.abilityName; + form.formName = record.formName; + form.formTempFlg = record.formTempFlg; + form.jsFormCodePath = record.jsFormCodePath; + form.formData = record.formProviderInfo.GetFormDataString(); + + return form; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/formmgr/src/form_timer_mgr.cpp b/services/formmgr/src/form_timer_mgr.cpp new file mode 100644 index 0000000000..a48df9d768 --- /dev/null +++ b/services/formmgr/src/form_timer_mgr.cpp @@ -0,0 +1,1017 @@ +/* + * Copyright (c) 2021 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 "appexecfwk_errors.h" +#include "app_log_wrapper.h" +#include "common_event_manager.h" +#include "common_event_support.h" +#include "form_constants.h" +#include "form_provider_mgr.h" +#include "form_refresh_limiter.h" +#include "form_timer_mgr.h" +#include "form_util.h" +#include "want.h" + +namespace OHOS { +namespace AppExecFwk { +FormTimerMgr::FormTimerMgr() +{ + Init(); +} +FormTimerMgr::~FormTimerMgr() +{ + ClearIntervalTimer(); +} +/** + * @brief Add form timer by timer task. + * @param task The form timer task. + * @return Returns true on success, false on failure. + */ +bool FormTimerMgr::AddFormTimer(const FormTimer &task) +{ + APP_LOGI("%{public}s, formId: %{public}lld", __func__, task.formId); + if (task.isUpdateAt) { + if (task.hour >= Constants::MIN_TIME && task.hour <= Constants::MAX_HOUR && task.min >= Constants::MIN_TIME && + task.min <= Constants::MAX_MININUTE) { + return AddUpdateAtTimer(task); + } else { + APP_LOGE("%{public}s failed, update at time is invalid", __func__); + return false; + } + } else { + if (task.period >= Constants::MIN_PERIOD && task.period <= Constants::MAX_PERIOD && + (task.period % Constants::MIN_PERIOD) == 0) { + return AddIntervalTimer(task); + } else { + APP_LOGE("%{public}s failed, interval time is invalid", __func__); + return false; + } + } +} +/** + * @brief Add duration form timer. + * @param formId The Id of the form. + * @param updateDuration Update duration + * @return Returns true on success, false on failure. + */ +bool FormTimerMgr::AddFormTimer(const int64_t formId, const long updateDuration) +{ + FormTimer timerTask(formId, updateDuration); + return AddFormTimer(timerTask); +} +/** + * @brief Add scheduled form timer. + * @param formId The Id of the form. + * @param updateAtHour Hour + * @param updateAtMin Min + * @return Returns true on success, false on failure. + */ +bool FormTimerMgr::AddFormTimer(const int64_t formId, const long updateAtHour, const long updateAtMin) +{ + FormTimer timerTask(formId, updateAtHour, updateAtMin); + return AddFormTimer(timerTask); +} +/** + * @brief Remove form timer by form id. + * @param formId The Id of the form. + * @return Returns true on success, false on failure. + */ +bool FormTimerMgr::RemoveFormTimer(const int64_t formId) +{ + APP_LOGI("%{public}s, task: %{public}lld", __func__, formId); + + if (!DeleteIntervalTimer(formId)) { + DeleteUpdateAtTimer(formId); + } + + DeleteDynamicItem(formId); + refreshLimiter_.DeleteItem(formId); + + return true; +} +/** + * @brief Update form timer. + * @param formId The Id of the form. + * @param type Timer type. + * @param timerCfg Timer config. + * @return Returns true on success, false on failure. + */ +bool FormTimerMgr::UpdateFormTimer(const int64_t formId, const UpdateType &type, const FormTimerCfg &timerCfg) +{ + if (!timerCfg.enableUpdate) { + APP_LOGW("%{public}s, enableUpdate is false", __func__); + return false; + } + + switch (type) { + case UpdateType::TYPE_INTERVAL_CHANGE: { + return UpdateIntervalValue(formId, timerCfg); + } + case UpdateType::TYPE_ATTIME_CHANGE: { + return UpdateAtTimerValue(formId, timerCfg); + } + case UpdateType::TYPE_INTERVAL_TO_ATTIME: { + return IntervalToAtTimer(formId, timerCfg); + } + case UpdateType::TYPE_ATTIME_TO_INTERVAL: { + return AtTimerToIntervalTimer(formId, timerCfg); + } + default: { + APP_LOGE("%{public}s failed, invalid UpdateType", __func__); + return false; + } + } +} +/** + * @brief Update Interval timer task value. + * @param formId The Id of the form. + * @param timerCfg task value. + * @return Returns true on success, false on failure. + */ +bool FormTimerMgr::UpdateIntervalValue(const int64_t formId, const FormTimerCfg &timerCfg) +{ + if (timerCfg.updateDuration < Constants::MIN_PERIOD || timerCfg.updateDuration > Constants::MAX_PERIOD + || (timerCfg.updateDuration % Constants::MIN_PERIOD) != 0) { + APP_LOGE("%{public}s failed, invalid param", __func__); + return false; + } + + std::lock_guard lock(intervalMutex_); + auto intervalTask = intervalTimerTasks_.find(formId); + if (intervalTask != intervalTimerTasks_.end()) { + intervalTask->second.period = timerCfg.updateDuration; + return true; + } else { + APP_LOGE("%{public}s failed, the interval timer is not exist", __func__); + return false; + } +} +/** + * @brief Update update at timer task value. + * @param formId The Id of the form. + * @param timerCfg task value. + * @return Returns true on success, false on failure. + */ +bool FormTimerMgr::UpdateAtTimerValue(const int64_t formId, const FormTimerCfg &timerCfg) +{ + if (timerCfg.updateAtHour < Constants::MIN_TIME || timerCfg.updateAtHour > Constants::MAX_HOUR + || timerCfg.updateAtMin < Constants::MIN_TIME || timerCfg.updateAtMin > Constants::MAX_MININUTE) { + APP_LOGE("%{public}s failed, time is invalid", __func__); + return false; + } + { + std::lock_guard lock(updateAtMutex_); + std::list::iterator itItem; + UpdateAtItem changedItem; + for (itItem = updateAtTimerTasks_.begin(); itItem != updateAtTimerTasks_.end(); itItem++) { + if (itItem->refreshTask.formId == formId) { + changedItem = *itItem; + updateAtTimerTasks_.erase(itItem); + break; + } + } + + if (changedItem.refreshTask.formId == 0) { + APP_LOGE("%{public}s failed, the update at timer is not exist", __func__); + return false; + } + changedItem.refreshTask.hour = timerCfg.updateAtHour; + changedItem.refreshTask.min = timerCfg.updateAtMin; + changedItem.updateAtTime = changedItem.refreshTask.hour * Constants::MIN_PER_HOUR + changedItem.refreshTask.min; + AddUpdateAtItem(changedItem); + } + + UpdateAtTimerAlarm(); + return true; +} +/** + * @brief Interval timer task to update at timer task. + * @param formId The Id of the form. + * @param timerCfg task value. + * @return Returns true on success, false on failure. + */ +bool FormTimerMgr::IntervalToAtTimer(const int64_t formId, const FormTimerCfg &timerCfg) +{ + if (timerCfg.updateAtHour < Constants::MIN_TIME || timerCfg.updateAtHour > Constants::MAX_HOUR + || timerCfg.updateAtMin < Constants::MIN_TIME || timerCfg.updateAtMin > Constants::MAX_MININUTE) { + APP_LOGE("%{public}s failed, time is invalid", __func__); + return false; + } + + std::lock_guard lock(intervalMutex_); + FormTimer timerTask; + auto intervalTask = intervalTimerTasks_.find(formId); + if (intervalTask != intervalTimerTasks_.end()) { + timerTask = intervalTask->second; + intervalTimerTasks_.erase(intervalTask); + + timerTask.isUpdateAt = true; + timerTask.hour = timerCfg.updateAtHour; + timerTask.min = timerCfg.updateAtMin; + if (!AddUpdateAtTimer(timerTask)) { + APP_LOGE("%{public}s, failed to add update at timer", __func__); + return false; + } + return true; + } else { + APP_LOGE("%{public}s failed, the interval timer is not exist", __func__); + return false; + } +} +/** + * @brief Update at timer task to interval timer task. + * @param formId The Id of the form. + * @param timerCfg task value. + * @return Returns true on success, false on failure. + */ +bool FormTimerMgr::AtTimerToIntervalTimer(const int64_t formId, const FormTimerCfg &timerCfg) +{ + if (timerCfg.updateDuration < Constants::MIN_PERIOD || timerCfg.updateDuration > Constants::MAX_PERIOD + || (timerCfg.updateDuration % Constants::MIN_PERIOD) != 0) { + APP_LOGE("%{public}s failed, time is invalid", __func__); + return false; + } + + UpdateAtItem targetItem; + { + std::lock_guard lock(updateAtMutex_); + std::list::iterator itItem; + for (itItem = updateAtTimerTasks_.begin(); itItem != updateAtTimerTasks_.end(); itItem++) { + if (itItem->refreshTask.formId == formId) { + targetItem = *itItem; + updateAtTimerTasks_.erase(itItem); + break; + } + } + } + + UpdateAtTimerAlarm(); + + if (targetItem.refreshTask.formId == 0) { + APP_LOGE("%{public}s failed, the update at timer is not exist", __func__); + return false; + } + targetItem.refreshTask.isUpdateAt = false; + targetItem.refreshTask.period = timerCfg.updateDuration; + targetItem.refreshTask.refreshTime = LONG_MAX; + if (!AddIntervalTimer(targetItem.refreshTask)) { + APP_LOGE("%{public}s, failed to add interval timer", __func__); + return false; + } + return true; +} +/** + * @brief Is limiter enable refresh. + * @param formId The Id of the form. + * @return Returns true on success, false on failure. + */ +bool FormTimerMgr::IsLimiterEnableRefresh(const int64_t formId) +{ + return refreshLimiter_.IsEnableRefresh(formId); +} +/** + * @brief Increase refresh count. + * @param formId The Id of the form. + */ +void FormTimerMgr::IncreaseRefreshCount(const int64_t formId) +{ + refreshLimiter_.Increase(formId); +} +/** + * @brief Set next refresh time. + * @param formId The Id of the form. + * @param nextGapTime Next gap time. + * @return Returns true on success, false on failure. + */ +bool FormTimerMgr::SetNextRefreshTime(const int64_t formId, const long nextGapTime) +{ + if (nextGapTime < Constants::MIN_NEXT_TIME) { + APP_LOGE("%{public}s failed, nextGapTime is invalid, nextGapTime:%{public}ld", __func__, nextGapTime); + return false; + } + auto timeSinceEpoch = std::chrono::steady_clock::now().time_since_epoch(); + auto timeInSec = std::chrono::duration_cast(timeSinceEpoch).count(); + int64_t refreshTime = timeInSec + nextGapTime * Constants::MS_PER_SECOND; + std::lock_guard lock(refreshMutex_); + bool isExist = false; + for (auto &refreshItem: dynamicRefreshTasks_) { + if (refreshItem.formId == formId) { + refreshItem.settedTime = refreshTime; + isExist = true; + break; + } + } + if (!isExist) { + DynamicRefreshItem theItem; + theItem.formId = formId; + theItem.settedTime = refreshTime; + dynamicRefreshTasks_.emplace_back(theItem); + } + std::sort(dynamicRefreshTasks_.begin(), dynamicRefreshTasks_.end(), CompareDynamicRefreshItem); + if (!UpdateDynamicAlarm()) { + APP_LOGE("%{public}s, failed to UpdateDynamicAlarm", __func__); + return false; + } + refreshLimiter_.AddItem(formId); + SetEnableFlag(formId, false); + + return true; +} + +void FormTimerMgr::SetEnableFlag(int64_t formId, bool flag) +{ + // try interval list + auto iter = intervalTimerTasks_.find(formId); + if (iter != intervalTimerTasks_.end()) { + iter->second.isEnable = flag; + APP_LOGI("%{public}s, formId:%{public}lld, isEnable:%{public}d", __func__, formId, flag ? 1 : 0); + return; + } +} + +/** + * @brief Get refresh count. + * @param formId The Id of the form. + * @return Returns refresh count. + */ +int FormTimerMgr::GetRefreshCount(const int64_t formId) const +{ + return refreshLimiter_.GetRefreshCount(formId); +} +/** + * @brief Mark remind. + * @param formId The Id of the form. + * @return true or false. + */ +void FormTimerMgr::MarkRemind(const int64_t formId) +{ + refreshLimiter_.MarkRemind(formId); +} +/** + * @brief Add update at timer. + * @param task Update time task. + * @return Returns true on success, false on failure. + */ +bool FormTimerMgr::AddUpdateAtTimer(const FormTimer &task) +{ + APP_LOGI("%{public}s start", __func__); + { + std::lock_guard lock(updateAtMutex_); + for (auto &updateAtTimer : updateAtTimerTasks_) { + if (updateAtTimer.refreshTask.formId == task.formId) { + APP_LOGW("%{public}s, already exist formTimer, formId:%{public}lld task", __func__, task.formId); + return true; + } + } + + UpdateAtItem atItem; + atItem.refreshTask = task; + atItem.updateAtTime = task.hour * Constants::MIN_PER_HOUR + task.min; + + AddUpdateAtItem(atItem); + } + + if (!UpdateAtTimerAlarm()) { + APP_LOGE("%{public}s, failed to update alarm.", __func__); + return false; + } + + return refreshLimiter_.AddItem(task.formId); +} +/** + * @brief Add update interval timer task. + * @param task Update interval timer task. + * @return Returns true on success, false on failure. + */ +bool FormTimerMgr::AddIntervalTimer(const FormTimer &task) +{ + APP_LOGI("%{public}s start", __func__); + { + std::lock_guard lock(intervalMutex_); + EnsureInitIntervalTimer(); + if (intervalTimerTasks_.find(task.formId) != intervalTimerTasks_.end()) { + APP_LOGW("%{public}s, already exist formTimer, formId:%{public}lld task", __func__, task.formId); + return true; + } + intervalTimerTasks_.emplace(task.formId, task); + } + UpdateLimiterAlarm(); + return refreshLimiter_.AddItem(task.formId); +} +/** + * @brief Add update at timer item. + * @param task Update at timer item. + */ +void FormTimerMgr::AddUpdateAtItem(const UpdateAtItem &atItem) +{ + if (updateAtTimerTasks_.empty()) { + updateAtTimerTasks_.emplace_back(atItem); + return; + } + + UpdateAtItem firstItem = updateAtTimerTasks_.front(); + if (atItem.updateAtTime < firstItem.updateAtTime) { + updateAtTimerTasks_.emplace_front(atItem); + return; + } + + bool isInsert = false; + std::list::iterator itItem; + for (itItem = updateAtTimerTasks_.begin(); itItem != updateAtTimerTasks_.end(); itItem++) { + if (atItem.updateAtTime < itItem->updateAtTime) { + updateAtTimerTasks_.insert(itItem, atItem); + isInsert = true; + break; + } + } + + if (!isInsert) { + updateAtTimerTasks_.emplace_back(atItem); + } +} +/** + * @brief Handle system time changed. + */ +void FormTimerMgr::HandleSystemTimeChanged() +{ + APP_LOGI("%{public}s start", __func__); + if (!updateAtTimerTasks_.empty()) { + UpdateAtTimerAlarm(); + } + APP_LOGI("%{public}s end", __func__); +} +/** + * @brief Reset form limiter. + */ +void FormTimerMgr::HandleResetLimiter() +{ + APP_LOGI("%{public}s start", __func__); + + std::vector remindTasks; + bool bGetTasks = GetRemindTasks(remindTasks); + if (bGetTasks) { + APP_LOGI("%{public}s failed, remind when reset limiter", __func__); + for (auto &task : remindTasks) { + ExecTimerTask(task); + } + } + APP_LOGI("%{public}s end", __func__); +} +/** + * @brief Update attime trigger. + * @param updateTime Update time. + */ +void FormTimerMgr::OnUpdateAtTrigger(long updateTime) +{ + APP_LOGI("%{public}s start, updateTime:%{public}ld", __func__, updateTime); + std::vector updateList; + { + std::lock_guard lock(updateAtMutex_); + std::list::iterator itItem; + for (itItem = updateAtTimerTasks_.begin(); itItem != updateAtTimerTasks_.end(); itItem++) { + if (itItem->updateAtTime == updateTime && itItem->refreshTask.isEnable) { + updateList.emplace_back(*itItem); + } + } + } + + UpdateAtTimerAlarm(); + + if (!updateList.empty()) { + APP_LOGI("%{public}s, update at timer triggered, trigged time: %{public}ld", __func__, updateTime); + for (auto &item : updateList) { + ExecTimerTask(item.refreshTask); + } + } + APP_LOGI("%{public}s end", __func__); +} +/** + * @brief Dynamic time trigger. + * @param updateTime Update time. + */ +void FormTimerMgr::OnDynamicTimeTrigger(long updateTime) +{ + APP_LOGI("%{public}s start, updateTime:%{public}ld", __func__, updateTime); + std::vector updateList; + { + std::lock_guard lock(dynamicMutex_); + auto timeSinceEpoch = std::chrono::steady_clock::now().time_since_epoch(); + auto timeInSec = std::chrono::duration_cast(timeSinceEpoch).count(); + long markedTime = timeInSec + Constants::ABS_REFRESH_MS; + std::vector::iterator itItem; + for (itItem = dynamicRefreshTasks_.begin(); itItem != dynamicRefreshTasks_.end();) { + if (itItem->settedTime <= updateTime || itItem->settedTime <= markedTime) { + if (refreshLimiter_.IsEnableRefresh(itItem->formId)) { + FormTimer timerTask(itItem->formId, true); + updateList.emplace_back(timerTask); + } + itItem = dynamicRefreshTasks_.erase(itItem); + SetIntervalEnableFlag(itItem->formId, true); + } else { + itItem++; + } + } + std::sort(dynamicRefreshTasks_.begin(), dynamicRefreshTasks_.end(), CompareDynamicRefreshItem); + } + + UpdateDynamicAlarm(); + if (!updateList.empty()) { + APP_LOGI("%{public}s triggered, trigged time: %{public}ld", __func__, updateTime); + for (auto &task : updateList) { + ExecTimerTask(task); + } + } + APP_LOGI("%{public}s end", __func__); +} +/** + * @brief Get remind tasks. + * @param remindTasks Remind tasks. + * @return Returns true on success, false on failure. + */ +bool FormTimerMgr::GetRemindTasks(std::vector &remindTasks) +{ + APP_LOGI("%{public}s start", __func__); + std::vector remindList = refreshLimiter_.GetRemindListAndResetLimit(); + for (int64_t id : remindList) { + FormTimer formTimer(id, false); + remindTasks.emplace_back(formTimer); + } + + UpdateLimiterAlarm(); + + if(remindTasks.size() > 0) { + return true; + } else { + return false; + } + APP_LOGI("%{public}s end", __func__); +} +/** + * @brief Set enableFlag for interval timer task. + * @param formId The Id of the form. + * @param flag Enable flag. + */ +void FormTimerMgr::SetIntervalEnableFlag(int64_t formId, bool flag) +{ + std::lock_guard lock(intervalMutex_); + // try interval list + auto refreshTask = intervalTimerTasks_.find(formId); + if (refreshTask != intervalTimerTasks_.end()) { + refreshTask->second.isEnable = flag; + APP_LOGI("%{public}s, formId:%{public}lld, isEnable:%{public}d", __func__, formId, flag ? 1 : 0); + return; + } +} +/** + * @brief Delete interval timer task. + * @param formId The Id of the form. + * @return Returns true on success, false on failure. + */ +bool FormTimerMgr::DeleteIntervalTimer(const int64_t formId) +{ + APP_LOGI("%{public}s start", __func__); + bool isExist = false; + std::lock_guard lock(intervalMutex_); + auto intervalTask = intervalTimerTasks_.find(formId); + if (intervalTask != intervalTimerTasks_.end()) { + intervalTimerTasks_.erase(intervalTask); + isExist = true; + } + + if (intervalTimerTasks_.empty()) { + ClearIntervalTimer(); + } + APP_LOGI("%{public}s end", __func__); + return isExist; +} +/** + * @brief Delete update at timer. + * @param formId The Id of the form. + */ +void FormTimerMgr::DeleteUpdateAtTimer(const int64_t formId) +{ + APP_LOGI("%{public}s start", __func__); + { + std::lock_guard lock(updateAtMutex_); + std::list::iterator itItem; + for (itItem = updateAtTimerTasks_.begin(); itItem != updateAtTimerTasks_.end(); itItem++) { + if (itItem->refreshTask.formId == formId) { + updateAtTimerTasks_.erase(itItem); + break; + } + } + } + + UpdateAtTimerAlarm(); + + APP_LOGI("%{public}s end", __func__); +} +/** + * @brief Delete dynamic refresh item. + * @param formId The Id of the form. + */ +void FormTimerMgr::DeleteDynamicItem(const int64_t formId) +{ + APP_LOGI("%{public}s start", __func__); + std::lock_guard lock(dynamicMutex_); + std::vector::iterator itItem; + for (itItem = dynamicRefreshTasks_.begin(); itItem != dynamicRefreshTasks_.end();) { + if (itItem->formId == formId) { + dynamicRefreshTasks_.erase(itItem); + SetIntervalEnableFlag(itItem->formId, true); + break; + } + } + std::sort(dynamicRefreshTasks_.begin(), dynamicRefreshTasks_.end(), CompareDynamicRefreshItem); + + UpdateDynamicAlarm(); + APP_LOGI("%{public}s end", __func__); +} +/** +* @brief interval timer task timeout. +*/ +void FormTimerMgr::OnIntervalTimeOut() +{ + APP_LOGI("%{public}s start", __func__); + std::lock_guard lock(intervalMutex_); + std::vector updateList; + long currentTime = FormUtil::GetCurrentNanosecond() / Constants::TIME_1000000; + for (auto &intervalPair : intervalTimerTasks_) { + FormTimer &intervalTask = intervalPair.second; + if ((intervalTask.refreshTime == LONG_MAX || (currentTime - intervalTask.refreshTime) >= intervalTask.period || + std::abs((currentTime - intervalTask.refreshTime) - intervalTask.period) < Constants::ABS_TIME) && + intervalTask.isEnable && refreshLimiter_.IsEnableRefresh(intervalTask.formId)) { + intervalTask.refreshTime = currentTime; + updateList.emplace_back(intervalTask); + } + } + + if (!updateList.empty()) { + for (auto &task : updateList) { + ExecTimerTask(task); + } + } + APP_LOGI("%{public}s end", __func__); +} +/** + * @brief Update at timer task alarm. + * @return Returns true on success, false on failure. + */ +bool FormTimerMgr::UpdateAtTimerAlarm() +{ + APP_LOGI("%{public}s start", __func__); + // AlarmManager* alarm = GetAlarmManagerLocked(); + // if (alarm == nullptr) { + // APP_LOGE("%{public}s failed, failed to get alarm manager, can not updateAlarm", __func__); + // return false; + // } + struct tm tmAtTime = {0}; + auto tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + struct tm* ptm = localtime_r(&tt, &tmAtTime); + if (ptm == nullptr) { + APP_LOGE("%{public}s failed, localtime error", __func__); + return false; + } + + int nowAtTime = tmAtTime.tm_hour * Constants::MIN_PER_HOUR + tmAtTime.tm_min; + long currentTime = FormUtil::GetCurrentMillisecond(); + UpdateAtItem findedItem; + bool bFinded = FindNextAtTimerItem(nowAtTime, findedItem); + if (!bFinded) { + ClearUpdateAtTimerResource(); + APP_LOGI("%{public}s, no update at task in system now.", __func__); + return true; + } + + int nextWakeUpTime = findedItem.updateAtTime; + tmAtTime.tm_sec = 0; + tmAtTime.tm_hour = findedItem.refreshTask.hour; + tmAtTime.tm_min = findedItem.refreshTask.min; + long selectTime = FormUtil::GetMillisecondFromTm(tmAtTime); + if (selectTime < currentTime) { + tmAtTime.tm_mday += 1; + nextWakeUpTime += (Constants::HOUR_PER_DAY * Constants::MIN_PER_HOUR); + } + + if (nextWakeUpTime == atTimerWakeUpTime_) { + APP_LOGW("%{public}s end, wakeUpTime not change, no need update alarm.", __func__); + return true; + } + + // PendingIntent pendingIntent = getPendingIntent(findedItem.updateAtTime); + // if (pendingIntent == null) { + // HiLog.error(LABEL_LOG, "create pendingIntent failed."); + // return false; + // } + atTimerWakeUpTime_ = nextWakeUpTime; + // if (currentPendingIntent != null) { + // alarm.cancel(currentPendingIntent); + // } + // currentPendingIntent = pendingIntent; + // alarm.setExact(AlarmManager.RTC_WAKEUP, FormUtil::GetMillisecondFromTm(tmAtTime), pendingIntent); + APP_LOGI("%{public}s end", __func__); + return true; +} +/** + * @brief Update limiter task alarm. + * @return Returns true on success, false on failure. + */ +bool FormTimerMgr::UpdateLimiterAlarm() +{ + APP_LOGI("%{public}s start", __func__); + // AlarmManager alarm = getAlarmManagerLocked(); + // if (alarm == null) { + // HiLog.error(LABEL_LOG, "faied to get alarm manager, can not updateLimiterAlarm"); + // return false; + // } + + // PendingIntent pendingIntent = getLimiterPendingIntent(); + // if (pendingIntent == null) { + // HiLog.error(LABEL_LOG, "create limiterPendingIntent failed."); + // return false; + // } + + // if (limiterPendingIntent != null) { + // alarm.cancel(limiterPendingIntent); + // } + // limiterPendingIntent = pendingIntent; + + // Calendar calendar = Calendar.getInstance(); + // calendar.set(Calendar.DATE, Calendar.getInstance().get(Calendar.DATE)); + // calendar.set(Calendar.HOUR_OF_DAY, MAX_HOUR); + // calendar.set(Calendar.MINUTE, MAX_MININUTE); + // calendar.set(Calendar.SECOND, MAX_SECOND); + // calendar.set(Calendar.MILLISECOND, LIMIT_MS); + // alarm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent); + APP_LOGI("%{public}s end", __func__); + return true; +} +/** + * @brief Update dynamic refresh task alarm. + * @return Returns true on success, false on failure. + */ +bool FormTimerMgr::UpdateDynamicAlarm() +{ + APP_LOGI("%{public}s start", __func__); + if (dynamicRefreshTasks_.empty()) { + ClearDynamicResource(); + return true; + } + + bool needUpdate = false; + DynamicRefreshItem firstTask = dynamicRefreshTasks_.at(0); + if (dynamicWakeUpTime_ != firstTask.settedTime) { + dynamicWakeUpTime_ = firstTask.settedTime; + needUpdate = true; + } + + if (!needUpdate) { + APP_LOGE("%{public}s failed, no need to UpdateDynamicAlarm.", __func__); + return true; + } + + // AlarmManager alarm = getAlarmManagerLocked(); + // if (alarm == null) { + // HiLog.error(LABEL_LOG, "faied to get alarm manager, can not UpdateDynamicAlarm."); + // return false; + // } + + // PendingIntent pendingIntent = getDynamicPendingIntent(dynamicWakeUpTime); + // if (pendingIntent == null) { + // HiLog.error(LABEL_LOG, "create dynamic pendingIntent failed.", __func__); + // return false; + // } + // if (dynamicPendingIntent != null) { + // alarm.cancel(dynamicPendingIntent); + // } + // dynamicPendingIntent = pendingIntent; + // alarm.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, dynamicWakeUpTime, pendingIntent); + APP_LOGI("%{public}s end", __func__); + + return true; +} +/** + * @brief Clear dynamic refresh resource. + */ +void FormTimerMgr::ClearDynamicResource() +{ + APP_LOGI("%{public}s start", __func__); + // AlarmManager alarm = getAlarmManagerLocked(); + // if (alarm == null) { + // return; + // } + + // if (dynamicPendingIntent != null) { + // alarm.cancel(dynamicPendingIntent); + // dynamicPendingIntent = null; + // } + dynamicWakeUpTime_ = LONG_MAX; + APP_LOGI("%{public}s end", __func__); +} +/** + * @brief Fint next at timer item. + * @param nowTime Update time. + * @param updateAtItem Next at timer item. + * @return Returns true on success, false on failure. + */ +bool FormTimerMgr::FindNextAtTimerItem(const int nowTime, UpdateAtItem &updateAtItem) +{ + APP_LOGI("%{public}s start", __func__); + if (updateAtTimerTasks_.empty()) { + APP_LOGW("%{public}s, updateAtTimerTasks_ is empty", __func__); + return false; + } + + std::lock_guard lock(updateAtMutex_); + std::list::iterator itItem; + for (itItem = updateAtTimerTasks_.begin(); itItem != updateAtTimerTasks_.end(); itItem++) { + if (itItem->updateAtTime > nowTime) { + updateAtItem = *itItem; + break; + } + } + + if (itItem == updateAtTimerTasks_.end()) { + updateAtItem = updateAtTimerTasks_.front(); + } + APP_LOGI("%{public}s end", __func__); + return true; +} +/** + * @brief Clear update at timer resource. + */ +void FormTimerMgr::ClearUpdateAtTimerResource() +{ + APP_LOGI("%{public}s start", __func__); + if (!updateAtTimerTasks_.empty()) { + APP_LOGW("%{public}s, updateAtTimerTasks_ is not empty", __func__); + return; + } + + // AlarmManager alarm = getAlarmManagerLocked(); + // if (alarm == null) { + // return; + // } + + // if (currentPendingIntent != null) { + // alarm.cancel(currentPendingIntent); + // currentPendingIntent = null; + // } + atTimerWakeUpTime_ = LONG_MAX; + + APP_LOGI("%{public}s end", __func__); +} +/** + * @brief Ensure init interval timer resource. + */ +void FormTimerMgr::EnsureInitIntervalTimer() +{ + if (intervalTimer_ != NULL) { + return; + } + + APP_LOGI("%{public}s, init base timer task", __func__); + intervalTimer_ = new Utils::Timer("interval timer"); + uint32_t iResult = intervalTimer_->Setup(); + if (iResult != ERR_OK) { + APP_LOGE("%{public}s failed, init base timer task error", __func__); + return; + } + auto timeCallback = std::bind(&FormTimerMgr::OnIntervalTimeOut, this); + intervalTimer_->Register(timeCallback, Constants::MIN_PERIOD); + + APP_LOGI("%{public}s end", __func__); +} +/** + * @brief Clear interval timer resource. + */ +void FormTimerMgr::ClearIntervalTimer() +{ + APP_LOGI("%{public}s start", __func__); + if (intervalTimer_ != nullptr) { + APP_LOGI("%{public}s clear interval timer start", __func__); + intervalTimer_->Shutdown(); + delete intervalTimer_; + intervalTimer_ = nullptr; + APP_LOGI("%{public}s clear interval timer end", __func__); + } + APP_LOGI("%{public}s end", __func__); +} +/** + * @brief Get thread pool for timer task. + */ +OHOS::ThreadPool* FormTimerMgr::GetTaskThreadExecutor() +{ + APP_LOGI("%{public}s start", __func__); + if (taskExecutor_ == nullptr) { + taskExecutor_ = new OHOS::ThreadPool("timer task thread"); + taskExecutor_->Start(Constants::WORK_POOL_SIZE); + } + APP_LOGI("%{public}s end", __func__); + return taskExecutor_; +} + +/** + * @brief Execute Form timer task. + * @param timerTask Form timer task. + */ +void FormTimerMgr::ExecTimerTask(const FormTimer &timerTask) +{ + APP_LOGI("%{public}s start", __func__); + OHOS::ThreadPool* Executor = GetTaskThreadExecutor(); + if (Executor != nullptr) { + APP_LOGI("%{public}s run", __func__); + AAFwk::Want want; + if (timerTask.isCountTimer) { + want.SetParam(Constants::KEY_IS_TIMER, true); + } + auto task = std::bind(&FormProviderMgr::RefreshForm, &FormProviderMgr::GetInstance(), timerTask.formId, want); + Executor->AddTask(task); + } + APP_LOGI("%{public}s end", __func__); +} + +/** + * @brief Init. + */ +void FormTimerMgr::Init() +{ + APP_LOGI("%{public}s start", __func__); + timerReceiver_ = nullptr; + EventFwk::MatchingSkills matchingSkills; + matchingSkills.AddEvent(Constants::ACTION_UPDATEATTIMER); + matchingSkills.AddEvent(EventFwk::CommonEventSupport::COMMON_EVENT_TIME_CHANGED); + matchingSkills.AddEvent(EventFwk::CommonEventSupport::COMMON_EVENT_TIMEZONE_CHANGED); + + // init TimerReceiver + EventFwk::CommonEventSubscribeInfo subscribeInfo(matchingSkills); + // subscribeInfo.SetPermission(permissin); + timerReceiver_ = std::make_shared(subscribeInfo); + EventFwk::CommonEventManager::SubscribeCommonEvent(timerReceiver_); + + intervalTimer_ = nullptr; + taskExecutor_ = nullptr; + + APP_LOGI("%{public}s end", __func__); +} + +/** + * @brief Receiver Constructor. + * @param subscriberInfo Subscriber info. + */ +FormTimerMgr::TimerReceiver::TimerReceiver(const EventFwk::CommonEventSubscribeInfo &subscriberInfo) + : EventFwk::CommonEventSubscriber(subscriberInfo) +{} +/** + * @brief Receive common event. + * @param eventData Common event data. + */ +void FormTimerMgr::TimerReceiver::OnReceiveEvent(const EventFwk::CommonEventData &eventData) +{ + AAFwk::Want want = eventData.GetWant(); + std::string action = want.GetAction(); + + APP_LOGI("%{public}s, action:%{public}s.", __func__, action.c_str()); + + if (action == EventFwk::CommonEventSupport::COMMON_EVENT_TIME_CHANGED + || action == EventFwk::CommonEventSupport::COMMON_EVENT_TIMEZONE_CHANGED) { + FormTimerMgr::GetInstance().HandleSystemTimeChanged(); + } else if (action == Constants::ACTION_UPDATEATTIMER) { + int type = want.GetIntParam(Constants::KEY_ACTION_TYPE, Constants::TYPE_STATIC_UPDATE); + if (type == Constants::TYPE_RESET_LIMIT) { + FormTimerMgr::GetInstance().HandleResetLimiter(); + } else if (type == Constants::TYPE_STATIC_UPDATE) { + long updateTime = want.GetLongParam(Constants::KEY_WAKEUP_TIME, -1); + if (updateTime < 0) { + APP_LOGE("%{public}s failed, invalid updateTime:%{public}ld.", __func__, updateTime); + return; + } + FormTimerMgr::GetInstance().OnUpdateAtTrigger(updateTime); + } else if (type == Constants::TYPE_DYNAMIC_UPDATE) { + long updateTime = want.GetLongParam(Constants::KEY_WAKEUP_TIME, 0); + if (updateTime <= 0) { + APP_LOGE("%{public}s failed, invalid updateTime:%{public}ld.", __func__, updateTime); + return; + } + FormTimerMgr::GetInstance().OnDynamicTimeTrigger(updateTime); + } else { + APP_LOGE("%{public}s failed, invalid type when action is update at timer.", __func__); + } + } else { + APP_LOGE("%{public}s failed, invalid action.", __func__); + } +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/formmgr/src/form_util.cpp b/services/formmgr/src/form_util.cpp new file mode 100644 index 0000000000..0d96831b29 --- /dev/null +++ b/services/formmgr/src/form_util.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2021 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 +// #include +#include +#include +// #include + +#include "app_log_wrapper.h" +#include "form_constants.h" +#include "form_util.h" +#include "ohos_account_kits.h" + +namespace OHOS { +namespace AppExecFwk { +using namespace std; +using namespace std::chrono; + +constexpr int64_t SEC_TO_NANOSEC = 1000000000; +constexpr int64_t SEC_TO_MILLISEC = 1000; +constexpr int64_t MILLISEC_TO_NANOSEC = 1000000; +constexpr int64_t INVALID_UDID_HASH = 0; +/** + * @brief create want for form. + * @param formName The name of the form. + * @param specificationId specification id. + * @param isTemporaryForm temporary form or not. + * @param want The want of the form. + */ +void FormUtil::CreateFormWant(const std::string &formName, const int32_t specificationId, const bool isTemporaryForm, +Want &want) +{ + want.SetParam(Constants::PARAM_FORM_NAME_KEY, formName); + want.SetParam(Constants::PARAM_FORM_DIMENSION_KEY, specificationId); + want.SetParam(Constants::PARAM_FORM_TEMPORARY_KEY, isTemporaryForm); +} + +/** + * @brief create default want for form. + * @param want The want of the form.. + * @param uri The uri. + * @param connectId connect id. + */ +void FormUtil::CreateDefaultFormWant(Want &want, const std::string &uri, const int32_t connectId) +{ + want.SetParam(Constants::FORM_CONNECT_ID, connectId); + want.SetParam(Constants::FORM_SUPPLY_INFO, uri); +} + +/** + * @brief create udid for form. + * @return udid. + */ +std::string FormUtil::GenerateUdid() +{ + // uuid_t uuid; + char buf[256] = {0}; + // uuid_generate(uuid); + + // uuid_unparse(uuid, buf); + return buf; +} + +/** + * @brief create form id for form. + * @param udidHash udid hash + * @return new form id. + */ +int64_t FormUtil::GenerateFormId(int64_t udidHash) +{ + struct timespec t; + t.tv_sec = 0; + t.tv_nsec = 0; + clock_gettime(CLOCK_REALTIME, &t); + + int64_t elapsedTime { ((t.tv_sec) * SEC_TO_NANOSEC + t.tv_nsec) }; + size_t elapsedHash = std::hash()(std::to_string(elapsedTime)); + APP_LOGI("%{public}s, GenerateFormId generate elapsed hash %{public}zu", __func__, elapsedHash); + int64_t formId = udidHash | (int32_t)(elapsedHash & 0x000000007fffffffL); + APP_LOGI("%{public}s, GenerateFormId generate formId %{public}lld", __func__, formId); + return formId; +} + +/** + * @brief padding form id. + * @param formId The id of the form. + * @param udidHash udid hash + * @return new form id. + */ +int64_t FormUtil::PaddingUDIDHash(int64_t formId, int64_t udidHash) +{ + // Compatible with int form id. + if ((formId & 0xffffffff00000000L) == 0) { + return udidHash | formId; + } + + return formId; +} +/** + * @brief create udid hash. + * @param udidHash udid hash. + * @return Returns true on success, false on failure. + */ +bool FormUtil::GenerateUdidHash(int64_t &udidHash) +{ + APP_LOGI("%{public}s start, udidHash: %{public}lld", __func__, udidHash); + if (udidHash != INVALID_UDID_HASH) { + return true; + } + + // std::string deviceId = GenerateUdid(); + // if (deviceId.empty()) { + // APP_LOGE("%{public}s fail, get udid failed.", __func__); + // return false; + // } + + // u_int64_t hashId = std::hash()(deviceId); + u_int64_t hashId = 0L; + const int32_t thirtyTwo = 32; + udidHash = (hashId & 0x0000000000ffffffL) << thirtyTwo; + if(udidHash < 0) { + udidHash = 0L; + } + APP_LOGI("%{public}s, FormAdapter generate hash %{public}lld", __func__, udidHash); + + return true; +} +/** + * @brief Get current system nanosecond. + * @return Current system nanosecond. + */ +long FormUtil::GetCurrentNanosecond() +{ + struct timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = 0; + clock_gettime(CLOCK_REALTIME, &ts); + return (ts.tv_sec * SEC_TO_NANOSEC + ts.tv_nsec); +} +/** + * @brief Get current system millisecond. + * @return Current system millisecond. + */ +long FormUtil::GetCurrentMillisecond() +{ + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + return (ts.tv_sec * SEC_TO_MILLISEC + ts.tv_nsec / MILLISEC_TO_NANOSEC); +} +/** + * @brief Get millisecond from tm. + * @param tmAtTime tm time. + * @return Millisecond. + */ +long FormUtil::GetMillisecondFromTm(struct tm &tmAtTime) +{ + time_t inputTime = mktime(&tmAtTime); + if (inputTime == -1) { + APP_LOGE("%{public}s fail, mktime failed.", __func__); + return -1; + } + system_clock::time_point pointTime = system_clock::from_time_t(inputTime); + auto timeMilliseconds = chrono::duration_cast(pointTime.time_since_epoch()); + return timeMilliseconds.count(); +} + +/** +* @brief split string. + * @param in string. + * @param delim delimiter. + * @return string list. + */ +std::vector FormUtil::StringSplit(const std::string &in, const std::string &delim) +{ + std::vector vEmpty; + try { + std::regex reg { delim }; + return std::vector { + std::sregex_token_iterator(in.begin(), in.end(), reg, -1), + std::sregex_token_iterator() + }; + } catch (const std::exception& e) { + APP_LOGE("%{public}s, failed to split string.", __func__); + } + return vEmpty; +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/formmgr/test/BUILD.gn b/services/formmgr/test/BUILD.gn new file mode 100644 index 0000000000..ffbcd46101 --- /dev/null +++ b/services/formmgr/test/BUILD.gn @@ -0,0 +1,65 @@ +# Copyright (c) 2021 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("//foundation/appexecfwk/standard/appexecfwk.gni") + +config("formmgr_test_config") { + include_dirs = [ + "//utils/native/base/include", + "//utils/system/safwk/native/include", + "mock/include", + ] + + configs = [ + "${services_path}/formmgr:formmgr_config", + "${common_path}:appexecfwk_common_config", + ] +} + +public_configs = [ + ":formmgr_test_config", + "//utils/native/base:utils_config", +] + +public_deps = [ + "${common_path}:libappexecfwk_common", + "//third_party/googletest:gmock_main", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", +] + +group("unittest") { + testonly = true + + deps = [ + "unittest/fms_form_cache_mgr_test:unittest", + "unittest/fms_form_data_mgr_test:unittest", + "unittest/fms_form_db_record_test:unittest", + "unittest/fms_form_host_record_test:unittest", + "unittest/fms_form_mgr_add_form_test:unittest", + "unittest/fms_form_mgr_cast_temp_form_test:unittest", + "unittest/fms_form_mgr_delete_form_test:unittest", + "unittest/fms_form_mgr_lifecycle_update_test:unittest", + "unittest/fms_form_mgr_message_event_test:unittest", + "unittest/fms_form_mgr_notify_invisible_forms_test:unittest", + "unittest/fms_form_mgr_notify_visible_forms_test:unittest", + "unittest/fms_form_mgr_release_form_test:unittest", + "unittest/fms_form_mgr_request_form_test:unittest", + "unittest/fms_form_mgr_update_form_test:unittest", + "unittest/fms_form_provider_data_test:unittest", + "unittest/fms_form_provider_mgr_test:unittest", + "unittest/fms_form_set_next_refresh_test:unittest", + "unittest/fms_form_sys_event_receiver_test:unittest", + "unittest/fms_form_timer_mgr_test:unittest", + ] +} diff --git a/services/formmgr/test/mock/include/mock_ability_manager.h b/services/formmgr/test/mock/include/mock_ability_manager.h new file mode 100644 index 0000000000..a64fbb6ae1 --- /dev/null +++ b/services/formmgr/test/mock/include/mock_ability_manager.h @@ -0,0 +1,552 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_TEST_MOCK_MOCK_APP_MGR_HOST_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_TEST_MOCK_MOCK_APP_MGR_HOST_H + +#include +#include + +#include "ability_manager_interface.h" +#include "mock_form_provider_client.h" +#include "semaphore_ex.h" + +namespace OHOS { +namespace AppExecFwk { +class MockAbilityMgrProxy : public IRemoteProxy { +public: + explicit MockAbilityMgrProxy(const sptr &impl) : IRemoteProxy(impl) + {} + + virtual ~MockAbilityMgrProxy() = default; + virtual int UpdateConfiguration(const AAFwk::DummyConfiguration &config) override + { + return 0; + } + virtual int StartAbility(const AAFwk::Want &want, int requestCode = -1) + { + return 0; + } + virtual int StartAbility(const AAFwk::Want &want, const sptr &callerToken, int requestCode = -1) + { + return 0; + } + virtual int TerminateAbility( + const sptr &token, int resultCode, const AAFwk::Want *resultWant = nullptr) + { + return 0; + } + virtual int ConnectAbility( + const AAFwk::Want &want, const sptr &connect, const sptr &callerToken) + { + return 0; + } + virtual int DisconnectAbility(const sptr &connect) + { + return 0; + } + virtual sptr AcquireDataAbility( + const Uri &uri, bool tryBind, const sptr &callerToken) + { + return nullptr; + } + virtual int ReleaseDataAbility( + sptr dataAbilityScheduler, const sptr &callerToken) + { + return 0; + } + virtual void AddWindowInfo(const sptr &token, int32_t windowToken) + { + return; + } + virtual int AttachAbilityThread(const sptr &scheduler, const sptr &token) + { + return 0; + } + virtual int AbilityTransitionDone(const sptr &token, int state) + { + return 0; + } + virtual int GetRecentMissions( + const int32_t numMax, const int32_t flags, std::vector &recentList) override + { + return 0; + } + virtual int PowerOff() override + { + return 0; + } + virtual int PowerOn() override + { + return 0; + } + virtual int lockMission(int missionId) + { + return 0; + } + virtual int UnlockMission(int missionId) override + { + return 0; + } + virtual int SetMissionDescriptionInfo( + const sptr &token, const AAFwk::MissionDescriptionInfo &missionDescriptionInfo) override + { + return 0; + } + virtual int GetMissionLockModeState() override + { + return 0; + } + virtual sptr GetWantSender( + const AAFwk::WantSenderInfo &wantSenderInfo, const sptr &callerToken) override + { + return nullptr; + } + virtual int SendWantSender(const sptr &target, const AAFwk::SenderInfo &senderInfo) override + { + return 0; + } + virtual void CancelWantSender(const sptr &sender) override + { + return; + } + virtual int GetPendingWantUid(const sptr &target) override + { + return 0; + } + virtual int GetPendingWantUserId(const sptr &target) override + { + return 0; + } + virtual std::string GetPendingWantBundleName(const sptr &target) override + { + return ""; + } + virtual int GetPendingWantCode(const sptr &target) override + { + return 0; + } + virtual int GetPendingWantType(const sptr &target) override + { + return 0; + } + virtual void RegisterCancelListener( + const sptr &sender, const sptr &receiver) override + { + return; + } + virtual void UnregisterCancelListener( + const sptr &sender, const sptr &receiver) override + { + return; + } + virtual int GetPendingRequestWant(const sptr &target, std::shared_ptr &want) override + { + return 0; + } + virtual int ScheduleConnectAbilityDone(const sptr &token, const sptr &remoteObject) + { + return 0; + } + virtual int ScheduleDisconnectAbilityDone(const sptr &token) + { + return 0; + } + virtual int ScheduleCommandAbilityDone(const sptr &token) + { + return 0; + } + virtual void DumpState(const std::string &args, std::vector &state) + { + return; + } + virtual int TerminateAbilityResult(const sptr &token, int startId) + { + return 0; + } + virtual int StopServiceAbility(const AAFwk::Want &want) + { + return 0; + } + virtual int GetAllStackInfo(AAFwk::StackInfo &stackInfo) + { + return 0; + } + virtual int GetMissionSnapshot(const int32_t missionId, AAFwk::MissionSnapshotInfo &snapshot) + { + return 0; + } + virtual int MoveMissionToTop(int32_t missionId) + { + return 0; + } + /** + * Requires that tasks associated with a given capability token be moved to the background + * + * @param token ability token + * @param nonFirst If nonfirst is false and not the lowest ability of the mission, you cannot move mission to end + * @return Returns ERR_OK on success, others on failure. + */ + virtual int MoveMissionToEnd(const sptr &token, const bool nonFirst) + { + return 0; + } + virtual int RemoveMission(int id) + { + return 0; + } + virtual int RemoveStack(int id) + { + return 0; + } + virtual int KillProcess(const std::string &bundleName) + { + return 0; + } + virtual int UninstallApp(const std::string &bundleName) + { + return 0; + } + virtual int TerminateAbilityByRecordId(const int64_t recordId = -1) + { + return 0; + } + virtual int TerminateAbilityByCaller(const sptr &callerToken, int requestCode) + { + return 0; + } + /** Checks whether this ability is the first ability in a mission. + * @param lostToken, the token of ability + * @return Returns true is first in Mission. + */ + virtual bool IsFirstInMission(const sptr &token) + { + return 0; + } + /** + * Checks whether a specified permission has been granted to the process identified by pid and uid + * + * @param permission Indicates the permission to check. + * @param pid Indicates the ID of the process to check. + * @param uid Indicates the UID of the process to check. + * @param message Describe success or failure + * + * @return Returns ERR_OK on success, others on failure. + */ + virtual int CompelVerifyPermission(const std::string &permission, int pid, int uid, std::string &message) + { + return 0; + } +}; + +class MockAbilityMgrStub : public IRemoteStub { +public: + using Uri = OHOS::Uri; + MockAbilityMgrStub() = default; + virtual ~MockAbilityMgrStub() = default; + + virtual int OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override + { + return 0; + } +}; +class MockAbilityMgrService : public MockAbilityMgrStub { +public: + void Wait() + { + sem_.Wait(); + } + + int Post() + { + sem_.Post(); + return 0; + } + + void PostVoid() + { + sem_.Post(); + } + + virtual int UpdateConfiguration(const AAFwk::DummyConfiguration &config) override + { + return 0; + } + virtual int StartAbility(const AAFwk::Want &want, int requestCode = -1) + { + return 0; + } + virtual int StartAbility(const AAFwk::Want &want, const sptr &callerToken, int requestCode = -1) + { + return 0; + } + virtual int TerminateAbility( + const sptr &token, int resultCode, const AAFwk::Want *resultWant = nullptr) + { + return 0; + } + virtual int ConnectAbility( + const AAFwk::Want &want, const sptr &connect, const sptr &callerToken) + { + connect->OnAbilityConnectDone(want.GetElement(), new (std::nothrow) MockFormProviderClient(), 0); + return 0; + } + virtual int DisconnectAbility(const sptr &connect) + { + return 0; + } + virtual sptr AcquireDataAbility( + const Uri &uri, bool tryBind, const sptr &callerToken) + { + return nullptr; + } + virtual int ReleaseDataAbility( + sptr dataAbilityScheduler, const sptr &callerToken) + { + return 0; + } + virtual void AddWindowInfo(const sptr &token, int32_t windowToken) + { + return; + } + virtual int AttachAbilityThread(const sptr &scheduler, const sptr &token) + { + return 0; + } + virtual int AbilityTransitionDone(const sptr &token, int state) + { + return 0; + } + virtual int ScheduleConnectAbilityDone(const sptr &token, const sptr &remoteObject) + { + return 0; + } + virtual int ScheduleDisconnectAbilityDone(const sptr &token) + { + return 0; + } + virtual int ScheduleCommandAbilityDone(const sptr &token) + { + return 0; + } + virtual void DumpState(const std::string &args, std::vector &state) + { + return; + } + virtual int TerminateAbilityResult(const sptr &token, int startId) + { + return 0; + } + virtual int StopServiceAbility(const AAFwk::Want &want) + { + return 0; + } + virtual int GetAllStackInfo(AAFwk::StackInfo &stackInfo) + { + return 0; + } + // virtual int GetRecentMissions( + // const int32_t numMax, const int32_t flags, std::vector &recentList) + // { + // return 0; + // } + virtual int GetRecentMissions( + const int32_t numMax, const int32_t flags, std::vector &recentList) override + { + return 0; + } + virtual int PowerOff() override + { + return 0; + } + virtual int PowerOn() override + { + return 0; + } + virtual int LockMission(int missionId) override + { + return 0; + } + virtual int UnlockMission(int missionId) override + { + return 0; + } + virtual int SetMissionDescriptionInfo( + const sptr &token, const AAFwk::MissionDescriptionInfo &missionDescriptionInfo) override + { + return 0; + } + virtual int GetMissionLockModeState() override + { + return 0; + } + virtual sptr GetWantSender( + const AAFwk::WantSenderInfo &wantSenderInfo, const sptr &callerToken) override + { + return nullptr; + } + virtual int SendWantSender(const sptr &target, const AAFwk::SenderInfo &senderInfo) override + { + return 0; + } + virtual void CancelWantSender(const sptr &sender) override + { + return; + } + virtual int GetPendingWantUid(const sptr &target) override + { + return 0; + } + virtual int GetPendingWantUserId(const sptr &target) override + { + return 0; + } + virtual std::string GetPendingWantBundleName(const sptr &target) override + { + return ""; + } + virtual int GetPendingWantCode(const sptr &target) override + { + return 0; + } + virtual int GetPendingWantType(const sptr &target) override + { + return 0; + } + virtual void RegisterCancelListener( + const sptr &sender, const sptr &receiver) override + { + return; + } + virtual void UnregisterCancelListener( + const sptr &sender, const sptr &receiver) override + { + return; + } + virtual int GetPendingRequestWant(const sptr &target, std::shared_ptr &want) override + { + return 0; + } + virtual int GetMissionSnapshot(const int32_t missionId, AAFwk::MissionSnapshotInfo &snapshot) + { + return 0; + } + virtual int MoveMissionToTop(int32_t missionId) + { + return 0; + } + /** + * Requires that tasks associated with a given capability token be moved to the background + * + * @param token ability token + * @param nonFirst If nonfirst is false and not the lowest ability of the mission, you cannot move mission to end + * @return Returns ERR_OK on success, others on failure. + */ + virtual int MoveMissionToEnd(const sptr &token, const bool nonFirst) + { + return 0; + } + virtual int RemoveMission(int id) + { + return 0; + } + virtual int RemoveStack(int id) + { + return 0; + } + virtual int KillProcess(const std::string &bundleName) + { + return 0; + } + virtual int UninstallApp(const std::string &bundleName) + { + return 0; + } + virtual int TerminateAbilityByRecordId(const int64_t recordId = -1) + { + return 0; + } + virtual int TerminateAbilityByCaller(const sptr &callerToken, int requestCode) + { + return 0; + } + int MoveMissionToFloatingStack(const MissionOption &missionOption) + { + return 0; + } + int MoveMissionToSplitScreenStack(const MissionOption &missionOption) + { + return 0; + } + int MinimizeMultiWindow(int missionId) + { + return 0; + } + int MaximizeMultiWindow(int missionId) + { + return 0; + } + int GetFloatingMissions(std::vector &list) + { + return 0; + } + int CloseMultiWindow(int missionId) + { + return 0; + } + int SetMissionStackSetting(const StackSetting &stackSetting) + { + return 0; + } + int StartAbility(const Want &want, const AbilityStartSetting &abilityStartSetting, + const sptr &callerToken, int requestCode = 0) + { + return 0; + } + int ChangeFocusAbility(const sptr &lostFocusToken, const sptr &getFocusToken) + { + return 0; + } + + /** Checks whether this ability is the first ability in a mission. + * @param lostToken, the token of ability + * @return Returns true is first in Mission. + */ + virtual bool IsFirstInMission(const sptr &token) + { + return 0; + } + /** + * Checks whether a specified permission has been granted to the process identified by pid and uid + * + * @param permission Indicates the permission to check. + * @param pid Indicates the ID of the process to check. + * @param uid Indicates the UID of the process to check. + * @param message Describe success or failure + * + * @return Returns ERR_OK on success, others on failure. + */ + virtual int CompelVerifyPermission(const std::string &permission, int pid, int uid, std::string &message) + { + return 0; + } + +private: + Semaphore sem_; +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_TEST_MOCK_MOCK_APP_MGR_HOST_H \ No newline at end of file diff --git a/services/formmgr/test/mock/include/mock_bundle_manager.h b/services/formmgr/test/mock/include/mock_bundle_manager.h new file mode 100644 index 0000000000..5a3ec17f10 --- /dev/null +++ b/services/formmgr/test/mock/include/mock_bundle_manager.h @@ -0,0 +1,538 @@ +/* + * Copyright (c) 2021 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 OHOS_AAFWK_ABILITY_MOCK_BUNDLE_MANAGER_H +#define OHOS_AAFWK_ABILITY_MOCK_BUNDLE_MANAGER_H + +#include + +#include "ability_info.h" +#include "application_info.h" +#include "bundle_mgr_interface.h" +#include "gmock/gmock.h" +#include "iremote_proxy.h" +#include "iremote_stub.h" +#include "ohos/aafwk/content/want.h" + +namespace OHOS { +namespace AppExecFwk { +class BundleMgrProxy : public IRemoteProxy { +public: + explicit BundleMgrProxy(const sptr &impl) : IRemoteProxy(impl) + {} + virtual ~BundleMgrProxy() + {} + MOCK_METHOD3( + CanRequestPermission, bool(const std::string &bundleName, const std::string &permissionName, const int userId)); + MOCK_METHOD3(RequestPermissionFromUser, + bool(const std::string &bundleName, const std::string &permission, const int userId)); + MOCK_METHOD2(GetNameForUid, bool(const int uid, std::string &name)); + MOCK_METHOD2(GetBundlesForUid, bool(const int uid, std::vector &)); + MOCK_METHOD2(SetAbilityEnabled, bool(const AbilityInfo &, bool)); + MOCK_METHOD1(IsAbilityEnabled, bool(const AbilityInfo &)); + MOCK_METHOD2(GetAbilityIcon, std::string(const std::string &bundleName, const std::string &className)); + MOCK_METHOD1(RegisterAllPermissionsChanged, bool(const sptr &callback)); + MOCK_METHOD2(RegisterPermissionsChanged, + bool(const std::vector &uids, const sptr &callback)); + MOCK_METHOD1(UnregisterPermissionsChanged, bool(const sptr &callback)); + bool QueryAbilityInfo(const AAFwk::Want &want, AbilityInfo &abilityInfo) override + { + return true; + } + bool QueryAbilityInfoByUri(const std::string &uri, AbilityInfo &abilityInfo) override + { + return true; + } + + std::string GetAppType(const std::string &bundleName) override + { + return "system"; + } + + virtual bool GetApplicationInfo(const std::string &appName, const ApplicationFlag flag, const int userId, + ApplicationInfo &appInfo) override + { + return true; + } + virtual bool GetApplicationInfos( + const ApplicationFlag flag, const int userId, std::vector &appInfos) override + { + return true; + } + + virtual bool GetBundleInfos(const BundleFlag flag, std::vector &bundleInfos) override + { + return true; + } + virtual int GetUidByBundleName(const std::string &bundleName, const int userId) override + { + if (bundleName.compare("com.form.host.app600") == 0) { + return 600; + } + return 0; + } + virtual std::string GetAppIdByBundleName(const std::string &bundleName, const int userId) override + { + return ""; + } + virtual bool GetBundleNameForUid(const int uid, std::string &bundleName) override + { + bundleName = "com.form.provider.service"; + return true; + } + virtual bool GetBundleGids(const std::string &bundleName, std::vector &gids) override + { + return true; + } + virtual bool GetBundleInfosByMetaData(const std::string &metaData, std::vector &bundleInfos) override + { + return true; + } + virtual bool QueryKeepAliveBundleInfos(std::vector &bundleInfos) override + { + return true; + } + virtual std::string GetAbilityLabel(const std::string &bundleName, const std::string &className) override + { + return ""; + } + + virtual bool GetBundleArchiveInfo( + const std::string &hapFilePath, const BundleFlag flag, BundleInfo &bundleInfo) override + { + return true; + } + + virtual bool GetLaunchWantForBundle(const std::string &bundleName, Want &want) override + { + return true; + } + + virtual int CheckPublicKeys(const std::string &firstBundleName, const std::string &secondBundleName) override + { + return 0; + } + + virtual int CheckPermission(const std::string &bundleName, const std::string &permission) override + { + return 0; + } + virtual bool GetPermissionDef(const std::string &permissionName, PermissionDef &permissionDef) override + { + return true; + } + virtual bool GetAllPermissionGroupDefs(std::vector &permissionDefs) override + { + return true; + } + virtual bool GetAppsGrantedPermissions( + const std::vector &permissions, std::vector &appNames) override + { + return true; + } + virtual bool HasSystemCapability(const std::string &capName) override + { + return true; + } + virtual bool GetSystemAvailableCapabilities(std::vector &systemCaps) override + { + return true; + } + virtual bool IsSafeMode() override + { + return true; + } + // clears cache data of a specified application. + virtual bool CleanBundleCacheFiles( + const std::string &bundleName, const sptr &cleanCacheCallback) override + { + return true; + } + virtual bool CleanBundleDataFiles(const std::string &bundleName) override + { + return true; + } + virtual bool RegisterBundleStatusCallback(const sptr &bundleStatusCallback) override + { + return true; + } + virtual bool ClearBundleStatusCallback(const sptr &bundleStatusCallback) override + { + return true; + } + // unregister callback of all application + virtual bool UnregisterBundleStatusCallback() override + { + return true; + } + virtual bool DumpInfos(const DumpFlag flag, const std::string &bundleName, std::string &result) override + { + return true; + } + virtual sptr GetBundleInstaller() override + { + return nullptr; + } + + /** + * @brief Obtains information about the shortcuts of the application. + * @param bundleName Indicates the name of the bundle to shortcut. + * @param form Indicates the callback a list to shortcutinfo. + * @return Returns true if shortcutinfo get success + */ + virtual bool GetShortcutInfos(const std::string &bundleName,std::vector &shortcut) override{ + return true; + } + // /** + // * @brief Starts a shortcut based on the given shortcut ID and bundle name. + // * @param bundleName BundleName Indicates the bundle name of the application to which the shortcut belongs. + // * @param shortcutId Starts a shortcut based on the given shortcut ID and bundle name. + // * @return Returns true if StartShortcut get success + // */ + // virtual bool StartShortcut(const std::string &shortcutId, const std::string &bundleName) override{ + // return true; + // } + /** + * @brief Disables specified home-screen shortcuts that are no longer used. + * @param shortcutIds Indicates the list of shortcut IDs to be disabled. + * @return Returns true if disableHomeShortcuts get success + */ + // virtual bool DisableHomeShortcuts(std::vector &shortcutIds) override{ + // return true; + // } + // /** + // * @brief Enables specified home-screen shortcuts. + // * @param shortcutIds Indicates the list of shortcut IDs to be enabled. + // * @return Returns true if enableHomeShortcuts? get success + // */ + // virtual bool EnableHomeShortcuts(std::vector &shortcutIds) override{ + // return true; + // } + // /** + // * @brief Checks whether a shortcut can be added to the home screen where the application is located. + // * @return Returns true if a shortcut can be added to the home screen; returns false otherwise. + // */ + // virtual bool IsHomeShortcutSupportes() override{ + // return true; + // } + // /** + // * @brief Adds a home-screen shortcut that will be fixed on the home screen. + // * @param shortcutInfo Indicates the ShortcutInfo object containing information about the home-screen + // * shortcut to add. The id, label, and intent attributes of this parameter must be specified. + // * @return Returns true if the shortcut is successfully added; returns false otherwise. + // */ + // virtual bool AddHomeShortcut(ShortcutInfo &shortcutInfo) override{ + // return true; + // } + // /** + // * @brief Updates information about specified home-screen shortcuts that have been added. + // * @param shortcutInfos Updates information about specified home-screen shortcuts that have been added. + // * @return Returns true if the operation is successful; returns false otherwise. + // */ + // virtual bool UpdateShortcuts(std::vector &shortcutInfos) override{ + // return true; + // } + // /** + // * @brief Checks whether a specified shortcut is available. + // * @param shortcutId Indicates the ID of the shortcut to check. + // * @param flag Indicates the type of the shortcut to check. Currently, only the home-screen shortcut + // * IBundleManager#QUERY_SHORTCUT_HOME is available. + // * @return Returns IBundleManager#SHORTCUT_EXISTENCE_EXISTS if the specified shortcut is available; returns + // * IBundleManager#SHORTCUT_EXISTENCE_NOT_EXISTS if it is not available; + // * returns IBundleManager.SHORTCUT_EXISTENCE_UNKNOW if an error occurs. + // */ + // virtual int IsShortcutExist(const std::string &shortcutId, const int &flag) override{ + // return 0; + // } + /** + * @brief Obtain the HAP module info of a specific ability. + * @param abilityInfo Indicates the ability. + * @param hapModuleInfo Indicates the obtained HapModuleInfo object. + * @return Returns true if the HapModuleInfo is successfully obtained; returns false otherwise. + */ + virtual bool GetHapModuleInfo(const AbilityInfo &abilityInfo, HapModuleInfo &hapModuleInfo) override + { + return true; + } + + virtual bool CheckIsSystemAppByUid(const int uid) override + { + if (uid == 600) { + return false; + } + return true; + } + virtual bool IsApplicationEnabled(const std::string &bundleName)override + { + return true; + } + virtual bool SetApplicationEnabled(const std::string &bundleName, bool isEnable) override + { + return true; + } + + virtual bool GetBundleInfo(const std::string &bundleName, const BundleFlag flag, BundleInfo &bundleInfo) override; + virtual bool GetAllFormsInfo(std::vector &formInfo) override; + virtual bool GetFormsInfoByApp(const std::string &bundleName, std::vector &formInfo) override; + virtual bool GetFormsInfoByModule(const std::string &bundleName, const std::string &moduleName, + std::vector &formInfo) override; +}; + +class BundleMgrStub : public IRemoteStub { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"IBundleMgr"); + virtual int OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; +}; + +class BundleMgrService : public BundleMgrStub { +public: + MOCK_METHOD2(GetAppIdByBundleName, std::string(const std::string &bundleName, const int userId)); + MOCK_METHOD2(CheckPermission, int(const std::string &bundleName, const std::string &permission)); + MOCK_METHOD1(CleanBundleDataFiles, bool(const std::string &bundleName)); + MOCK_METHOD3( + CanRequestPermission, bool(const std::string &bundleName, const std::string &permissionName, const int userId)); + MOCK_METHOD3(RequestPermissionFromUser, + bool(const std::string &bundleName, const std::string &permission, const int userId)); + MOCK_METHOD2(GetNameForUid, bool(const int uid, std::string &name)); + MOCK_METHOD2(GetBundlesForUid, bool(const int uid, std::vector &)); + MOCK_METHOD2(SetAbilityEnabled, bool(const AbilityInfo &, bool)); + MOCK_METHOD1(IsAbilityEnabled, bool(const AbilityInfo &)); + MOCK_METHOD2(GetAbilityIcon, std::string(const std::string &bundleName, const std::string &className)); + MOCK_METHOD1(RegisterAllPermissionsChanged, bool(const sptr &callback)); + MOCK_METHOD2(RegisterPermissionsChanged, + bool(const std::vector &uids, const sptr &callback)); + MOCK_METHOD1(UnregisterPermissionsChanged, bool(const sptr &callback)); + bool QueryAbilityInfo(const AAFwk::Want &want, AbilityInfo &abilityInfo) override; + bool QueryAbilityInfoByUri(const std::string &uri, AbilityInfo &abilityInfo) override; + + std::string GetAppType(const std::string &bundleName) override; + virtual int GetUidByBundleName(const std::string &bundleName, const int userId) override; + + virtual bool GetApplicationInfo( + const std::string &appName, const ApplicationFlag flag, const int userId, ApplicationInfo &appInfo) override; + virtual bool GetApplicationInfos( + const ApplicationFlag flag, const int userId, std::vector &appInfos) override + { + return true; + }; + virtual bool GetBundleInfo(const std::string &bundleName, const BundleFlag flag, BundleInfo &bundleInfo) override; + virtual bool GetBundleInfos(const BundleFlag flag, std::vector &bundleInfos) override + { + return true; + }; + virtual bool GetBundleNameForUid(const int uid, std::string &bundleName) override + { + bundleName = "com.form.provider.service"; + return true; + }; + virtual bool GetBundleGids(const std::string &bundleName, std::vector &gids) override; + virtual bool GetBundleInfosByMetaData(const std::string &metaData, std::vector &bundleInfos) override + { + return true; + }; + virtual bool QueryKeepAliveBundleInfos(std::vector &bundleInfos) override + { + return true; + }; + virtual std::string GetAbilityLabel(const std::string &bundleName, const std::string &className) override + { + return ""; + }; + // obtains information about an application bundle contained in a ohos Ability Package (HAP). + virtual bool GetBundleArchiveInfo( + const std::string &hapFilePath, const BundleFlag flag, BundleInfo &bundleInfo) override + { + return true; + }; + virtual bool GetHapModuleInfo(const AbilityInfo &abilityInfo, HapModuleInfo &hapModuleInfo) override + { + return true; + } + // obtains the Want for starting the main ability of an application based on the given bundle name. + virtual bool GetLaunchWantForBundle(const std::string &bundleName, Want &want) override + { + return true; + }; + // checks whether the publickeys of two bundles are the same. + virtual int CheckPublicKeys(const std::string &firstBundleName, const std::string &secondBundleName) override + { + return 0; + }; + // checks whether a specified bundle has been granted a specific permission. + virtual bool GetPermissionDef(const std::string &permissionName, PermissionDef &permissionDef) override + { + return true; + }; + virtual bool GetAllPermissionGroupDefs(std::vector &permissionDefs) override + { + return true; + }; + virtual bool GetAppsGrantedPermissions( + const std::vector &permissions, std::vector &appNames) override + { + return true; + }; + virtual bool HasSystemCapability(const std::string &capName) override + { + return true; + }; + virtual bool GetSystemAvailableCapabilities(std::vector &systemCaps) override + { + return true; + }; + virtual bool IsSafeMode() override + { + return true; + }; + // clears cache data of a specified application. + virtual bool CleanBundleCacheFiles( + const std::string &bundleName, const sptr &cleanCacheCallback) override + { + return true; + }; + + virtual bool RegisterBundleStatusCallback(const sptr &bundleStatusCallback) override + { + return true; + }; + virtual bool ClearBundleStatusCallback(const sptr &bundleStatusCallback) override + { + return true; + }; + // unregister callback of all application + virtual bool UnregisterBundleStatusCallback() override + { + return true; + }; + virtual bool DumpInfos(const DumpFlag flag, const std::string &bundleName, std::string &result) override + { + return true; + }; + virtual sptr GetBundleInstaller() override + { + return nullptr; + }; + virtual bool IsApplicationEnabled(const std::string &bundleName) override + { + return true; + }; + virtual bool CheckIsSystemAppByUid(const int uid) override + { + if (uid == 600) { + return false; + } + + return true; + }; + virtual bool SetApplicationEnabled(const std::string &bundleName, bool isEnable) override + { + return true; + }; + + /** + * @brief Obtains information about the shortcuts of the application. + * @param bundleName Indicates the name of the bundle to shortcut. + * @param form Indicates the callback a list to shortcutinfo. + * @return Returns true if shortcutinfo get success + */ + virtual bool GetShortcutInfos(const std::string &bundleName,std::vector &shortcut) override{ + return true; + } + // /** + // * @brief Starts a shortcut based on the given shortcut ID and bundle name. + // * @param bundleName BundleName Indicates the bundle name of the application to which the shortcut belongs. + // * @param shortcutId Starts a shortcut based on the given shortcut ID and bundle name. + // * @return Returns true if StartShortcut get success + // */ + // virtual bool StartShortcut(const std::string &shortcutId, const std::string &bundleName) override{ + // return true; + // } + // /** + // * @brief Disables specified home-screen shortcuts that are no longer used. + // * @param shortcutIds Indicates the list of shortcut IDs to be disabled. + // * @return Returns true if disableHomeShortcuts get success + // */ + // virtual bool DisableHomeShortcuts(std::vector &shortcutIds) override{ + // return true; + // } + // /** + // * @brief Enables specified home-screen shortcuts. + // * @param shortcutIds Indicates the list of shortcut IDs to be enabled. + // * @return Returns true if enableHomeShortcuts? get success + // */ + // virtual bool EnableHomeShortcuts(std::vector &shortcutIds) override{ + // return true; + // } + /** + * @brief Checks whether a shortcut can be added to the home screen where the application is located. + * @return Returns true if a shortcut can be added to the home screen; returns false otherwise. + */ + // virtual bool IsHomeShortcutSupportes() override{ + // return true; + // } + // /** + // * @brief Adds a home-screen shortcut that will be fixed on the home screen. + // * @param shortcutInfo Indicates the ShortcutInfo object containing information about the home-screen shortcut + // * to add. The id, label, and intent attributes of this parameter must be specified. + // * @return Returns true if the shortcut is successfully added; returns false otherwise. + // */ + // virtual bool AddHomeShortcut(ShortcutInfo &shortcutInfo) override{ + // return true; + // } + // /** + // * @brief Updates information about specified home-screen shortcuts that have been added. + // * @param shortcutInfos Updates information about specified home-screen shortcuts that have been added. + // * @return Returns true if the operation is successful; returns false otherwise. + // */ + // virtual bool UpdateShortcuts(std::vector &shortcutInfos) override{ + // return true; + // } + // /** + // * @brief Checks whether a specified shortcut is available. + // * @param shortcutId Indicates the ID of the shortcut to check. + // * @param flag Indicates the type of the shortcut to check. Currently, only the home-screen shortcut + // * IBundleManager#QUERY_SHORTCUT_HOME is available. + // * @return Returns IBundleManager#SHORTCUT_EXISTENCE_EXISTS if the specified shortcut is available; returns + // * IBundleManager#SHORTCUT_EXISTENCE_NOT_EXISTS if it is not available; returns + // * IBundleManager.SHORTCUT_EXISTENCE_UNKNOW if an error occurs. + // */ + // virtual int IsShortcutExist(const std::string &shortcutId, const int &flag) override{ + // return 0; + // } + + virtual bool GetAllFormsInfo(std::vector &formInfo) override; + virtual bool GetFormsInfoByApp(const std::string &bundleName, std::vector &formInfo) override; + virtual bool GetFormsInfoByModule(const std::string &bundleName, const std::string &moduleName, + std::vector &formInfo) override; + virtual bool QueryAbilityInfos(const Want &want, std::vector &abilityInfos) override + { + return true; + }; + virtual bool GetModuleUsageRecords( + const int32_t number, std::vector &moduleUsageRecords) override + { + return true; + } + virtual bool NotifyActivityLifeStatus( + const std::string &bundleName, const std::string &abilityName, const int64_t launchTime) override + { + return true; + } +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // OHOS_AAFWK_ABILITY_MOCK_BUNDLE_MANAGER_H diff --git a/services/formmgr/test/mock/include/mock_form_death_callback.h b/services/formmgr/test/mock/include/mock_form_death_callback.h new file mode 100644 index 0000000000..2563698580 --- /dev/null +++ b/services/formmgr/test/mock/include/mock_form_death_callback.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_MOCK_FORM_DEATH_CALLBACK_H +#define FOUNDATION_APPEXECFWK_SERVICES_MOCK_FORM_DEATH_CALLBACK_H + +#include +#include +#include +#include +#include +#include + +#include "app_log_wrapper.h" +#include "event_handler.h" +#include "form_constants.h" +#include "form_death_callback.h" +#include "form_mgr_stub.h" +#include "form_js_info.h" +#include "form_provider_data.h" +#include "ipc_types.h" +#include "iremote_object.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @class MockFormDeathCallback. + * The MockFormDeathCallback for form mgr test. + */ +class MockFormDeathCallback : public FormDeathCallback { +public: + MockFormDeathCallback() = default; + virtual ~MockFormDeathCallback() = default; + + void OnDeathReceived() + { + APP_LOGI("%{public}s called.", __func__); + } + + void OnReconnectFailed() + { + APP_LOGI("%{public}s called.", __func__); + } +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_MOCK_FORM_DEATH_CALLBACK_H diff --git a/services/formmgr/test/mock/include/mock_form_host_client.h b/services/formmgr/test/mock/include/mock_form_host_client.h new file mode 100644 index 0000000000..7d7f08d5df --- /dev/null +++ b/services/formmgr/test/mock/include/mock_form_host_client.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_OHOS_FORM_HOST_CLIENT_H +#define FOUNDATION_APPEXECFWK_OHOS_FORM_HOST_CLIENT_H + +#include +// #include "ability.h" +#include "form_host_stub.h" +#include "iremote_object.h" +#include "iremote_stub.h" +#include "semaphore_ex.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @class MockFormHostClient + * MockFormHostClient. + */ +class MockFormHostClient : public FormHostStub { +public: + MockFormHostClient() = default; + virtual ~MockFormHostClient() = default; + + void Wait() + { + sem_.Wait(); + } + + int Post() + { + sem_.Post(); + return 0; + } + + void PostVoid() + { + sem_.Post(); + } + + // void AddForm(const Ability& slice, int64_t formId); + + // void RemoveForm(const Ability& slice, int64_t formId); + + // bool ContainsForm(int64_t formId); + /** + * Request to give back a Form. + * + * @param formId, The Id of the forms to create. + * @param formInfo, Form info. + * @return none. + */ + virtual void OnAcquired(const FormJsInfo &formInfo) override; + + /** + * Form is updated. + * + * @param formId, The Id of the form to update. + * @param formInfo, Form info. + * @return none. + */ + virtual void OnUpdate(const FormJsInfo &formInfo) override; + + /** + * Form provider is uninstalled. + * + * @param formIds, The Id list of the forms. + * @return none. + */ + virtual void OnUninstall(const std::vector &formIds) override; + +private: + +private: + Semaphore sem_; + DISALLOW_COPY_AND_MOVE(MockFormHostClient); +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_OHOS_FORM_HOST_CLIENT_H diff --git a/services/formmgr/test/mock/include/mock_form_provider_client.h b/services/formmgr/test/mock/include/mock_form_provider_client.h new file mode 100644 index 0000000000..8f8a6857d3 --- /dev/null +++ b/services/formmgr/test/mock/include/mock_form_provider_client.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_OHOS_FORM_PROVIDER_CLIENT_H +#define FOUNDATION_APPEXECFWK_OHOS_FORM_PROVIDER_CLIENT_H + +#include +#include +#include +#include "form_provider_stub.h" + +#include "want.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * @class FormProviderStub + * FormProviderStub. + */ +class MockFormProviderClient : public FormProviderStub { +public: + MockFormProviderClient() = default; + virtual ~MockFormProviderClient() = default; + +private: + /** + * Acquire to give back an ProviderFormInfo. This is sync API. + * + * @param want, Indicates the {@link Want} structure containing form info. + * @param callerToken, Caller ability token. + * @return none. + */ + virtual int AcquireProviderFormInfo(const int64_t formId, const Want &want, + const sptr &callerToken) override; + + /** + * Notify provider when the form was deleted. + * + * @param formId, The Id of the form. + * @param callerToken, Caller ability token. + * @return none. + */ + virtual int NotifyFormDelete(const int64_t formId, const Want &want, + const sptr &callerToken) override; + + /** + * Notify provider when the form was deleted. + * + * @param formIds, The id list of forms. + * @param want Indicates the structure containing form info. + * @param callerToken, Caller ability token. + * @return none. + */ + virtual int NotifyFormsDelete(const std::vector &formIds, const Want &want, + const sptr &callerToken) override; + + /** + * @brief Notify provider when the form need update. + * @param formId The Id of the form. + * @param want Indicates the structure containing form info. + * @param callerToken Caller ability token. + */ + virtual int NotifyFormUpdate(const int64_t formId, const Want &want, + const sptr &callerToken) override; + + /** + * @brief Event notify when change the form visible. + * + * @param formEvents The vector of form ids. + * @param formVisibleType The form visible type, including FORM_VISIBLE and FORM_INVISIBLE. + * @param want Indicates the structure containing form info. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int EventNotify(const std::vector &formIds, const int32_t formVisibleType, + const Want &want, const sptr &callerToken) override; + + /** + * Notify provider when the temp form was cast to normal form. + * + * @param formId, The Id of the form to update. + * @param callerToken, Caller ability token. + * @return none. + */ + virtual int NotifyFormCastTempForm(const int64_t formId, const Want &want, + const sptr &callerToken) override; + /** + * @brief Fire message event to form provider. + * @param formId The Id of the from. + * @param message Event message. + * @param want The want of the request. + * @param callerToken Form provider proxy object. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int FireFormEvent(const int64_t formId, const std::string &message, const Want &want, + const sptr &callerToken) override; +private: + DISALLOW_COPY_AND_MOVE(MockFormProviderClient); +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_OHOS_FORM_PROVIDER_CLIENT_H diff --git a/services/formmgr/test/mock/include/mock_form_token.h b/services/formmgr/test/mock/include/mock_form_token.h new file mode 100644 index 0000000000..ca655e5f44 --- /dev/null +++ b/services/formmgr/test/mock/include/mock_form_token.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_TEST_MOCK_INCLUDE_MOCK_FORM_TOKEN_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_TEST_MOCK_INCLUDE_MOCK_FORM_TOKEN_H + +#include "iremote_broker.h" +#include "iremote_object.h" +#include "iremote_proxy.h" +#include "iremote_stub.h" +#include "nocopyable.h" + +namespace OHOS { +namespace AppExecFwk { +class IFormToken : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.appexecfwk.FormToken"); +}; + +class MockFormToken : public IRemoteStub { +public: + MockFormToken() = default; + virtual ~MockFormToken() = default; + + virtual int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) + { + return 0; + } + +private: + DISALLOW_COPY_AND_MOVE(MockFormToken); +}; + +class FormTokenProxy : public IRemoteProxy { +public: + explicit FormTokenProxy(const sptr &impl) : IRemoteProxy(impl) + {} + + virtual ~FormTokenProxy() = default; + +private: + DISALLOW_COPY_AND_MOVE(FormTokenProxy); +}; + +DECLARE_INTERFACE_DESCRIPTOR(u"IFormToken"); +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_TEST_MOCK_INCLUDE_MOCK_FORM_TOKEN_H diff --git a/services/formmgr/test/mock/include/mock_form_user_manager.h b/services/formmgr/test/mock/include/mock_form_user_manager.h new file mode 100644 index 0000000000..f60c1ad865 --- /dev/null +++ b/services/formmgr/test/mock/include/mock_form_user_manager.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_TEST_MOCK_INCLUDE_MOCK_FORM_USER_MANAGER_H +#define FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_TEST_MOCK_INCLUDE_MOCK_FORM_USER_MANAGER_H + + +#include + +#include "form_info.h" +#include "iremote_proxy.h" +#include "iremote_stub.h" +#include "form_mgr_interface.h" + +namespace OHOS { +namespace AppExecFwk { +class IFormUserMgr : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.appexecfwk.FormUserMgr"); + /** + * Update form with formId, send formId to form manager service. + * + * @param formId, The Id of the form to update. + * @param bundleName, Provider ability bundleName. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int UpdateForm(const int64_t formId, const FmsFormInfo &formInfo) = 0; +}; + +class FormUserMgrProxy : public IRemoteProxy { +public: + explicit FormUserMgrProxy(const sptr &impl) : IRemoteProxy(impl) + {} + virtual ~FormUserMgrProxy() + {} + /** + * Update form with formId, send formId to form manager service. + * + * @param formId, The Id of the form to update. + * @param bundleName, Provider ability bundleName. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int UpdateForm(const int64_t formId, const FmsFormInfo &formInfo) override + { + return ERR_OK; + } +}; + +class FormUserMgrStub : public IRemoteStub { +public: + FormUserMgrStub(); + virtual ~FormUserMgrStub(); + virtual int OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; +private: + int32_t HandleUpdateForm(MessageParcel &data, MessageParcel &reply); +}; + +class FormUserMgrService : public FormUserMgrStub { +public: + void OnStart() override; + void OnStop() override; + + /** + * Update form with formId, send formId to form manager service. + * + * @param formId, The Id of the form to update. + * @param bundleName, Provider ability bundleName. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int UpdateForm(const int64_t formId, const FmsFormInfo &formInfo) override + { + return ERR_OK; + } +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_FORMMGR_TEST_MOCK_INCLUDE_MOCK_FORM_USER_MANAGER_H diff --git a/services/formmgr/test/mock/src/mock_bundle_manager.cpp b/services/formmgr/test/mock/src/mock_bundle_manager.cpp new file mode 100644 index 0000000000..4905e22612 --- /dev/null +++ b/services/formmgr/test/mock/src/mock_bundle_manager.cpp @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2021 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 "mock_bundle_manager.h" + +#include "ability_info.h" +#include "application_info.h" +#include "form_info.h" + +namespace OHOS { +namespace AppExecFwk { +const std::string FORM_PROVIDER_BUNDLE_NAME = "com.form.provider.service"; +const std::string PARAM_PROVIDER_PACKAGE_NAME = "com.form.provider.app.test.abiliy"; +const std::string PARAM_PROVIDER_MODULE_NAME = "com.form.provider.app.test.abiliy"; +const std::string FORM_PROVIDER_ABILITY_NAME = "com.form.provider.app.test.abiliy"; +const std::string FORM_PROVIDER_MODULE_SOURCE_DIR = ""; +const std::string FORM_JS_COMPOMENT_NAME = "jsComponentName"; +const std::string PARAM_FORM_NAME = "com.form.name.test"; +const std::string DEVICE_ID = "ohos-phone1"; + +bool BundleMgrProxy::GetBundleInfo(const std::string &bundleName, const BundleFlag flag, BundleInfo &bundleInfo) +{ + return true; +} + +int BundleMgrService::GetUidByBundleName(const std::string &bundleName, const int userId) +{ + if (bundleName.compare("com.form.host.app600") == 0) { + return 600; + } + return 0; +} + +bool BundleMgrProxy::GetAllFormsInfo(std::vector &formInfo) +{ + return true; +} +bool BundleMgrProxy::GetFormsInfoByApp(const std::string &bundleName, std::vector &formInfo) +{ + return true; +} +bool BundleMgrProxy::GetFormsInfoByModule(const std::string &bundleName, const std::string &moduleName, +std::vector &formInfo) +{ + return true; +} + +int BundleMgrStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + return 0; +} + +bool BundleMgrService::QueryAbilityInfo(const AAFwk::Want &want, AbilityInfo &abilityInfo) +{ + return true; +} + +bool BundleMgrService::QueryAbilityInfoByUri(const std::string &uri, AbilityInfo &abilityInfo) +{ + return false; +} + +bool BundleMgrService::GetApplicationInfo( + const std::string &appName, const ApplicationFlag flag, const int userId, ApplicationInfo &appInfo) +{ + return true; +} + +std::string BundleMgrService::GetAppType(const std::string &bundleName) +{ + return "system"; +} + +bool BundleMgrService::GetBundleInfo(const std::string &bundleName, const BundleFlag flag, BundleInfo &bundleInfo) +{ + std::vector abilityInfos; + ApplicationInfo applicationInfo; + ModuleInfo moduleInfo; + + moduleInfo.moduleSourceDir = FORM_PROVIDER_MODULE_SOURCE_DIR; + moduleInfo.moduleName = PARAM_PROVIDER_MODULE_NAME; + bundleInfo.name = bundleName; + applicationInfo.bundleName = bundleName; + applicationInfo.moduleInfos.emplace_back(moduleInfo); + bundleInfo.applicationInfo = applicationInfo; + + bundleInfo.moduleNames.emplace_back(PARAM_PROVIDER_MODULE_NAME); + + AbilityInfo abilityInfo; + abilityInfo.name = FORM_PROVIDER_ABILITY_NAME; + abilityInfo.package = PARAM_PROVIDER_PACKAGE_NAME; + abilityInfo.moduleName = PARAM_PROVIDER_MODULE_NAME; + abilityInfo.deviceId = DEVICE_ID; + bundleInfo.abilityInfos.emplace_back(abilityInfo); + + return true; +} +bool BundleMgrService::GetBundleGids(const std::string &bundleName, std::vector &gids) +{ + return true; +} + +bool BundleMgrService::GetAllFormsInfo(std::vector &formInfo) +{ + return true; +} +bool BundleMgrService::GetFormsInfoByApp(const std::string &bundleName, std::vector &formInfo) +{ + FormInfo form; + form.bundleName = bundleName; + form.abilityName = FORM_PROVIDER_ABILITY_NAME; + form.moduleName = PARAM_PROVIDER_MODULE_NAME; + form.name = PARAM_FORM_NAME; + form.updateEnabled = true; + form.updateDuration = 1; + form.scheduledUpateTime = "06:06"; + form.jsComponentName = FORM_JS_COMPOMENT_NAME; + form.formVisibleNotify = true; + form.supportDimensions = {1, 2}; + form.defaultDimension = 1; + formInfo.emplace_back(form); + return true; +} +bool BundleMgrService::GetFormsInfoByModule(const std::string &bundleName, const std::string &moduleName, +std::vector &formInfo) +{ + FormInfo form; + form.bundleName = bundleName; + form.abilityName = FORM_PROVIDER_ABILITY_NAME; + form.moduleName = PARAM_PROVIDER_MODULE_NAME; + form.name = PARAM_FORM_NAME; + form.updateEnabled = true; + form.updateDuration = 1; + form.scheduledUpateTime = "06:06"; + form.jsComponentName = FORM_JS_COMPOMENT_NAME; + form.formVisibleNotify = true; + form.supportDimensions = {1, 2}; + form.defaultDimension = 1; + formInfo.emplace_back(form); + return true; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/formmgr/test/mock/src/mock_form_host_client.cpp b/services/formmgr/test/mock/src/mock_form_host_client.cpp new file mode 100644 index 0000000000..ad90b9ad4c --- /dev/null +++ b/services/formmgr/test/mock/src/mock_form_host_client.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2021 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 "appexecfwk_errors.h" +#include "app_log_wrapper.h" +#include "errors.h" +#include "mock_form_host_client.h" +#include "string_ex.h" + +namespace OHOS { +namespace AppExecFwk { +// void MockFormHostClient::AddForm(const Ability& slice, int64_t formId){ + +// } + +// void MockFormHostClient::RemoveForm(const Ability& slice, int64_t formId{ + +// } + +// bool MockFormHostClient::ContainsForm(int64_t formId){ +// return false; +// } + +/** + * Request to give back a Form. + * + * @param formInfo, Form info. + * @return none. + */ +void MockFormHostClient::OnAcquired(const FormJsInfo &formInfo) +{ + APP_LOGD("MockFormHostClient OnAcquired"); + + int64_t formId = formInfo.formId; + ASSERT_FALSE(formId == 0); + PostVoid(); +} + +/** +* Form is updated. +* +* @param bundleName, Provider ability bundleName. +* @return none. +*/ +void MockFormHostClient::OnUpdate(const FormJsInfo &formInfo) +{ + APP_LOGD("MockFormHostClient OnUpdate"); + PostVoid(); +} + + +/** + * Form provider is uninstalled + * + * @param formIds, The Id list of the forms. + * @return none. + */ +void MockFormHostClient::OnUninstall(const std::vector &formIds) +{ + APP_LOGD("MockFormHostClient OnUnInstall"); + PostVoid(); +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/formmgr/test/mock/src/mock_form_provider_client.cpp b/services/formmgr/test/mock/src/mock_form_provider_client.cpp new file mode 100644 index 0000000000..2b94d46ec1 --- /dev/null +++ b/services/formmgr/test/mock/src/mock_form_provider_client.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2021 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 "app_log_wrapper.h" +#include "errors.h" +#include "form_constants.h" +#include "form_supply_interface.h" +#include "mock_form_provider_client.h" +#include "string_ex.h" + +namespace OHOS { +namespace AppExecFwk { +/** + * Acquire to give back an ProviderFormInfo. This is sync API. + * + * @param want, The want of the form to create. + * @param callerToken, Caller ability token. + * @return none. + */ +int MockFormProviderClient::AcquireProviderFormInfo(const int64_t formId, const Want &want, +const sptr &callerToken) +{ + // avoid the user modify the number in onCreate + + APP_LOGD("Acquire provider form info"); + + sptr formSupply = iface_cast(callerToken); + if (formSupply == nullptr) { + APP_LOGE("failed to get formSupplyProxy"); + } + // Want newWant; + // newWant.SetElement(want.GetElement()); + // long formId = want.GetLongParam(Constants::PARAM_FORM_IDENTITY_KEY, 0); + // APP_LOGD("AcquireProviderFormInfo, formId:%{public}ld", formId); + + // newWant.SetParam(Constants::PARAM_FORM_IDENTITY_KEY, formId); + + // int type = want.GetIntParam(Constants::ACQUIRE_TYPE, 0); + // newWant.SetParam(Constants::ACQUIRE_TYPE, type); + FormProviderInfo formProviderInfo; + formSupply->OnAcquire(formProviderInfo, want); + return ERR_OK; +} + +/** + * Notify provider when the form was deleted. + * + * @param formId, The Id of the form. + * @param callerToken, Caller ability token. + * @return none. + */ +int MockFormProviderClient::NotifyFormDelete(const int64_t formId, const Want &want, +const sptr &callerToken) +{ + APP_LOGD("Notify form delete"); + return ERR_OK; +} +/** + * Notify provider when the forms was deleted. + * + * @param formIds, The id list of forms. + * @param want Indicates the structure containing form info. + * @param callerToken, Caller ability token. + * @return none. + */ +int MockFormProviderClient::NotifyFormsDelete(const std::vector &formIds, const Want &want, +const sptr &callerToken) +{ + APP_LOGD("Notify forms delete"); + return ERR_OK; +} + +/** + * @brief Notify provider when the form need update. + * @param formId The Id of the form. + * @param want Indicates the structure containing form info. + * @param callerToken Caller ability token. + */ +int MockFormProviderClient::NotifyFormUpdate(const int64_t formId, const Want &want, +const sptr &callerToken) +{ + APP_LOGD("Notify form update"); + return ERR_OK; +} + +/** + * @brief Event notify when change the form visible. + * + * @param formEvents The vector of form ids. + * @param formVisibleType The form visible type, including FORM_VISIBLE and FORM_INVISIBLE. + * @param want Indicates the structure containing form info. + * @param callerToken Caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ +int MockFormProviderClient::EventNotify(const std::vector &formIds, const int32_t formVisibleType, + const Want &want, const sptr &callerToken) +{ + APP_LOGD("Event notify"); + return ERR_OK; +} + +/** + * Notify provider when the temp form was cast to normal form. + * + * @param formId, The Id of the form to update. + * @param callerToken, Caller ability token. + * @return none. + */ +int MockFormProviderClient::NotifyFormCastTempForm(const int64_t formId, const Want &want, +const sptr &callerToken) +{ + APP_LOGD("Notify cast temp form"); + return ERR_OK; +} +/** + * @brief Fire message event to form provider. + * @param formId The Id of the from. + * @param message Event message. + * @param want The want of the request. + * @param callerToken Form provider proxy object. + * @return Returns ERR_OK on success, others on failure. + */ +int MockFormProviderClient::FireFormEvent(const int64_t formId, const std::string &message, const Want &want, +const sptr &callerToken) +{ + APP_LOGD("Fire form event"); + return ERR_OK; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/formmgr/test/unittest/fms_form_cache_mgr_test/BUILD.gn b/services/formmgr/test/unittest/fms_form_cache_mgr_test/BUILD.gn new file mode 100644 index 0000000000..b3153757f9 --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_cache_mgr_test/BUILD.gn @@ -0,0 +1,75 @@ +# Copyright (c) 2021 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/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/formmgrservice" + +ohos_unittest("FmsFormCacheMgrTest") { + module_out_path = module_output_path + + sources = [ "//foundation/appexecfwk/standard/services/formmgr/test/unittest/fms_form_cache_mgr_test/fms_form_cache_mgr_test.cpp" ] + + include_dirs = [ + "//third_party/zlib/contrib/minizip", + "//third_party/zlib", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/fmskit/native/include/", + "//foundation/appexecfwk/standard/common/log/include/", + "//foundation/appexecfwk/standard/services/formmgr/include", + "//foundation/appexecfwk/standard/services/bundlemgr/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base/include/", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/formmgr/", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include/", + "//foundation/distributedschedule/samgr/adapter/interfaces/innerkits/include/", + ] + + configs = [ + "${services_path}/formmgr/test:formmgr_test_config", + "//foundation/aafwk/standard/services/abilitymgr:abilityms_config", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:formmgr_sdk_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/common:libappexecfwk_common", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${appexecfwk_path}/interfaces/innerkits/fmskit:fmskit_native", + "${libs_path}/libeventhandler:libeventhandler_target", + "${services_path}/formmgr:fms_target", + "//base/security/permission/interfaces/innerkits/permission_standard/permissionsdk:libpermissionsdk_standard", + "//base/startup/appspawn_standard:appspawn_socket_client", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/aafwk/standard/services/abilitymgr:abilityms_target", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":FmsFormCacheMgrTest" ] +} diff --git a/services/formmgr/test/unittest/fms_form_cache_mgr_test/fms_form_cache_mgr_test.cpp b/services/formmgr/test/unittest/fms_form_cache_mgr_test/fms_form_cache_mgr_test.cpp new file mode 100644 index 0000000000..5942712a56 --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_cache_mgr_test/fms_form_cache_mgr_test.cpp @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2021 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 "app_log_wrapper.h" +#define private public +#include "form_cache_mgr.h" +#undef private + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; + +const int64_t PARAM_FORM_ID_FIRST = 1001; +const int64_t PARAM_FORM_ID_SECOND = 1002; + +namespace { +class FmsFormCacheMgrTest : public testing::Test { +public: + + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + +protected: + FormCacheMgr formCacheMgr_; +}; + + +void FmsFormCacheMgrTest::SetUpTestCase() +{} + +void FmsFormCacheMgrTest::TearDownTestCase() +{} + +void FmsFormCacheMgrTest::SetUp() +{} + +void FmsFormCacheMgrTest::TearDown() +{} + +/* + * Feature: FormCacheMgr + * Function: GetData + * FunctionPoints: FormCacheMgr GetData interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: invoke GetData works by input key. + */ +HWTEST_F(FmsFormCacheMgrTest, FmsFormCacheMgrTest_001, TestSize.Level0) +{ + APP_LOGI("fms_form_cache_mgr_test_001 start"); + + std::string dataResult = ""; + formCacheMgr_.cacheData_[PARAM_FORM_ID_FIRST]= "{'a':'1','b':'2'}"; + EXPECT_TRUE(formCacheMgr_.GetData(PARAM_FORM_ID_FIRST, dataResult)); + EXPECT_EQ("{'a':'1','b':'2'}", dataResult); + + GTEST_LOG_(INFO) << "fms_form_cache_mgr_test_001 end"; +} + +/* + * Feature: FormCacheMgr + * Function: GetData + * FunctionPoints: FormCacheMgr GetData interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: can not get data by input key. + */ + +HWTEST_F(FmsFormCacheMgrTest, FmsFormCacheMgrTest_002, TestSize.Level0) +{ + APP_LOGI("fms_form_cache_mgr_test_002 start"); + + std::string dataResult = ""; + formCacheMgr_.cacheData_[PARAM_FORM_ID_FIRST]= "{'a':'1','b':'2'}"; + EXPECT_FALSE(formCacheMgr_.GetData(PARAM_FORM_ID_SECOND, dataResult)); + + GTEST_LOG_(INFO) << "fms_form_cache_mgr_test_002 end"; +} + +/* + * Feature: FormCacheMgr + * Function: AddData + * FunctionPoints: FormCacheMgr AddData interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: add data by input param. + */ +HWTEST_F(FmsFormCacheMgrTest, FmsFormCacheMgrTest_003, TestSize.Level0) +{ + APP_LOGI("fms_form_cache_mgr_test_003 start"); + + std::string dataResult = "{'a':'1','b':'2'}"; + EXPECT_TRUE(formCacheMgr_.AddData(PARAM_FORM_ID_FIRST, dataResult)); + EXPECT_EQ(formCacheMgr_.cacheData_[PARAM_FORM_ID_FIRST], dataResult); + + GTEST_LOG_(INFO) << "fms_form_cache_mgr_test_003 end"; +} + +/* + * Feature: FormCacheMgr + * Function: AddData + * FunctionPoints: FormCacheMgr AddData interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: cache contains data and add the new data by input param. + */ +HWTEST_F(FmsFormCacheMgrTest, FmsFormCacheMgrTest_004, TestSize.Level0) +{ + APP_LOGI("fms_form_cache_mgr_test_004 start"); + + std::string dataResult1 = "{'a':'1','b':'2'}"; + std::string dataResult2 = "{'a':'2','b':'2'}"; + formCacheMgr_.AddData(PARAM_FORM_ID_FIRST, dataResult1); + EXPECT_TRUE(formCacheMgr_.AddData(PARAM_FORM_ID_SECOND, dataResult2)); + EXPECT_EQ(formCacheMgr_.cacheData_[PARAM_FORM_ID_SECOND],dataResult2); + + GTEST_LOG_(INFO) << "fms_form_cache_mgr_test_004 end"; +} + +/* + * Feature: FormCacheMgr + * Function: AddData + * FunctionPoints: FormCacheMgr AddData interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: add data but key conflict + */ +HWTEST_F(FmsFormCacheMgrTest, FmsFormCacheMgrTest_010, TestSize.Level0) +{ + APP_LOGI("fms_form_cache_mgr_test_010 start"); + + std::string dataResult1 = "{'a':'1','b':'2'}"; + std::string dataResult2 = "{'a':'2','b':'2'}"; + formCacheMgr_.AddData(PARAM_FORM_ID_FIRST, dataResult1); + EXPECT_FALSE(formCacheMgr_.AddData(PARAM_FORM_ID_FIRST, dataResult2)); + + GTEST_LOG_(INFO) << "fms_form_cache_mgr_test_010 end"; +} + +/* + * Feature: FormCacheMgr + * Function: DeleteData + * FunctionPoints: FormCacheMgr DeleteData interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: delete data by input key + */ +HWTEST_F(FmsFormCacheMgrTest, FmsFormCacheMgrTest_005, TestSize.Level0) +{ + APP_LOGI("fms_form_cache_mgr_test_005 start"); + + std::string dataResult = ""; + std::string dataResult1 = "{'a':'1','b':'2'}"; + std::string dataResult2 = "{'a':'2','b':'2'}"; + formCacheMgr_.AddData(PARAM_FORM_ID_FIRST, dataResult1); + formCacheMgr_.AddData(PARAM_FORM_ID_SECOND, dataResult2); + EXPECT_TRUE(formCacheMgr_.DeleteData(PARAM_FORM_ID_SECOND)); + EXPECT_FALSE(formCacheMgr_.GetData(PARAM_FORM_ID_SECOND, dataResult)); + EXPECT_EQ(formCacheMgr_.cacheData_[PARAM_FORM_ID_FIRST], dataResult1); + + GTEST_LOG_(INFO) << "fms_form_cache_mgr_test_005 end"; +} + +/* + * Feature: FormCacheMgr + * Function: DeleteData + * FunctionPoints: FormCacheMgr DeleteData interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: delete data but not exsit + */ +HWTEST_F(FmsFormCacheMgrTest, FmsFormCacheMgrTest_006, TestSize.Level0) +{ + APP_LOGI("fms_form_cache_mgr_test_006 start"); + + EXPECT_TRUE(formCacheMgr_.DeleteData(PARAM_FORM_ID_SECOND)); + + GTEST_LOG_(INFO) << "fms_form_cache_mgr_test_006 end"; +} + +/* + * Feature: FormCacheMgr + * Function: UpdateData + * FunctionPoints: FormCacheMgr UpdateData interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: update cache's data by input param + */ +HWTEST_F(FmsFormCacheMgrTest, FmsFormCacheMgrTest_007, TestSize.Level0) +{ + APP_LOGI("fms_form_cache_mgr_test_007 start"); + + std::string dataResult = ""; + std::string dataResult1 = "{'a':'1','b':'2'}"; + std::string dataResult2 = "{'a':'2','b':'2'}"; + formCacheMgr_.AddData(PARAM_FORM_ID_FIRST, dataResult1); + EXPECT_TRUE(formCacheMgr_.UpdateData(PARAM_FORM_ID_FIRST, dataResult2)); + EXPECT_EQ(formCacheMgr_.cacheData_[PARAM_FORM_ID_FIRST], dataResult2); + + GTEST_LOG_(INFO) << "fms_form_cache_mgr_test_007 end"; +} + +/* + * Feature: FormCacheMgr + * Function: UpdateData + * FunctionPoints: FormCacheMgr UpdateData interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: update cache's data but not exsit key + */ +HWTEST_F(FmsFormCacheMgrTest, FmsFormCacheMgrTest_008, TestSize.Level0) +{ + APP_LOGI("fms_form_cache_mgr_test_008 start"); + + std::string dataResult1 = "{'a':'1','b':'2'}"; + EXPECT_FALSE(formCacheMgr_.UpdateData(PARAM_FORM_ID_FIRST, dataResult1)); + + GTEST_LOG_(INFO) << "fms_form_cache_mgr_test_008 end"; +} +} \ No newline at end of file diff --git a/services/formmgr/test/unittest/fms_form_data_mgr_test/BUILD.gn b/services/formmgr/test/unittest/fms_form_data_mgr_test/BUILD.gn new file mode 100644 index 0000000000..5b71a556ce --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_data_mgr_test/BUILD.gn @@ -0,0 +1,81 @@ +# Copyright (c) 2021 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/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/formmgrservice" + +ohos_unittest("FmsFormDataMgrTest") { + module_out_path = module_output_path + + sources = [ + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_form_host_client.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/unittest/fms_form_data_mgr_test/fms_form_data_mgr_test.cpp", + ] + + include_dirs = [ + "//third_party/json/include", + "//foundation/appexecfwk/standard/common/log/include/", + "//foundation/appexecfwk/standard/services/formmgr/include", + + #"//foundation/appexecfwk/standard/services/bundlemgr/include", + #"//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base/include/", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/formmgr/", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/bundlemgr/", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include/", + + #"//foundation/distributedschedule/samgr/adapter/interfaces/innerkits/include/", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler/include", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/include", + "//foundation/appexecfwk/appexecfwk_lite/interfaces/kits/bundle_lite", + ] + + configs = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:formmgr_sdk_config", + #"${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:bundlemgr_sdk_config", + #"//foundation/appexecfwk/standard/services/formmgr:formmgr_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/common:libappexecfwk_common", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${services_path}/formmgr:fms_target", + + #"${libs_path}/libeventhandler:libeventhandler_target", + #"//base/startup/appspawn_standard:appspawn_socket_client", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +############################################################################### +group("unittest") { + testonly = true + + deps = [ ":FmsFormDataMgrTest" ] +} +############################################################################### diff --git a/services/formmgr/test/unittest/fms_form_data_mgr_test/fms_form_data_mgr_test.cpp b/services/formmgr/test/unittest/fms_form_data_mgr_test/fms_form_data_mgr_test.cpp new file mode 100644 index 0000000000..9864114ed6 --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_data_mgr_test/fms_form_data_mgr_test.cpp @@ -0,0 +1,2136 @@ +/* + * Copyright (c) 2021 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 +#include +#include +#include "appexecfwk_errors.h" +#include "app_log_wrapper.h" +#define private public +#include "form_data_mgr.h" +#undef private +#include "form_constants.h" +#include "form_record.h" +#include "mock_form_host_client.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; +const std::string FORM_HOST_BUNDLE_NAME = "com.form.provider.service"; +const std::string FORM_PROVIDER_ABILITY_NAME = "com.form.provider.app.test.abiliy"; +const std::string PARAM_PROVIDER_MODULE_NAME = "com.form.provider.app.test.abiliy"; +const std::string FORM_NAME = "formName"; + +namespace { +class FmsFormDataMgrTest : public testing::Test { +public: + FmsFormDataMgrTest() + {} + ~FmsFormDataMgrTest() + {} + + void SetUp(); + void TearDown(); + void InitFormItemInfo(int64_t formId, FormItemInfo &form_item_info); + +protected: + FormDataMgr formDataMgr_; + sptr token_; +}; + +void FmsFormDataMgrTest::SetUp(void) +{ + // token + token_ = new (std::nothrow) OHOS::AppExecFwk::MockFormHostClient(); +} + +void FmsFormDataMgrTest::TearDown(void) +{} + +void FmsFormDataMgrTest::InitFormItemInfo(int64_t formId, FormItemInfo &form_item_info) +{ + // create hapSourceDirs + std::vector hapSourceDirs; + std::string hapSourceDir = "1/2/3"; + hapSourceDirs.emplace_back(hapSourceDir); + + // create form_item_info + form_item_info.SetFormId(formId); + form_item_info.SetTemporaryFlag(true); + form_item_info.SetEnableUpdateFlag(true); + form_item_info.SetUpdateDuration(Constants::MIN_CONFIG_DURATION); + form_item_info.SetScheduledUpdateTime("10:30"); + form_item_info.SetHapSourceDirs(hapSourceDirs); +} + +/** + * @tc.number: FmsFormDataMgrTest_AllotFormRecord_001 + * @tc.name: AllotFormRecord + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * temporaryFlag is true, and tempForms is empty, then create a tempForm. + * formRecords_ is empty, then create formRecords. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_AllotFormRecord_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_AllotFormRecord_001 start"; + + int64_t formId = 1; + int callingUid = 0; + + // create FormItemInfo + FormItemInfo form_item_info; + InitFormItemInfo(formId, form_item_info); + + FormRecord recordResult = formDataMgr_.AllotFormRecord(form_item_info, callingUid ); + EXPECT_EQ(formId, recordResult.formId); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_AllotFormRecord_001 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_AllotFormRecord_002 + * @tc.name: AllotFormRecord + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * formRecords_ is include this formId. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_AllotFormRecord_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_AllotFormRecord_002 start"; + + int64_t formId = 2; + int callingUid = 0; + + // create FormItemInfo + FormItemInfo form_item_info; + InitFormItemInfo(formId, form_item_info); + + // create formRecords + FormRecord record = formDataMgr_.CreateFormRecord(form_item_info, callingUid); + formDataMgr_.formRecords_.emplace(formId, record); + + FormRecord recordResult = formDataMgr_.AllotFormRecord(form_item_info, callingUid ); + EXPECT_EQ(formId, recordResult.formId); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_AllotFormRecord_002 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_AllotFormRecord_003 + * @tc.name: AllotFormRecord + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * formRecords_ is not include this formId, then create formRecords. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_AllotFormRecord_003, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_AllotFormRecord_003 start"; + + int64_t formId = 3; + int64_t otherformId = 100; + int callingUid = 0; + + // create FormItemInfo + FormItemInfo form_item_info; + InitFormItemInfo(formId, form_item_info); + + // create other FormItemInfo + FormItemInfo otherFormItemInfo; + InitFormItemInfo(otherformId, otherFormItemInfo); + + // create formRecords + FormRecord record = formDataMgr_.CreateFormRecord(otherFormItemInfo, callingUid); + formDataMgr_.formRecords_.emplace(otherformId, record); + + FormRecord recordResult = formDataMgr_.AllotFormRecord(form_item_info, callingUid ); + EXPECT_EQ(formId, recordResult.formId); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_AllotFormRecord_003 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_AllotFormRecord_004 + * @tc.name: AllotFormRecord + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * EnableUpdateFlag is true, + * SetUpdateDuration is not MAX_CONFIG_DURATION.(call ParseIntervalConfig) + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_AllotFormRecord_004, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_AllotFormRecord_004 start"; + + int64_t formId = 4; + int callingUid = 0; + + // create FormItemInfo + FormItemInfo form_item_info; + InitFormItemInfo(formId, form_item_info); + form_item_info.SetUpdateDuration(Constants::MAX_CONFIG_DURATION); + + FormRecord recordResult = formDataMgr_.AllotFormRecord(form_item_info, callingUid ); + EXPECT_EQ(formId, recordResult.formId); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_AllotFormRecord_004 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_AllotFormRecord_005 + * @tc.name: AllotFormRecord + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * EnableUpdateFlag is true, + * SetUpdateDuration is between MIN_CONFIG_DURATION and MAX_CONFIG_DURATION.(call ParseIntervalConfig) + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_AllotFormRecord_005, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_AllotFormRecord_005 start"; + + int64_t formId = 5; + int callingUid = 0; + + // create FormItemInfo + FormItemInfo form_item_info; + InitFormItemInfo(formId, form_item_info); + form_item_info.SetUpdateDuration(Constants::MAX_CONFIG_DURATION-2); + + FormRecord recordResult = formDataMgr_.AllotFormRecord(form_item_info, callingUid ); + EXPECT_EQ(formId, recordResult.formId); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_AllotFormRecord_005 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_AllotFormRecord_006 + * @tc.name: AllotFormRecord + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * SetUpdateDuration is 0.(call ParseAtTimerConfig) + * 获取配置项scheduledUpdateTime_为empty + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_AllotFormRecord_006, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_AllotFormRecord_006 start"; + + int64_t formId = 6; + int callingUid = 0; + + // create FormItemInfo + FormItemInfo form_item_info; + InitFormItemInfo(formId, form_item_info); + form_item_info.SetUpdateDuration(0); + form_item_info.scheduledUpdateTime_.clear(); + + FormRecord recordResult = formDataMgr_.AllotFormRecord(form_item_info, callingUid ); + EXPECT_EQ(formId, recordResult.formId); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_AllotFormRecord_006 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_AllotFormRecord_007 + * @tc.name: AllotFormRecord + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * SetUpdateDuration is 0.(call ParseAtTimerConfig) + * 获取配置项scheduledUpdateTime_为无效值 + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_AllotFormRecord_007, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_AllotFormRecord_007 start"; + + int64_t formId = 7; + int callingUid = 0; + + // create FormItemInfo + FormItemInfo form_item_info; + InitFormItemInfo(formId, form_item_info); + form_item_info.SetUpdateDuration(0); + form_item_info.SetScheduledUpdateTime("10:30:10"); + + FormRecord recordResult = formDataMgr_.AllotFormRecord(form_item_info, callingUid ); + EXPECT_EQ(formId, recordResult.formId); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_AllotFormRecord_007 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_AllotFormRecord_008 + * @tc.name: AllotFormRecord + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * SetUpdateDuration is 0.(call ParseAtTimerConfig) + * 获取配置项scheduledUpdateTime_为无效值 + * 不存在hapSourceDirs_ + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_AllotFormRecord_008, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_AllotFormRecord_008 start"; + + int64_t formId = 8; + int callingUid = 0; + + // create FormItemInfo + FormItemInfo form_item_info; + InitFormItemInfo(formId, form_item_info); + form_item_info.SetUpdateDuration(0); + form_item_info.SetScheduledUpdateTime("10:70"); + form_item_info.hapSourceDirs_.clear(); + + FormRecord recordResult = formDataMgr_.AllotFormRecord(form_item_info, callingUid ); + EXPECT_EQ(formId, recordResult.formId); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_AllotFormRecord_008 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_AllotFormRecord_009 + * @tc.name: AllotFormRecord + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * SetUpdateDuration is 0.(call ParseAtTimerConfig) + * 获取配置项scheduledUpdateTime_为有效值 + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_AllotFormRecord_009, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_AllotFormRecord_009 start"; + + int64_t formId = 9; + int callingUid = 0; + + // create FormItemInfo + FormItemInfo form_item_info; + InitFormItemInfo(formId, form_item_info); + form_item_info.SetUpdateDuration(0); + + FormRecord recordResult = formDataMgr_.AllotFormRecord(form_item_info, callingUid ); + EXPECT_EQ(formId, recordResult.formId); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_AllotFormRecord_009 end"; +} + + +/** + * @tc.number: FmsFormDataMgrTest_AllotFormHostRecord_001 + * @tc.name: AllotFormHostRecord + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * clientRecords_ is include token_. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_AllotFormHostRecord_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_AllotFormHostRecord_001 start"; + + int64_t formId = 1; + int callingUid = 0; + + // create FormItemInfo + FormItemInfo formItemInfo; + InitFormItemInfo(formId, formItemInfo); + + // create clientRecords_ + FormHostRecord formHostRecord; + formHostRecord.SetClientStub(token_); + formDataMgr_.clientRecords_.push_back(formHostRecord); + + EXPECT_EQ(true, formDataMgr_.AllotFormHostRecord(formItemInfo, token_, formId, callingUid)); + EXPECT_EQ(true, formDataMgr_.clientRecords_.begin()->forms_[formId]); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_AllotFormHostRecord_001 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_AllotFormHostRecord_002 + * @tc.name: AllotFormHostRecord + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * clientRecords_ is not include token_. + * CreateHostRecord is OK. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_AllotFormHostRecord_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_AllotFormHostRecord_002 start"; + + int64_t formId = 2; + int callingUid = 0; + + //create FormItemInfo + FormItemInfo formItemInfo; + InitFormItemInfo(formId, formItemInfo); + + EXPECT_EQ(true, formDataMgr_.AllotFormHostRecord(formItemInfo, token_, formId, callingUid)); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_AllotFormHostRecord_002 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_AllotFormHostRecord_003 + * @tc.name: AllotFormHostRecord + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * clientRecords_ is not include token_. + * CreateHostRecord is NG. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_AllotFormHostRecord_003, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_AllotFormHostRecord_003 start"; + + int64_t formId = 3; + int callingUid = 0; + + // create FormItemInfo + FormItemInfo formItemInfo; + InitFormItemInfo(formId, formItemInfo); + + // set callerToken nullptr + token_ = nullptr; + + EXPECT_EQ(false, formDataMgr_.AllotFormHostRecord(formItemInfo, token_, formId, callingUid)); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_AllotFormHostRecord_003 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_CreateFormInfo_001 + * @tc.name: CreateFormInfo + * @tc.desc: Verify that the return value is correct. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_CreateFormInfo_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_CreateFormInfo_001 start"; + + int64_t formId = 1; + + // create record + FormRecord record; + record.bundleName = FORM_HOST_BUNDLE_NAME; + record.abilityName = FORM_PROVIDER_ABILITY_NAME; + record.formName = FORM_NAME; + record.formTempFlg = true; + + FormJsInfo formInfo; + + formDataMgr_.CreateFormInfo(formId, record, formInfo); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_CreateFormInfo_001 output=>bundleName:"< formInfos; + + EXPECT_EQ(false, formDataMgr_.GetFormRecord(bundleName, formInfos)); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_GetFormRecord_2_001 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_GetFormRecord_2_002 + * @tc.name: GetFormRecord_2 + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * formRecords is found. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_GetFormRecord_2_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_GetFormRecord_2_002 start"; + + std::string bundleName = "bundleName"; + std::vector formInfos; + + // create formRecords_ + int64_t formId = 2; + int callingUid = 0; + FormItemInfo formItemInfo; + InitFormItemInfo(formId, formItemInfo); + formItemInfo.SetProviderBundleName(bundleName); + FormRecord record = formDataMgr_.CreateFormRecord(formItemInfo, callingUid); + formDataMgr_.formRecords_.emplace(formId, record); + + EXPECT_EQ(true, formDataMgr_.GetFormRecord(bundleName, formInfos)); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_GetFormRecord_2_002 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_HasFormUserUids_001 + * @tc.name: HasFormUserUids + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * formRecords is not found. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_HasFormUserUids_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_HasFormUserUids_001 start"; + + int64_t formId = 1; + + EXPECT_EQ(false, formDataMgr_.HasFormUserUids(formId)); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_HasFormUserUids_001 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_HasFormUserUids_002 + * @tc.name: HasFormUserUids + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * formRecords is found. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_HasFormUserUids_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_HasFormUserUids_002 start"; + + int64_t formId = 2; + + // create formRecords_ + int callingUid = 0; + FormItemInfo formItemInfo; + InitFormItemInfo(formId, formItemInfo); + FormRecord record = formDataMgr_.CreateFormRecord(formItemInfo, callingUid); + formDataMgr_.formRecords_.emplace(formId, record); + + EXPECT_EQ(true, formDataMgr_.HasFormUserUids(formId)); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_HasFormUserUids_002 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_GetFormHostRecord_001 + * @tc.name: GetFormHostRecord + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * clientRecords_ is not found. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_GetFormHostRecord_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_GetFormHostRecord_001 start"; + + int64_t formId = 1; + FormHostRecord formHostRecord; + + EXPECT_EQ(false, formDataMgr_.GetFormHostRecord(formId, formHostRecord)); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_GetFormHostRecord_001 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_GetFormHostRecord_002 + * @tc.name: GetFormHostRecord + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * clientRecords_ is found. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_GetFormHostRecord_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_GetFormHostRecord_002 start"; + + int64_t formId = 2; + FormHostRecord formHostRecord; + + // create clientRecords_ + FormHostRecord form_host_record; + form_host_record.SetClientStub(token_); + form_host_record.AddForm(formId); + formDataMgr_.clientRecords_.push_back(form_host_record); + + EXPECT_EQ(true, formDataMgr_.GetFormHostRecord(formId, formHostRecord)); + EXPECT_EQ(true, formHostRecord.forms_[formId]); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_GetFormHostRecord_002 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_DeleteHostRecord_001 + * @tc.name: DeleteHostRecord + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * clientRecords_ is found. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_DeleteHostRecord_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_DeleteHostRecord_001 start"; + + int64_t formId = 1; + + // create clientRecords_ + FormHostRecord formHostRecord; + formHostRecord.SetClientStub(token_); + formHostRecord.AddForm(formId); + formDataMgr_.clientRecords_.push_back(formHostRecord); + + EXPECT_EQ(true, formDataMgr_.DeleteHostRecord(token_, formId)); + EXPECT_EQ(true, formDataMgr_.clientRecords_.empty()); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_DeleteHostRecord_001 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_CleanHostRemovedForms_001 + * @tc.name: CleanHostRemovedForms + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * clientRecords_ is found. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_CleanHostRemovedForms_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_CleanHostRemovedForms_001 start"; + + std::vector removedFormIds; + int64_t formId = 1; + removedFormIds.emplace_back(formId); + + // create clientRecords_ + FormHostRecord formHostRecord; + formHostRecord.SetClientStub(token_); + formHostRecord.AddForm(formId); + formDataMgr_.clientRecords_.push_back(formHostRecord); + + formDataMgr_.CleanHostRemovedForms(removedFormIds); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_CleanHostRemovedForms_001 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_HandleHostDied_001 + * @tc.name: HandleHostDied + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * clientRecords_ & tempForms_ & formRecords is found. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_HandleHostDied_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_HandleHostDied_001 start"; + + int64_t formId = 1; + + // create tempForms_ + formDataMgr_.tempForms_.emplace_back(formId); + + // create clientRecords_ + FormHostRecord formHostRecord; + formHostRecord.SetClientStub(token_); + formHostRecord.AddForm(formId); + formDataMgr_.clientRecords_.push_back(formHostRecord); + + // create formRecords + int callingUid = 0; + FormItemInfo formItemInfo; + InitFormItemInfo(formId, formItemInfo); + FormRecord record = formDataMgr_.CreateFormRecord(formItemInfo, callingUid); + formDataMgr_.formRecords_.emplace(formId, record); + + formDataMgr_.HandleHostDied(token_); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_HandleHostDied_001 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_HandleHostDied_002 + * @tc.name: HandleHostDied + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * tempForms_ is not match. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_HandleHostDied_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_HandleHostDied_002 start"; + + int64_t formId = 2; + int64_t otherFormId = 3; + + // create tempForms_ + formDataMgr_.tempForms_.emplace_back(otherFormId); + + // create clientRecords_ + FormHostRecord formHostRecord; + formHostRecord.SetClientStub(token_); + formHostRecord.AddForm(formId); + formDataMgr_.clientRecords_.push_back(formHostRecord); + + // create formRecords + int callingUid = 0; + FormItemInfo formItemInfo; + InitFormItemInfo(formId, formItemInfo); + FormRecord record = formDataMgr_.CreateFormRecord(formItemInfo, callingUid); + formDataMgr_.formRecords_.emplace(formId, record); + + formDataMgr_.HandleHostDied(token_); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_HandleHostDied_002 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_HandleHostDied_003 + * @tc.name: HandleHostDied + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * remoteHost is not match, formRecords is not found. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_HandleHostDied_003, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_HandleHostDied_003 start"; + + int64_t formId = 3; + + // create clientRecords_ + sptr token_2; + FormHostRecord formHostRecord; + formHostRecord.SetClientStub(token_2); + formHostRecord.AddForm(formId); + formDataMgr_.clientRecords_.push_back(formHostRecord); + + // create formRecords + int callingUid = 0; + FormItemInfo formItemInfo; + InitFormItemInfo(formId, formItemInfo); + FormRecord record = formDataMgr_.CreateFormRecord(formItemInfo, callingUid); + formDataMgr_.formRecords_.emplace(formId, record); + + formDataMgr_.HandleHostDied(token_); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_HandleHostDied_003 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_IsEnableRefresh_001 + * @tc.name: IsEnableRefresh + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * clientRecords_ is not found. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_IsEnableRefresh_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_IsEnableRefresh_001 start"; + + int64_t formId = 1; + EXPECT_EQ(false, formDataMgr_.IsEnableRefresh(formId)); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_IsEnableRefresh_001 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_IsEnableRefresh_002 + * @tc.name: IsEnableRefresh + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * clientRecords_ is found. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_IsEnableRefresh_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_IsEnableRefresh_002 start"; + + int64_t formId = 2; + + // create clientRecords_ + sptr token_; + FormHostRecord formHostRecord; + formHostRecord.SetClientStub(token_); + formHostRecord.AddForm(formId); + formDataMgr_.clientRecords_.push_back(formHostRecord); + + EXPECT_EQ(true, formDataMgr_.IsEnableRefresh(formId)); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_IsEnableRefresh_002 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_GenerateUdidHash_001 + * @tc.name: GenerateUdidHash + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * udidHash_ is not 0. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_GenerateUdidHash_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_GenerateUdidHash_001 start"; + + formDataMgr_.udidHash_ = 1; + EXPECT_EQ(true, formDataMgr_.GenerateUdidHash()); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_GenerateUdidHash_001 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_GenerateUdidHash_002 + * @tc.name: GenerateUdidHash + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * udidHash_ is 0. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_GenerateUdidHash_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_GenerateUdidHash_002 start"; + + formDataMgr_.udidHash_ = Constants::INVALID_UDID_HASH; + EXPECT_EQ(true, formDataMgr_.GenerateUdidHash()); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_GenerateUdidHash_002 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_GetMatchedHostClient_001 + * @tc.name: GetMatchedHostClient + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * clientRecords_ is not found. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_GetMatchedHostClient_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_GetMatchedHostClient_001 start"; + + // create clientRecords_ + FormHostRecord formHostRecord; + + EXPECT_EQ(false, formDataMgr_.GetMatchedHostClient(token_, formHostRecord)); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_GetMatchedHostClient_001 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_GetMatchedHostClient_002 + * @tc.name: GetMatchedHostClient + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * clientRecords_ is found. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_GetMatchedHostClient_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_GetMatchedHostClient_002 start"; + + int64_t formId = 2; + + // create clientRecords_ + FormHostRecord formHostRecord; + formHostRecord.SetClientStub(token_); + formHostRecord.AddForm(formId); + formDataMgr_.clientRecords_.push_back(formHostRecord); + + FormHostRecord formHostRecordOutput; + + EXPECT_EQ(true, formDataMgr_.GetMatchedHostClient(token_, formHostRecordOutput)); + EXPECT_EQ(true, formHostRecordOutput.forms_[formId]); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_GetMatchedHostClient_002 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_SetNeedRefresh_001 + * @tc.name: SetNeedRefresh + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * formRecords_ is not found. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_SetNeedRefresh_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_SetNeedRefresh_001 start"; + + int64_t formId = 1; + bool needRefresh = true; + + formDataMgr_.SetNeedRefresh(formId, needRefresh); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_SetNeedRefresh_001 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_SetNeedRefresh_002 + * @tc.name: SetNeedRefresh + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * formRecords_ is not found. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_SetNeedRefresh_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_SetNeedRefresh_002 start"; + + int64_t formId = 2; + bool needRefresh = true; + + // create formRecords + int callingUid = 0; + FormItemInfo formItemInfo; + InitFormItemInfo(formId, formItemInfo); + FormRecord record = formDataMgr_.CreateFormRecord(formItemInfo, callingUid); + formDataMgr_.formRecords_.emplace(formId, record); + + formDataMgr_.SetNeedRefresh(formId, needRefresh); + EXPECT_EQ(true, formDataMgr_.formRecords_.find(formId)->second.needRefresh); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_SetNeedRefresh_002 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_SetCountTimerRefresh_001 + * @tc.name: SetCountTimerRefresh + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * formRecords_ is not found. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_SetCountTimerRefresh_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_SetCountTimerRefresh_001 start"; + + int64_t formId = 1; + bool countTimerRefresh = true; + + formDataMgr_.SetCountTimerRefresh(formId, countTimerRefresh); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_SetCountTimerRefresh_001 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_SetCountTimerRefresh_002 + * @tc.name: SetCountTimerRefresh + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * formRecords_ is not found. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_SetCountTimerRefresh_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_SetCountTimerRefresh_002 start"; + + int64_t formId = 2; + bool countTimerRefresh = true; + + // create formRecords + int callingUid = 0; + FormItemInfo formItemInfo; + InitFormItemInfo(formId, formItemInfo); + FormRecord record = formDataMgr_.CreateFormRecord(formItemInfo, callingUid); + formDataMgr_.formRecords_.emplace(formId, record); + + formDataMgr_.SetCountTimerRefresh(formId, countTimerRefresh); + EXPECT_EQ(true, formDataMgr_.formRecords_.find(formId)->second.isCountTimerRefresh); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_SetCountTimerRefresh_002 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_GetUpdatedForm_001 + * @tc.name: GetUpdatedForm + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * targetForms is empty. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_GetUpdatedForm_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_GetUpdatedForm_001 start"; + + FormRecord record; + std::vector targetForms; + FormInfo updatedForm; + + EXPECT_EQ(false, formDataMgr_.GetUpdatedForm(record, targetForms, updatedForm)); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_GetUpdatedForm_001 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_GetUpdatedForm_002 + * @tc.name: GetUpdatedForm + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * targetForms is not empty. record is same as formInfo. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_GetUpdatedForm_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_GetUpdatedForm_002 start"; + + int32_t specification = 2; + + FormRecord record; + record.bundleName = FORM_HOST_BUNDLE_NAME; + record.moduleName = PARAM_PROVIDER_MODULE_NAME; + record.abilityName = FORM_PROVIDER_ABILITY_NAME; + record.formName = FORM_NAME; + record.specification = specification; + + std::vector targetForms; + FormInfo formInfo; + formInfo.bundleName = FORM_HOST_BUNDLE_NAME; + formInfo.moduleName = PARAM_PROVIDER_MODULE_NAME; + formInfo.abilityName = FORM_PROVIDER_ABILITY_NAME; + formInfo.name = FORM_NAME; + formInfo.supportDimensions.emplace_back(specification); + targetForms.emplace_back(formInfo); + + FormInfo updatedForm; + + EXPECT_EQ(true, formDataMgr_.GetUpdatedForm(record, targetForms, updatedForm)); + EXPECT_EQ(FORM_HOST_BUNDLE_NAME, updatedForm.bundleName); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_GetUpdatedForm_002 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_GetUpdatedForm_003 + * @tc.name: GetUpdatedForm + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * targetForms is not empty. record is not same as formInfo. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_GetUpdatedForm_003, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_GetUpdatedForm_003 start"; + + int32_t specification = 3; + + FormRecord record; + record.bundleName = "bundleName"; + record.moduleName = PARAM_PROVIDER_MODULE_NAME; + record.abilityName = FORM_PROVIDER_ABILITY_NAME; + record.formName = FORM_NAME; + record.specification = specification; + + std::vector targetForms; + FormInfo formInfo; + formInfo.bundleName = FORM_HOST_BUNDLE_NAME; + formInfo.moduleName = PARAM_PROVIDER_MODULE_NAME; + formInfo.abilityName = FORM_PROVIDER_ABILITY_NAME; + formInfo.name = FORM_NAME; + formInfo.supportDimensions.emplace_back(specification); + targetForms.emplace_back(formInfo); + + FormInfo updatedForm; + + EXPECT_EQ(false, formDataMgr_.GetUpdatedForm(record, targetForms, updatedForm)); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_GetUpdatedForm_003 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_SetEnableUpdate_001 + * @tc.name: SetEnableUpdate + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * formRecords_ is not found. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_SetEnableUpdate_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_SetEnableUpdate_001 start"; + + int64_t formId = 1; + bool enableUpdate = true; + + formDataMgr_.SetEnableUpdate(formId, enableUpdate); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_SetEnableUpdate_001 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_SetEnableUpdate_002 + * @tc.name: SetEnableUpdate + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * formRecords_ is not found. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_SetEnableUpdate_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_SetEnableUpdate_002 start"; + + int64_t formId = 2; + bool enableUpdate = true; + + // create formRecords + int callingUid = 0; + FormItemInfo formItemInfo; + InitFormItemInfo(formId, formItemInfo); + FormRecord record = formDataMgr_.CreateFormRecord(formItemInfo, callingUid); + formDataMgr_.formRecords_.emplace(formId, record); + + formDataMgr_.SetEnableUpdate(formId, enableUpdate); + EXPECT_EQ(true, formDataMgr_.formRecords_.find(formId)->second.isEnableUpdate); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_SetEnableUpdate_002 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_SetUpdateInfo_001 + * @tc.name: SetUpdateInfo + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * formRecords_ is not found. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_SetUpdateInfo_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_SetUpdateInfo_001 start"; + + int64_t formId = 1; + bool enableUpdate = true; + long updateDuration = 100; + int updateAtHour = 24; + int updateAtMin = 59; + + formDataMgr_.SetUpdateInfo(formId, enableUpdate, updateDuration, updateAtHour, updateAtMin); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_SetUpdateInfo_001 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_SetUpdateInfo_002 + * @tc.name: SetUpdateInfo + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * formRecords_ is not found. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_SetUpdateInfo_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_SetUpdateInfo_002 start"; + + int64_t formId = 1; + bool enableUpdate = true; + long updateDuration = 100; + int updateAtHour = 24; + int updateAtMin = 59; + + // create formRecords + int callingUid = 0; + FormItemInfo formItemInfo; + InitFormItemInfo(formId, formItemInfo); + FormRecord record = formDataMgr_.CreateFormRecord(formItemInfo, callingUid); + formDataMgr_.formRecords_.emplace(formId, record); + + formDataMgr_.SetUpdateInfo(formId, enableUpdate, updateDuration, updateAtHour, updateAtMin); + EXPECT_EQ(true, formDataMgr_.formRecords_.find(formId)->second.isEnableUpdate); + EXPECT_EQ(100, formDataMgr_.formRecords_.find(formId)->second.updateDuration); + EXPECT_EQ(24, formDataMgr_.formRecords_.find(formId)->second.updateAtHour); + EXPECT_EQ(59, formDataMgr_.formRecords_.find(formId)->second.updateAtMin); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_SetUpdateInfo_002 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_CleanRemovedFormRecords_001 + * @tc.name: CleanRemovedFormRecords + + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * removedForm is matched with formRecords_. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_CleanRemovedFormRecords_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_CleanRemovedFormRecords_001 start"; + + // create formRecords + int callingUid = 0; + int64_t formId = 1; + FormItemInfo formItemInfo; + InitFormItemInfo(formId, formItemInfo); + FormRecord record = formDataMgr_.CreateFormRecord(formItemInfo, callingUid); + formDataMgr_.formRecords_.emplace(formId, record); + + std::string bundleName = FORM_HOST_BUNDLE_NAME; + + std::set removedForms; + int64_t removedForm = formId; + removedForms.emplace(removedForm); + + formDataMgr_.CleanRemovedFormRecords(bundleName, removedForms); + EXPECT_EQ(true, formDataMgr_.formRecords_.empty()); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_CleanRemovedFormRecords_001 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_CleanRemovedFormRecords_002 + * @tc.name: CleanRemovedFormRecords + + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * removedForm is not matched with formRecords_. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_CleanRemovedFormRecords_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_CleanRemovedFormRecords_002 start"; + + // create formRecords + int callingUid = 0; + int64_t formId = 2; + FormItemInfo formItemInfo; + InitFormItemInfo(formId, formItemInfo); + FormRecord record = formDataMgr_.CreateFormRecord(formItemInfo, callingUid); + formDataMgr_.formRecords_.emplace(formId, record); + + std::string bundleName = FORM_HOST_BUNDLE_NAME; + + std::set removedForms; + int64_t removedForm = 100; + removedForms.emplace(removedForm); + + formDataMgr_.CleanRemovedFormRecords(bundleName, removedForms); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_CleanRemovedFormRecords_002 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_CleanRemovedTempFormRecords_001 + * @tc.name: CleanRemovedTempFormRecords + + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * bundleName is matched with formRecords_, and it is temp. + * erase formRecords_ and tempForms_. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_CleanRemovedTempFormRecords_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_CleanRemovedTempFormRecords_001 start"; + + int64_t formId = 1; + std::string bundleName = FORM_HOST_BUNDLE_NAME; + + std::set removedForms; + int64_t removedForm = formId; + removedForms.emplace(removedForm); + + // create formRecords + int callingUid = 0; + FormItemInfo formItemInfo; + InitFormItemInfo(formId, formItemInfo); + formItemInfo.SetProviderBundleName(bundleName); + FormRecord record = formDataMgr_.CreateFormRecord(formItemInfo, callingUid); + formDataMgr_.formRecords_.emplace(formId, record); + + // create tempForms_ + formDataMgr_.tempForms_.emplace_back(formId); + + formDataMgr_.CleanRemovedTempFormRecords(bundleName, removedForms); + EXPECT_EQ(true, formDataMgr_.formRecords_.empty()); + EXPECT_EQ(true, formDataMgr_.tempForms_.empty()); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_CleanRemovedTempFormRecords_001 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_CleanRemovedTempFormRecords_002 + * @tc.name: CleanRemovedTempFormRecords + + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * bundleName is not matched with formRecords_. + * erase none. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_CleanRemovedTempFormRecords_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_CleanRemovedTempFormRecords_002 start"; + + int64_t formId = 2; + std::string bundleName = FORM_HOST_BUNDLE_NAME; + std::string otherBundleName = "bundleName"; + + std::set removedForms; + int64_t removedForm = formId; + removedForms.emplace(removedForm); + + // create formRecords + int callingUid = 0; + FormItemInfo formItemInfo; + InitFormItemInfo(formId, formItemInfo); + formItemInfo.SetProviderBundleName(otherBundleName); + FormRecord record = formDataMgr_.CreateFormRecord(formItemInfo, callingUid); + formDataMgr_.formRecords_.emplace(formId, record); + + // create tempForms_ + formDataMgr_.tempForms_.emplace_back(formId); + + formDataMgr_.CleanRemovedTempFormRecords(bundleName, removedForms); + EXPECT_EQ(false, formDataMgr_.formRecords_.empty()); + EXPECT_EQ(false, formDataMgr_.tempForms_.empty()); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_CleanRemovedTempFormRecords_002 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_GetReCreateFormRecordsByBundleName_001 + * @tc.name: GetReCreateFormRecordsByBundleName + + * @tc.desc: Verify that the return value is correct. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_GetReCreateFormRecordsByBundleName_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_GetReCreateFormRecordsByBundleName_001 start"; + + int64_t formId = 1; + std::string bundleName = FORM_HOST_BUNDLE_NAME; + + std::set reCreateForms; + int64_t reCreateForm = formId; + reCreateForms.emplace(reCreateForm); + + // create formRecords + int callingUid = 0; + FormItemInfo formItemInfo; + InitFormItemInfo(formId, formItemInfo); + formItemInfo.SetProviderBundleName(bundleName); + FormRecord record = formDataMgr_.CreateFormRecord(formItemInfo, callingUid); + formDataMgr_.formRecords_.emplace(formId, record); + + formDataMgr_.GetReCreateFormRecordsByBundleName(bundleName, reCreateForms); + EXPECT_EQ(true, reCreateForms.count(formId)); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_GetReCreateFormRecordsByBundleName_001 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_SetFormCacheInited_001 + * @tc.name: SetFormCacheInited + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * formRecords_ is not found. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_SetFormCacheInited_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_SetFormCacheInited_001 start"; + + int64_t formId = 1; + + formDataMgr_.SetFormCacheInited(formId, true); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_SetFormCacheInited_001 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_SetFormCacheInited_002 + * @tc.name: SetFormCacheInited + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * formRecords_ is found. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_SetFormCacheInited_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_SetFormCacheInited_002 start"; + + int64_t formId = 2; + + // create formRecords + int callingUid = 0; + FormItemInfo formItemInfo; + InitFormItemInfo(formId, formItemInfo); + FormRecord record = formDataMgr_.CreateFormRecord(formItemInfo, callingUid); + formDataMgr_.formRecords_.emplace(formId, record); + + formDataMgr_.SetFormCacheInited(formId, true); + EXPECT_EQ(true, formDataMgr_.formRecords_.find(formId)->second.isInited); + EXPECT_EQ(false, formDataMgr_.formRecords_.find(formId)->second.needRefresh); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_SetFormCacheInited_002 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_SetVersionUpgrade_001 + * @tc.name: SetVersionUpgrade + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * formRecords_ is not found. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_SetVersionUpgrade_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_SetVersionUpgrade_001 start"; + + int64_t formId = 1; + bool version = true; + + formDataMgr_.SetVersionUpgrade(formId, version); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_SetVersionUpgrade_001 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_SetVersionUpgrade_002 + * @tc.name: SetFormCacheInitedTrue + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * formRecords_ is found. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_SetVersionUpgrade_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_SetVersionUpgrade_002 start"; + + int64_t formId = 2; + bool versionUpgrade = true; + + // create formRecords + int callingUid = 0; + FormItemInfo formItemInfo; + InitFormItemInfo(formId, formItemInfo); + FormRecord record = formDataMgr_.CreateFormRecord(formItemInfo, callingUid); + formDataMgr_.formRecords_.emplace(formId, record); + + formDataMgr_.SetVersionUpgrade(formId, versionUpgrade); + EXPECT_EQ(true, formDataMgr_.formRecords_.find(formId)->second.versionUpgrade); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_SetVersionUpgrade_002 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_UpdateHostNeedRefresh_001 + * @tc.name: UpdateHostNeedRefresh + * @tc.desc: Verify that the return value is correct. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_UpdateHostNeedRefresh_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_UpdateHostNeedRefresh_001 start"; + + int64_t formId = 1; + bool needRefresh = true; + + // create clientRecords_ + FormHostRecord formHostRecord; + formHostRecord.AddForm(formId); + formDataMgr_.clientRecords_.push_back(formHostRecord); + + formDataMgr_.UpdateHostNeedRefresh(formId, needRefresh); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_UpdateHostNeedRefresh_001 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_UpdateHostForm_001 + * @tc.name: UpdateHostForm + * @tc.desc: Verify that the return value is correct. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_UpdateHostForm_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_UpdateHostForm_001 start"; + + int64_t formId = 1; + FormRecord formRecord; + + // create clientRecords_ + FormHostRecord formHostRecord; + formHostRecord.AddForm(formId); + formDataMgr_.clientRecords_.push_back(formHostRecord); + + EXPECT_EQ(true, formDataMgr_.UpdateHostForm(formId, formRecord)); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_UpdateHostForm_001 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_UpdateHostFormFlag_001 + * @tc.name: UpdateHostFormFlag + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * clientRecords_ is not exit. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_UpdateHostFormFlag_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_UpdateHostFormFlag_001 start"; + + std::vector formIds; + int64_t formId = 1; + formIds.emplace_back(formId); + + bool flag = true; + + std::vector refreshForms; + + EXPECT_EQ(ERR_FORM_INVALID_PARAM, formDataMgr_.UpdateHostFormFlag(formIds, token_, flag, refreshForms)); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_UpdateHostFormFlag_001 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_UpdateHostFormFlag_002 + * @tc.name: UpdateHostFormFlag + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * formRecords's VersionUpgrade is false. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_UpdateHostFormFlag_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_UpdateHostFormFlag_002 start"; + + std::vector formIds; + int64_t formId = 2; + formIds.emplace_back(formId); + + bool flag = true; + + std::vector refreshForms; + + // create clientRecords_ + FormHostRecord formHostRecord; + formHostRecord.SetClientStub(token_); + formHostRecord.AddForm(formId); + // SetNeedRefresh:true + formHostRecord.SetNeedRefresh(formId, true); + formDataMgr_.clientRecords_.push_back(formHostRecord); + + // create formRecords + int callingUid = 0; + FormItemInfo formItemInfo; + InitFormItemInfo(formId, formItemInfo); + FormRecord record = formDataMgr_.CreateFormRecord(formItemInfo, callingUid); + formDataMgr_.formRecords_.emplace(formId, record); + // versionUpgrade : false + formDataMgr_.SetVersionUpgrade(formId, false); + + EXPECT_EQ(ERR_OK, formDataMgr_.UpdateHostFormFlag(formIds, token_, flag, refreshForms)); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_UpdateHostFormFlag_002 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_UpdateHostFormFlag_003 + * @tc.name: UpdateHostFormFlag + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * formRecords's VersionUpgrade is true. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_UpdateHostFormFlag_003, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_UpdateHostFormFlag_003 start"; + + std::vector formIds; + int64_t formId = 3; + formIds.emplace_back(formId); + + bool flag = true; + + std::vector refreshForms; + + // create clientRecords_ + FormHostRecord formHostRecord; + formHostRecord.SetClientStub(token_); + formHostRecord.AddForm(formId); + // SetNeedRefresh:true + formHostRecord.SetNeedRefresh(formId, true); + formDataMgr_.clientRecords_.push_back(formHostRecord); + + // create formRecords + int callingUid = 0; + FormItemInfo formItemInfo; + InitFormItemInfo(formId, formItemInfo); + FormRecord record = formDataMgr_.CreateFormRecord(formItemInfo, callingUid); + formDataMgr_.formRecords_.emplace(formId, record); + // versionUpgrade : true + formDataMgr_.SetVersionUpgrade(formId, true); + + EXPECT_EQ(ERR_OK, formDataMgr_.UpdateHostFormFlag(formIds, token_, flag, refreshForms)); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_UpdateHostFormFlag_003 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_UpdateHostFormFlag_004 + * @tc.name: UpdateHostFormFlag + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * clientRecords_'s NeedRefresh is false. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_UpdateHostFormFlag_004, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_UpdateHostFormFlag_004 start"; + + std::vector formIds; + int64_t formId = 4; + formIds.emplace_back(formId); + + bool flag = true; + + std::vector refreshForms; + + // create clientRecords_ + FormHostRecord formHostRecord; + formHostRecord.SetClientStub(token_); + formHostRecord.AddForm(formId); + // SetNeedRefresh:false + formHostRecord.SetNeedRefresh(formId, false); + formDataMgr_.clientRecords_.push_back(formHostRecord); + + // create formRecords + int callingUid = 0; + FormItemInfo formItemInfo; + InitFormItemInfo(formId, formItemInfo); + FormRecord record = formDataMgr_.CreateFormRecord(formItemInfo, callingUid); + formDataMgr_.formRecords_.emplace(formId, record); + + EXPECT_EQ(ERR_OK, formDataMgr_.UpdateHostFormFlag(formIds, token_, flag, refreshForms)); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_UpdateHostFormFlag_004 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_UpdateHostFormFlag_005 + * @tc.name: UpdateHostFormFlag + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * clientRecords_ is not include formId. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_UpdateHostFormFlag_005, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_UpdateHostFormFlag_005 start"; + + std::vector formIds; + int64_t formId = 5; + formIds.emplace_back(formId); + + bool flag = true; + + std::vector refreshForms; + + // create clientRecords_ + int64_t otherformId = 500; + FormHostRecord formHostRecord; + formHostRecord.SetClientStub(token_); + formHostRecord.AddForm(otherformId); + formDataMgr_.clientRecords_.push_back(formHostRecord); + + // create formRecords + int callingUid = 0; + FormItemInfo formItemInfo; + InitFormItemInfo(formId, formItemInfo); + FormRecord record = formDataMgr_.CreateFormRecord(formItemInfo, callingUid); + formDataMgr_.formRecords_.emplace(formId, record); + + EXPECT_EQ(ERR_OK, formDataMgr_.UpdateHostFormFlag(formIds, token_, flag, refreshForms)); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_UpdateHostFormFlag_005 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_UpdateHostFormFlag_006 + * @tc.name: UpdateHostFormFlag + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * flag is false. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_UpdateHostFormFlag_006, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_UpdateHostFormFlag_006 start"; + + std::vector formIds; + int64_t formId = 6; + formIds.emplace_back(formId); + + bool flag = false; + + std::vector refreshForms; + + // create clientRecords_ + FormHostRecord formHostRecord; + formHostRecord.SetClientStub(token_); + formHostRecord.AddForm(formId); + formDataMgr_.clientRecords_.push_back(formHostRecord); + + // create formRecords + int callingUid = 0; + FormItemInfo formItemInfo; + InitFormItemInfo(formId, formItemInfo); + FormRecord record = formDataMgr_.CreateFormRecord(formItemInfo, callingUid); + formDataMgr_.formRecords_.emplace(formId, record); + + EXPECT_EQ(ERR_OK, formDataMgr_.UpdateHostFormFlag(formIds, token_, flag, refreshForms)); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_UpdateHostFormFlag_006 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_UpdateHostFormFlag_007 + * @tc.name: UpdateHostFormFlag + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * formRecords's needRefresh is true. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_UpdateHostFormFlag_007, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_UpdateHostFormFlag_007 start"; + + std::vector formIds; + int64_t formId = 7; + formIds.emplace_back(formId); + + bool flag = true; + + std::vector refreshForms; + + // create clientRecords_ + FormHostRecord formHostRecord; + formHostRecord.SetClientStub(token_); + formHostRecord.AddForm(formId); + formDataMgr_.clientRecords_.push_back(formHostRecord); + + // create formRecords + int callingUid = 0; + FormItemInfo formItemInfo; + InitFormItemInfo(formId, formItemInfo); + FormRecord record = formDataMgr_.CreateFormRecord(formItemInfo, callingUid); + // needRefresh:true + record.needRefresh = true; + formDataMgr_.formRecords_.emplace(formId, record); + + EXPECT_EQ(ERR_OK, formDataMgr_.UpdateHostFormFlag(formIds, token_, flag, refreshForms)); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_UpdateHostFormFlag_007 end"; +} + +/** + * @tc.number: FmsFormDataMgrTest_UpdateHostFormFlag_008 + * @tc.name: UpdateHostFormFlag + * @tc.desc: Verify that the return value is correct. + * @tc.details: + * formRecords is not include formId. + */ +HWTEST_F(FmsFormDataMgrTest, FmsFormDataMgrTest_UpdateHostFormFlag_008, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_UpdateHostFormFlag_008 start"; + + std::vector formIds; + int64_t formId = 8; + formIds.emplace_back(formId); + + bool flag = true; + + std::vector refreshForms; + + // create clientRecords_ + FormHostRecord formHostRecord; + formHostRecord.SetClientStub(token_); + formHostRecord.AddForm(formId); + formDataMgr_.clientRecords_.push_back(formHostRecord); + + // create formRecords + int64_t otherFormId = 800; + int callingUid = 0; + FormItemInfo formItemInfo; + InitFormItemInfo(otherFormId, formItemInfo); + FormRecord record = formDataMgr_.CreateFormRecord(formItemInfo, callingUid); + formDataMgr_.formRecords_.emplace(otherFormId, record); + + EXPECT_EQ(ERR_OK, formDataMgr_.UpdateHostFormFlag(formIds, token_, flag, refreshForms)); + + GTEST_LOG_(INFO) << "FmsFormDataMgrTest_UpdateHostFormFlag_008 end"; +} +} diff --git a/services/formmgr/test/unittest/fms_form_db_record_test/BUILD.gn b/services/formmgr/test/unittest/fms_form_db_record_test/BUILD.gn new file mode 100644 index 0000000000..22051724cd --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_db_record_test/BUILD.gn @@ -0,0 +1,76 @@ +# Copyright (c) 2021 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/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/formmgrservice" + +ohos_unittest("FmsFormDbRecordTest") { + module_out_path = module_output_path + + sources = [ "//foundation/appexecfwk/standard/services/formmgr/test/unittest/fms_form_db_record_test/fms_form_db_record_test.cpp" ] + + include_dirs = [ + "//third_party/json/include", + "//foundation/appexecfwk/standard/common/log/include/", + "//foundation/appexecfwk/standard/services/formmgr/include", + + #"//foundation/appexecfwk/standard/services/bundlemgr/include", + #"//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base/include/", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/formmgr/", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/bundlemgr/", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include/", + + #"//foundation/distributedschedule/samgr/adapter/interfaces/innerkits/include/", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler/include", + ] + + configs = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:formmgr_sdk_config", + #"${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:bundlemgr_sdk_config", + #"//foundation/appexecfwk/standard/services/formmgr:formmgr_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/common:libappexecfwk_common", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${services_path}/formmgr:fms_target", + + #"${libs_path}/libeventhandler:libeventhandler_target", + #"//base/startup/appspawn_standard:appspawn_socket_client", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +############################################################################### +group("unittest") { + testonly = true + + deps = [ ":FmsFormDbRecordTest" ] +} +############################################################################### diff --git a/services/formmgr/test/unittest/fms_form_db_record_test/fms_form_db_record_test.cpp b/services/formmgr/test/unittest/fms_form_db_record_test/fms_form_db_record_test.cpp new file mode 100644 index 0000000000..944bfb5e83 --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_db_record_test/fms_form_db_record_test.cpp @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2021 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 +#include +#include +#include "app_log_wrapper.h" +#define private public +#include "form_db_cache.h" +#include "form_mgr_adapter.h" +#include "form_storage_mgr.h" +#undef private +#include "form_record.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; + +namespace { +class FmsFormDbRecordTest : public testing::Test { +public: + void InitFormRecord(); + FormRecord formRecord_; + FormMgrAdapter formMgrAdapter_; +}; + +void FmsFormDbRecordTest::InitFormRecord() +{ + formRecord_.isInited = false; + formRecord_.needFreeInstall = false; + formRecord_.versionUpgrade = false; + formRecord_.needRefresh = false; + formRecord_.packageName = "TestPackageName"; + formRecord_.bundleName = "TestBundleName"; + formRecord_.moduleName = "TestModuleName"; + formRecord_.abilityName = "TestAbilityName"; + formRecord_.formName = "TestFormName"; + formRecord_.specification = 0; + formRecord_.isEnableUpdate = false; + formRecord_.updateDuration = 0; + formRecord_.updateAtHour = 0; + formRecord_.updateAtMin = 0; + formRecord_.hapSourceDirs.emplace_back("hapSourceDirs1"); + formRecord_.formName = "formNameTest"; + formRecord_.formTempFlg = false; + formRecord_.formUserUids.emplace_back(1); + formRecord_.formVisibleNotify = false; + formRecord_.formVisibleNotifyState = 0; +} + +HWTEST_F(FmsFormDbRecordTest, FmsFormDbRecordTest_001, TestSize.Level0) // create +{ + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_001 start"; + FormDbCache::GetInstance().Start(); + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_001 end"; +} + +HWTEST_F(FmsFormDbRecordTest, FmsFormDbRecordTest_002, TestSize.Level0) // save formId 0, callIds[1] +{ + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_002 start"; + InitFormRecord(); + EXPECT_EQ(ERR_OK, FormDbCache::GetInstance().UpdateDBRecord(0, formRecord_)); + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_002 end"; +} + +HWTEST_F(FmsFormDbRecordTest, FmsFormDbRecordTest_003, TestSize.Level0) // save formId 1, callIds[1, 0] +{ + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_003 start"; + InitFormRecord(); + formRecord_.formUserUids.emplace_back(0); + EXPECT_EQ(ERR_OK, FormDbCache::GetInstance().UpdateDBRecord(1, formRecord_)); + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_003 end"; +} + +HWTEST_F(FmsFormDbRecordTest, FmsFormDbRecordTest_004, TestSize.Level0) // modify formId 1, callIds[1,2] +{ + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_004 start"; + InitFormRecord(); + formRecord_.formUserUids.emplace_back(2); + EXPECT_EQ(ERR_OK, FormDbCache::GetInstance().UpdateDBRecord(1, formRecord_)); + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_004 end"; +} + +HWTEST_F(FmsFormDbRecordTest, FmsFormDbRecordTest_005, TestSize.Level0) // modify formId 0, callIds[1,2] +{ + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_005 start"; + InitFormRecord(); + formRecord_.formUserUids.emplace_back(2); + EXPECT_EQ(ERR_OK, FormDbCache::GetInstance().UpdateDBRecord(0, formRecord_)); + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_005 end"; +} + +HWTEST_F(FmsFormDbRecordTest, FmsFormDbRecordTest_006, TestSize.Level0) // GetAllDBRecord +{ + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_006 start"; + FormRecord record; + EXPECT_EQ(ERR_OK, FormDbCache::GetInstance().GetDBRecord(0, record)); + + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_006 formName: " << record.formName; + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_006 bundleName:" << record.bundleName; + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_006 moduleName:" << record.moduleName; + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_006 abilityName:" << record.abilityName; + for (unsigned int j = 0; j < record.formUserUids.size(); j++){ + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_006 formUserUids:" << record.formUserUids[j]; + } + + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_006 -------------------"; + + EXPECT_EQ(ERR_OK, FormDbCache::GetInstance().GetDBRecord(1, record)); + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_006 formName: " << record.formName; + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_006 bundleName:" << record.bundleName; + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_006 moduleName:" << record.moduleName; + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_006 abilityName:" << record.abilityName; + for (unsigned int j = 0; j < record.formUserUids.size(); j++){ + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_006 formUserUids:" << record.formUserUids[j]; + } + + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_006 end"; +} + +HWTEST_F(FmsFormDbRecordTest, FmsFormDbRecordTest_007, TestSize.Level0) // save for next load: formId 0, callIds[1] +{ + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_007 start"; + + InitFormRecord(); + EXPECT_EQ(ERR_OK, FormDbCache::GetInstance().UpdateDBRecord(0, formRecord_)); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_007 end"; +} + +HWTEST_F(FmsFormDbRecordTest, FmsFormDbRecordTest_008, TestSize.Level0) // save for next load: formId 1, callIds[1,0] +{ + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_008 start"; + + InitFormRecord(); + formRecord_.formUserUids.emplace_back(0); + EXPECT_EQ(ERR_OK, FormDbCache::GetInstance().UpdateDBRecord(1, formRecord_)); + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_008 end"; +} + +HWTEST_F(FmsFormDbRecordTest, FmsFormDbRecordTest_009, TestSize.Level0) // GetAllDBRecord +{ + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_009 start"; + + FormRecord record; + EXPECT_EQ(ERR_OK, FormDbCache::GetInstance().GetDBRecord(0, record)); + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_009 formName: " << record.formName; + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_009 bundleName:" << record.bundleName; + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_009 moduleName:" << record.moduleName; + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_009 abilityName:" << record.abilityName; + for (unsigned int j = 0; j < record.formUserUids.size(); j++){ + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_009 formUserUids:" << record.formUserUids[j]; + } + + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_009 -------------------"; + + EXPECT_EQ(ERR_OK, FormDbCache::GetInstance().GetDBRecord(1, record)); + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_009 formName: " << record.formName; + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_009 bundleName:" << record.bundleName; + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_009 moduleName:" << record.moduleName; + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_009 abilityName:" << record.abilityName; + for (unsigned int j = 0; j < record.formUserUids.size(); j++){ + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_009 formUserUids:" << record.formUserUids[j]; + } + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_009 end"; +} + +HWTEST_F(FmsFormDbRecordTest, FmsFormDbRecordTest_010, TestSize.Level0) // DeleteDbRecord(1) +{ + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_010 start"; + EXPECT_EQ(ERR_OK, FormDbCache::GetInstance().DeleteFormInfo(1)); + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_010 end"; +} + +HWTEST_F(FmsFormDbRecordTest, FmsFormDbRecordTest_011, TestSize.Level0) // DeleteDbRecord not exist +{ + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_011 start"; + EXPECT_EQ(ERR_APPEXECFWK_FORM_JSON_DELETE_FAIL, FormDbCache::GetInstance().DeleteFormInfo(2)); + GTEST_LOG_(INFO) << "FmsFormDbRecordTest_011 end"; +} +} diff --git a/services/formmgr/test/unittest/fms_form_host_record_test/BUILD.gn b/services/formmgr/test/unittest/fms_form_host_record_test/BUILD.gn new file mode 100644 index 0000000000..8f7fc495b4 --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_host_record_test/BUILD.gn @@ -0,0 +1,82 @@ +# Copyright (c) 2021 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/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/formmgrservice" + +ohos_unittest("FmsFormHostRecordTest") { + module_out_path = module_output_path + + sources = [ + "//foundation/appexecfwk/standard/interfaces/innerkits/fmskit/native/src/form_mgr.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_bundle_manager.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_form_host_client.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_form_provider_client.cpp", + ] + sources += [ "fms_form_host_record_test.cpp" ] + + include_dirs = [ + "//third_party/zlib/contrib/minizip", + "//third_party/zlib", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/fmskit/native/include/", + "//foundation/appexecfwk/standard/common/log/include/", + "//foundation/appexecfwk/standard/services/formmgr/include", + "//foundation/appexecfwk/standard/services/bundlemgr/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base/include/", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/formmgr/", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include/", + "//foundation/distributedschedule/samgr/adapter/interfaces/innerkits/include/", + ] + + configs = [ + "${services_path}/formmgr/test:formmgr_test_config", + "//foundation/aafwk/standard/services/abilitymgr:abilityms_config", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:formmgr_sdk_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/common:libappexecfwk_common", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${appexecfwk_path}/interfaces/innerkits/fmskit:fmskit_native", + "${libs_path}/libeventhandler:libeventhandler_target", + "${services_path}/formmgr:fms_target", + "//base/security/permission/interfaces/innerkits/permission_standard/permissionsdk:libpermissionsdk_standard", + "//base/startup/appspawn_standard:appspawn_socket_client", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/aafwk/standard/services/abilitymgr:abilityms_target", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/googletest:gmock_main", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":FmsFormHostRecordTest" ] +} diff --git a/services/formmgr/test/unittest/fms_form_host_record_test/fms_form_host_record_test.cpp b/services/formmgr/test/unittest/fms_form_host_record_test/fms_form_host_record_test.cpp new file mode 100644 index 0000000000..c9956ac308 --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_host_record_test/fms_form_host_record_test.cpp @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2021 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 "form_ams_helper.h" +#include "form_bms_helper.h" +#include "form_data_mgr.h" +#include "form_db_cache.h" +#include "form_host_interface.h" +#define private public +#include "form_mgr.h" +#undef private +#include "form_mgr_service.h" +#include "if_system_ability_manager.h" +#include "inner_bundle_info.h" +#include "ipc_skeleton.h" +#include "iservice_registry.h" + +#include "mock_ability_manager.h" +#include "mock_bundle_manager.h" +#include "mock_form_host_client.h" +#include "permission/permission_kit.h" +#include "permission/permission.h" +#include "running_process_info.h" +#include "system_ability_definition.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; +using namespace OHOS::Security; + +namespace { +const std::string PERMISSION_NAME_REQUIRE_FORM = "ohos.permission.REQUIRE_FORM"; +const std::string PARAM_PROVIDER_PACKAGE_NAME = "com.form.provider.app.test.abiliy"; +const std::string FORM_PROVIDER_BUNDLE_NAME = "com.form.provider.service"; +const std::string PARAM_PROVIDER_MODULE_NAME = "com.form.provider.app.test.abiliy"; +const std::string FORM_PROVIDER_ABILITY_NAME = "com.form.provider.app.test.abiliy"; +const std::string PARAM_FORM_NAME = "com.form.name.test"; + +const std::string FORM_JS_COMPOMENT_NAME = "jsComponentName"; +const std::string FORM_PROVIDER_MODULE_SOURCE_DIR = ""; + +const std::string FORM_HOST_BUNDLE_NAME = "com.form.host.app"; + +const std::string DEVICE_ID = "ohos-phone1"; +const std::string DEF_LABEL1 = "PermissionFormRequireGrant"; + +class FmsFormHostRecordTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + +protected: + sptr token_; + std::shared_ptr formyMgrServ_ = DelayedSingleton::GetInstance(); + + sptr mockBundleMgr_; + sptr mockAbilityMgrServ_; +}; + +void FmsFormHostRecordTest::SetUpTestCase() +{} + +void FmsFormHostRecordTest::TearDownTestCase() +{} + +void FmsFormHostRecordTest::SetUp() +{ + formyMgrServ_->OnStart(); + + mockBundleMgr_ = new (std::nothrow) BundleMgrService(); + EXPECT_TRUE(mockBundleMgr_ != nullptr); + FormBmsHelper::GetInstance().SetBundleManager(mockBundleMgr_); + + mockAbilityMgrServ_ = new (std::nothrow) MockAbilityMgrService(); + FormAmsHelper::GetInstance().SetAbilityManager(mockAbilityMgrServ_); + + token_ = new (std::nothrow) MockFormHostClient(); + + // Permission install + std::vector permList; + Permission::PermissionDef permDef; + permDef.permissionName = PERMISSION_NAME_REQUIRE_FORM; + permDef.bundleName = FORM_PROVIDER_BUNDLE_NAME; + permDef.grantMode = Permission::GrantMode::USER_GRANT; + permDef.availableScope = Permission::AvailableScope::AVAILABLE_SCOPE_ALL; + permDef.label = DEF_LABEL1; + permDef.labelId = 1; + permDef.description = DEF_LABEL1; + permDef.descriptionId = 1; + permList.emplace_back(permDef); + Permission::PermissionKit::AddDefPermissions(permList); + Permission::PermissionKit::AddUserGrantedReqPermissions(FORM_PROVIDER_BUNDLE_NAME, {PERMISSION_NAME_REQUIRE_FORM}, + 0); + Permission::PermissionKit::GrantUserGrantedPermission(FORM_PROVIDER_BUNDLE_NAME, PERMISSION_NAME_REQUIRE_FORM, 0); +} + +void FmsFormHostRecordTest::TearDown() +{} + +/* + * Feature: FormMgrService + * Function: FormHostRecord + * SubFunction: OnRemoteDied Function + * FunctionPoints: FormMgr OnRemoteDied interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Quote of form is not 0 after remote died. + */ +HWTEST_F(FmsFormHostRecordTest, OnRemoteDied_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_host_record_test_001 start"; + + int64_t formId1 {12001}; + int callingUid {0}; + // Create cache + FormItemInfo record1; + record1.SetFormId(formId1); + record1.SetProviderBundleName(FORM_HOST_BUNDLE_NAME); + record1.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + record1.SetTemporaryFlag(true); + FormDataMgr::GetInstance().AllotFormRecord(record1, callingUid); + int64_t formId2 {12002}; + FormItemInfo record2; + record2.SetFormId(formId2); + record2.SetProviderBundleName(FORM_HOST_BUNDLE_NAME); + record2.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + record2.SetTemporaryFlag(true); + FormDataMgr::GetInstance().AllotFormRecord(record2, callingUid); + // Set host record + FormItemInfo info; + FormDataMgr::GetInstance().AllotFormHostRecord(info, token_, formId1, callingUid); + + FormHostRecord hostRecord; + FormDataMgr::GetInstance().GetFormHostRecord(formId1, hostRecord); + hostRecord.GetDeathRecipient()->OnRemoteDied(token_); + + FormDataMgr::GetInstance().DeleteFormRecord(formId1); + FormDataMgr::GetInstance().DeleteFormRecord(formId2); + FormDataMgr::GetInstance().ClearHostDataByUId(callingUid); + + GTEST_LOG_(INFO) << "fms_form_host_record_test_001 end"; +} +} diff --git a/services/formmgr/test/unittest/fms_form_mgr_add_form_test/BUILD.gn b/services/formmgr/test/unittest/fms_form_mgr_add_form_test/BUILD.gn new file mode 100644 index 0000000000..9a2aaf24cf --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_mgr_add_form_test/BUILD.gn @@ -0,0 +1,86 @@ +# Copyright (c) 2021 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/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/formmgrservice" + +ohos_unittest("FmsFormMgrAddFormTest") { + module_out_path = module_output_path + + sources = [ + "//foundation/appexecfwk/standard/interfaces/innerkits/fmskit/native/src/form_mgr.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_bundle_manager.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_form_host_client.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_form_provider_client.cpp", + ] + sources += [ "fms_form_mgr_add_form_test.cpp" ] + + include_dirs = [ + "//third_party/zlib/contrib/minizip", + "//third_party/zlib", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/fmskit/native/include/", + "//foundation/appexecfwk/standard/common/log/include/", + "//foundation/appexecfwk/standard/services/formmgr/include", + "//foundation/appexecfwk/standard/services/bundlemgr/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base/include/", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/formmgr/", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include/", + "//foundation/distributedschedule/samgr/adapter/interfaces/innerkits/include/", + ] + + configs = [ + "${services_path}/formmgr/test:formmgr_test_config", + "//foundation/aafwk/standard/services/abilitymgr:abilityms_config", + + # "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:bundlemgr_sdk_config", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:formmgr_sdk_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/common:libappexecfwk_common", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${appexecfwk_path}/interfaces/innerkits/fmskit:fmskit_native", + "${libs_path}/libeventhandler:libeventhandler_target", + "${services_path}/formmgr:fms_target", + "//base/security/permission/interfaces/innerkits/permission_standard/permissionsdk:libpermissionsdk_standard", + "//base/startup/appspawn_standard:appspawn_socket_client", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + + #"${services_path}/bundlemgr:bms_target", + "//foundation/aafwk/standard/services/abilitymgr:abilityms_target", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/googletest:gmock_main", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":FmsFormMgrAddFormTest" ] +} diff --git a/services/formmgr/test/unittest/fms_form_mgr_add_form_test/fms_form_mgr_add_form_test.cpp b/services/formmgr/test/unittest/fms_form_mgr_add_form_test/fms_form_mgr_add_form_test.cpp new file mode 100644 index 0000000000..2213089b19 --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_mgr_add_form_test/fms_form_mgr_add_form_test.cpp @@ -0,0 +1,547 @@ +/* + * Copyright (c) 2021 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 "form_ams_helper.h" +#include "form_bms_helper.h" +#define private public +#include "form_data_mgr.h" +#undef private +#include "form_db_cache.h" +#include "form_host_interface.h" +#define private public +#include "form_mgr.h" +#undef private +#include "form_mgr_service.h" +#include "if_system_ability_manager.h" +#include "inner_bundle_info.h" +#include "ipc_skeleton.h" +#include "iservice_registry.h" + +#include "mock_ability_manager.h" +#include "mock_bundle_manager.h" +#include "mock_form_host_client.h" +#include "permission/permission_kit.h" +#include "permission/permission.h" +#include "running_process_info.h" +#include "system_ability_definition.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; +using namespace OHOS::Security; + +namespace { +const std::string PERMISSION_NAME_REQUIRE_FORM = "ohos.permission.REQUIRE_FORM"; +const std::string PARAM_PROVIDER_PACKAGE_NAME = "com.form.provider.app.test.abiliy"; +const std::string FORM_PROVIDER_BUNDLE_NAME = "com.form.provider.service"; +const std::string PARAM_PROVIDER_MODULE_NAME = "com.form.provider.app.test.abiliy"; +const std::string FORM_PROVIDER_ABILITY_NAME = "com.form.provider.app.test.abiliy"; +const std::string PARAM_FORM_NAME = "com.form.name.test"; + +const std::string FORM_JS_COMPOMENT_NAME = "jsComponentName"; +const std::string FORM_PROVIDER_MODULE_SOURCE_DIR = ""; + +const std::string FORM_HOST_BUNDLE_NAME = "com.form.host.app"; + +const int32_t PARAM_FORM_DIMENSION_VALUE = 1; + +const std::string DEVICE_ID = "ohos-phone1"; +const std::string DEF_LABEL1 = "PermissionFormRequireGrant"; + +class FmsFormMgrAddFormTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + +protected: + sptr token_; + std::shared_ptr formyMgrServ_ = DelayedSingleton::GetInstance(); + + sptr mockBundleMgr_; + sptr mockAbilityMgrServ_; +}; + +void FmsFormMgrAddFormTest::SetUpTestCase() +{} + +void FmsFormMgrAddFormTest::TearDownTestCase() +{} + +void FmsFormMgrAddFormTest::SetUp() +{ + // APP_LOGI("fms_form_mgr_client_test_001 setup"); + formyMgrServ_->OnStart(); + + mockBundleMgr_ = new (std::nothrow) BundleMgrService(); + EXPECT_TRUE(mockBundleMgr_ != nullptr); + FormBmsHelper::GetInstance().SetBundleManager(mockBundleMgr_); + + mockAbilityMgrServ_ = new (std::nothrow) MockAbilityMgrService(); + FormAmsHelper::GetInstance().SetAbilityManager(mockAbilityMgrServ_); + + // APP_LOGI("fms_form_mgr_client_test_001 FormMgrService started"); + token_ = new (std::nothrow) MockFormHostClient(); + + // Permission install + std::vector permList; + Permission::PermissionDef permDef; + permDef.permissionName = PERMISSION_NAME_REQUIRE_FORM; + permDef.bundleName = FORM_PROVIDER_BUNDLE_NAME; + permDef.grantMode = Permission::GrantMode::USER_GRANT; + permDef.availableScope = Permission::AvailableScope::AVAILABLE_SCOPE_ALL; + permDef.label = DEF_LABEL1; + permDef.labelId = 1; + permDef.description = DEF_LABEL1; + permDef.descriptionId = 1; + permList.emplace_back(permDef); + Permission::PermissionKit::AddDefPermissions(permList); + Permission::PermissionKit::AddUserGrantedReqPermissions(FORM_PROVIDER_BUNDLE_NAME, {PERMISSION_NAME_REQUIRE_FORM}, + 0); + Permission::PermissionKit::GrantUserGrantedPermission(FORM_PROVIDER_BUNDLE_NAME, PERMISSION_NAME_REQUIRE_FORM, 0); +} + +void FmsFormMgrAddFormTest::TearDown() +{} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: AddForm Function + * FunctionPoints: FormMgr AddForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if FormMgr invoke AddForm works. + */ + +HWTEST_F(FmsFormMgrAddFormTest, AddForm_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_add_form_test_001 start"; + // No cache + FormJsInfo formJsInfo; + Want want; + want.SetParam(Constants::PARAM_FORM_HOST_BUNDLENAME_KEY, FORM_HOST_BUNDLE_NAME); + want.SetParam(Constants::PARAM_MODULE_NAME_KEY, PARAM_PROVIDER_MODULE_NAME); + want.SetParam(Constants::PARAM_FORM_NAME_KEY, PARAM_FORM_NAME); + want.SetParam(Constants::PARAM_FORM_DIMENSION_KEY, PARAM_FORM_DIMENSION_VALUE); + want.SetElementName(DEVICE_ID, FORM_PROVIDER_BUNDLE_NAME, FORM_PROVIDER_ABILITY_NAME); + want.SetParam(Constants::PARAM_FORM_TEMPORARY_KEY, false); + want.SetParam(Constants::ACQUIRE_TYPE, Constants::ACQUIRE_TYPE_CREATE_FORM); + + EXPECT_EQ(ERR_OK, FormMgr::GetInstance().AddForm(0L, want, token_, formJsInfo)); + token_->Wait(); + + size_t dataCnt{1}; + int64_t formId = formJsInfo.formId; + // Form record alloted. + FormRecord formInfo; + bool ret = FormDataMgr::GetInstance().GetFormRecord(formId, formInfo); + EXPECT_TRUE(ret); + EXPECT_EQ(dataCnt, formInfo.formUserUids.size()); + // Database info alloted. + std::vector formDBInfos; + FormDbCache::GetInstance().GetAllFormInfo(formDBInfos); + EXPECT_EQ(dataCnt, formDBInfos.size()); + FormDBInfo dbInfo {formDBInfos[0]}; + EXPECT_EQ(formId, dbInfo.formId); + EXPECT_EQ(dataCnt, dbInfo.formUserUids.size()); + // Form host record alloted. + FormHostRecord hostRecord; + ret = FormDataMgr::GetInstance().GetFormHostRecord(formId, hostRecord); + EXPECT_TRUE(ret); + + FormDataMgr::GetInstance().DeleteFormRecord(formId); + FormDbCache::GetInstance().DeleteFormInfo(formId); + FormDataMgr::GetInstance().DeleteHostRecord(token_, formId); + GTEST_LOG_(INFO) << "fms_form_mgr_add_form_test_001 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: AddForm Function + * FunctionPoints: FormMgr AddForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Add form with cache info. + */ +HWTEST_F(FmsFormMgrAddFormTest, AddForm_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_add_form_test_002 start"; + + int64_t formId = 0x0ffabcff00000000; + int callingUid {0}; + // Set cache + FormItemInfo record1; + record1.SetFormId(formId); + record1.SetProviderBundleName(FORM_PROVIDER_BUNDLE_NAME); + record1.SetModuleName(PARAM_FORM_NAME); + record1.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + record1.SetFormName(PARAM_FORM_NAME); + record1.SetSpecificationId(PARAM_FORM_DIMENSION_VALUE); + record1.SetTemporaryFlag(false); + FormRecord retFormRec = FormDataMgr::GetInstance().AllotFormRecord(record1, callingUid); + retFormRec.updateAtHour = 1; + retFormRec.updateAtMin = 1; + FormDataMgr::GetInstance().UpdateFormRecord(formId, retFormRec); + // Set database info + FormDBInfo formDBInfo(formId, retFormRec); + FormDbCache::GetInstance().SaveFormInfo(formDBInfo); + // Set form host record + FormItemInfo info; + FormDataMgr::GetInstance().AllotFormHostRecord(info, token_, formId, callingUid); + + FormJsInfo formJsInfo; + Want want; + want.SetParam(Constants::PARAM_FORM_HOST_BUNDLENAME_KEY, FORM_HOST_BUNDLE_NAME); + want.SetParam(Constants::PARAM_MODULE_NAME_KEY, PARAM_PROVIDER_MODULE_NAME); + want.SetParam(Constants::PARAM_FORM_NAME_KEY, PARAM_FORM_NAME); + want.SetParam(Constants::PARAM_FORM_DIMENSION_KEY, PARAM_FORM_DIMENSION_VALUE); + want.SetElementName(DEVICE_ID, FORM_PROVIDER_BUNDLE_NAME, FORM_PROVIDER_ABILITY_NAME); + want.SetParam(Constants::PARAM_FORM_TEMPORARY_KEY, false); + want.SetParam(Constants::ACQUIRE_TYPE, Constants::ACQUIRE_TYPE_CREATE_FORM); + + GTEST_LOG_(INFO) << "formId :"<Wait(); + + size_t dataCnt{1}; + size_t formUserUidCnt{1}; + // Cache params updated. + FormRecord formInfo; + bool ret = FormDataMgr::GetInstance().GetFormRecord(formId, formInfo); + EXPECT_TRUE(ret); + EXPECT_EQ(formUserUidCnt, formInfo.formUserUids.size()); + // database info updated. + std::vector formDBInfos; + FormDbCache::GetInstance().GetAllFormInfo(formDBInfos); + EXPECT_EQ(dataCnt, formDBInfos.size()); + FormDBInfo dbInfo {formDBInfos[0]}; + EXPECT_EQ(formId, dbInfo.formId); + EXPECT_EQ(formUserUidCnt, dbInfo.formUserUids.size()); + // Form host record not changed. + FormHostRecord hostRecord; + ret = FormDataMgr::GetInstance().GetFormHostRecord(formId, hostRecord); + EXPECT_TRUE(ret); + + FormDataMgr::GetInstance().DeleteFormRecord(formId); + FormDbCache::GetInstance().DeleteFormInfo(formId); + FormDataMgr::GetInstance().DeleteHostRecord(token_, formId); + + GTEST_LOG_(INFO) << "fms_form_mgr_add_form_test_002 end"; +} +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: AddForm Function + * FunctionPoints: FormMgr AddForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Add form with database info but without cache. + */ +HWTEST_F(FmsFormMgrAddFormTest, AddForm_003, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_add_form_test_003 start"; + + int64_t formId = 0x0ffabcdf00000000; + int callingUid {0}; + // Set database info + FormRecord record1; + record1.formId = formId; + record1.bundleName = FORM_PROVIDER_BUNDLE_NAME; + record1.moduleName = PARAM_FORM_NAME; + record1.abilityName = FORM_PROVIDER_ABILITY_NAME; + record1.formName = PARAM_FORM_NAME; + record1.specification = PARAM_FORM_DIMENSION_VALUE; + record1.formUserUids.emplace_back(callingUid); + record1.formTempFlg = false; + FormDBInfo formDBInfo(formId, record1); + FormDbCache::GetInstance().SaveFormInfo(formDBInfo); + // Set form host record + FormItemInfo info; + FormDataMgr::GetInstance().AllotFormHostRecord(info, token_, formId, callingUid); + FormJsInfo formJsInfo; + Want want; + want.SetParam(Constants::PARAM_FORM_HOST_BUNDLENAME_KEY, FORM_HOST_BUNDLE_NAME); + want.SetParam(Constants::PARAM_MODULE_NAME_KEY, PARAM_PROVIDER_MODULE_NAME); + want.SetParam(Constants::PARAM_FORM_NAME_KEY, PARAM_FORM_NAME); + want.SetParam(Constants::PARAM_FORM_DIMENSION_KEY, PARAM_FORM_DIMENSION_VALUE); + want.SetElementName(DEVICE_ID, FORM_PROVIDER_BUNDLE_NAME, FORM_PROVIDER_ABILITY_NAME); + want.SetParam(Constants::PARAM_FORM_TEMPORARY_KEY, false); + want.SetParam(Constants::ACQUIRE_TYPE, Constants::ACQUIRE_TYPE_CREATE_FORM); + + GTEST_LOG_(INFO) << "formId :"<Wait(); + + size_t dataCnt{1}; + size_t formUserUidCnt{1}; + // Cache params updated. + FormRecord formInfo; + bool ret = FormDataMgr::GetInstance().GetFormRecord(formId, formInfo); + EXPECT_TRUE(ret); + EXPECT_EQ(formUserUidCnt, formInfo.formUserUids.size()); + // databse info updated. + std::vector formDBInfos; + FormDbCache::GetInstance().GetAllFormInfo(formDBInfos); + EXPECT_EQ(dataCnt, formDBInfos.size()); + FormDBInfo dbInfo {formDBInfos[0]}; + EXPECT_EQ(formId, dbInfo.formId); + EXPECT_EQ(formUserUidCnt, dbInfo.formUserUids.size()); + // Form host record not changed. + FormHostRecord hostRecord; + ret = FormDataMgr::GetInstance().GetFormHostRecord(formId, hostRecord); + EXPECT_TRUE(ret); + + FormDataMgr::GetInstance().DeleteFormRecord(formId); + FormDbCache::GetInstance().DeleteFormInfo(formId); + FormDataMgr::GetInstance().DeleteHostRecord(token_, formId); + + GTEST_LOG_(INFO) << "fms_form_mgr_add_form_test_003 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: AddForm Function + * FunctionPoints: FormMgr AddForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Invalid case when callertoken is nullptr. + */ +HWTEST_F(FmsFormMgrAddFormTest, AddForm_004, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_add_form_test_004 start"; + + int64_t formId = 0x0ffabcde00000000; + + FormJsInfo formJsInfo; + Want want; + want.SetParam(Constants::PARAM_FORM_HOST_BUNDLENAME_KEY, FORM_HOST_BUNDLE_NAME); + want.SetParam(Constants::PARAM_MODULE_NAME_KEY, PARAM_PROVIDER_MODULE_NAME); + want.SetParam(Constants::PARAM_FORM_NAME_KEY, PARAM_FORM_NAME); + want.SetParam(Constants::PARAM_FORM_DIMENSION_KEY, PARAM_FORM_DIMENSION_VALUE); + want.SetElementName(DEVICE_ID, FORM_PROVIDER_BUNDLE_NAME, FORM_PROVIDER_ABILITY_NAME); + want.SetParam(Constants::PARAM_FORM_TEMPORARY_KEY, false); + want.SetParam(Constants::ACQUIRE_TYPE, Constants::ACQUIRE_TYPE_CREATE_FORM); + + EXPECT_EQ(ERR_APPEXECFWK_FORM_INVALID_PARAM, FormMgr::GetInstance().AddForm(formId, want, nullptr, formJsInfo)); + + GTEST_LOG_(INFO) << "fms_form_mgr_add_form_test_004 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: AddForm Function + * FunctionPoints: FormMgr AddForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: BundleName,AbilityName,moduleName in Want is null separately. + */ +HWTEST_F(FmsFormMgrAddFormTest, AddForm_005, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_add_form_test_005 start"; + + int64_t formId = 0x0ffabcdd00000000; + FormJsInfo formJsInfo; + Want want; + want.SetParam(Constants::PARAM_FORM_HOST_BUNDLENAME_KEY, FORM_HOST_BUNDLE_NAME); + want.SetParam(Constants::PARAM_MODULE_NAME_KEY, PARAM_PROVIDER_MODULE_NAME); + want.SetParam(Constants::PARAM_FORM_NAME_KEY, PARAM_FORM_NAME); + want.SetParam(Constants::PARAM_FORM_DIMENSION_KEY, PARAM_FORM_DIMENSION_VALUE); + want.SetElementName(DEVICE_ID, "", FORM_PROVIDER_ABILITY_NAME); + want.SetParam(Constants::PARAM_FORM_TEMPORARY_KEY, false); + want.SetParam(Constants::ACQUIRE_TYPE, Constants::ACQUIRE_TYPE_CREATE_FORM); + EXPECT_EQ(ERR_APPEXECFWK_FORM_INVALID_PARAM, FormMgr::GetInstance().AddForm(formId, want, nullptr, formJsInfo)); + + want.SetElementName(DEVICE_ID, FORM_PROVIDER_BUNDLE_NAME, ""); + EXPECT_EQ(ERR_APPEXECFWK_FORM_INVALID_PARAM, FormMgr::GetInstance().AddForm(formId, want, nullptr, formJsInfo)); + + want.SetElementName(DEVICE_ID, FORM_PROVIDER_BUNDLE_NAME, FORM_PROVIDER_ABILITY_NAME); + std::string tmp = ""; + want.SetParam(Constants::PARAM_MODULE_NAME_KEY, tmp); + EXPECT_EQ(ERR_APPEXECFWK_FORM_INVALID_PARAM, FormMgr::GetInstance().AddForm(formId, want, nullptr, formJsInfo)); + + GTEST_LOG_(INFO) << "fms_form_mgr_add_form_test_005 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: AddForm Function + * FunctionPoints: FormMgr AddForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Case when cache info is not matched with form. + */ +HWTEST_F(FmsFormMgrAddFormTest, AddForm_006, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_add_form_test_006 start"; + + int64_t formId = 0x0ababcff00000000; + int callingUid {0}; + // Set cache info . + FormItemInfo record1; + record1.SetFormId(formId); + record1.SetProviderBundleName(FORM_PROVIDER_ABILITY_NAME); + record1.SetModuleName(PARAM_FORM_NAME); + record1.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + record1.SetFormName(PARAM_FORM_NAME); + record1.SetSpecificationId(PARAM_FORM_DIMENSION_VALUE); + record1.SetTemporaryFlag(false); + FormRecord retFormRec = FormDataMgr::GetInstance().AllotFormRecord(record1, callingUid); + // Set database info. + FormDBInfo formDBInfo(formId, retFormRec); + FormDbCache::GetInstance().SaveFormInfo(formDBInfo); + // Set form host record. + FormItemInfo info; + FormDataMgr::GetInstance().AllotFormHostRecord(info, token_, 111L, callingUid); + + FormJsInfo formJsInfo; + Want want; + want.SetParam(Constants::PARAM_FORM_HOST_BUNDLENAME_KEY, FORM_HOST_BUNDLE_NAME); + want.SetParam(Constants::PARAM_MODULE_NAME_KEY, PARAM_PROVIDER_MODULE_NAME); + want.SetParam(Constants::PARAM_FORM_NAME_KEY, PARAM_FORM_NAME); + want.SetParam(Constants::PARAM_FORM_DIMENSION_KEY, PARAM_FORM_DIMENSION_VALUE); + want.SetElementName(DEVICE_ID, FORM_PROVIDER_BUNDLE_NAME, FORM_PROVIDER_ABILITY_NAME); + want.SetParam(Constants::PARAM_FORM_TEMPORARY_KEY, false); + want.SetParam(Constants::ACQUIRE_TYPE, Constants::ACQUIRE_TYPE_CREATE_FORM); + + GTEST_LOG_(INFO) << "formId :"<Wait(); + + FormDataMgr::GetInstance().DeleteFormRecord(formId); + FormDbCache::GetInstance().DeleteFormInfo(formId); + FormDataMgr::GetInstance().DeleteHostRecord(token_, formId); + + GTEST_LOG_(INFO) << "fms_form_mgr_add_form_test_006 end"; +} +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: AddForm Function + * FunctionPoints: FormMgr AddForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Case when temp form is out of limit. + */ +HWTEST_F(FmsFormMgrAddFormTest, AddForm_007, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_add_form_test_007 start"; + + int64_t formId = 0x0ababc5f00000000; + int callingUid {0}, tempCount = 0; + // Set cache info . + FormItemInfo record1[OHOS::AppExecFwk::Constants::MAX_TEMP_FORMS]; + for (; tempCountWait(); + + FormDataMgr::GetInstance().DeleteFormRecord(formId); + FormDbCache::GetInstance().DeleteFormInfo(formId); + FormDataMgr::GetInstance().DeleteHostRecord(token_, formId); + + for (tempCount = 0; tempCountWait(); + + FormDataMgr::GetInstance().DeleteFormRecord(formId); + FormDbCache::GetInstance().DeleteFormInfo(formId); + FormDataMgr::GetInstance().DeleteHostRecord(token_, formId); + + for (tempCount = 0; tempCount +#include "form_ams_helper.h" +#include "form_bms_helper.h" +#include "form_data_mgr.h" +#include "form_db_cache.h" +#include "form_host_interface.h" +#define private public +#include "form_mgr.h" +#undef private +#include "form_mgr_service.h" +#include "if_system_ability_manager.h" +#include "inner_bundle_info.h" +#include "ipc_skeleton.h" +#include "iservice_registry.h" + +#include "mock_ability_manager.h" +#include "mock_bundle_manager.h" +#include "mock_form_host_client.h" +#include "permission/permission.h" +#include "permission/permission_kit.h" +#include "running_process_info.h" +#include "system_ability_definition.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; +using namespace OHOS::Security; + +namespace { +const std::string PERMISSION_NAME_REQUIRE_FORM = "ohos.permission.REQUIRE_FORM"; +const std::string PARAM_PROVIDER_PACKAGE_NAME = "com.form.provider.app.test.abiliy"; +const std::string FORM_PROVIDER_BUNDLE_NAME = "com.form.provider.service"; +const std::string PARAM_PROVIDER_MODULE_NAME = "com.form.provider.app.test.abiliy"; +const std::string FORM_PROVIDER_ABILITY_NAME = "com.form.provider.app.test.abiliy"; +const std::string PARAM_FORM_NAME = "com.form.name.test"; + +const std::string FORM_JS_COMPOMENT_NAME = "jsComponentName"; +const std::string FORM_PROVIDER_MODULE_SOURCE_DIR = ""; + +const std::string FORM_HOST_BUNDLE_NAME = "com.form.host.app"; + +const int32_t PARAM_FORM_DIMENSION_VALUE = 1; + +const std::string DEVICE_ID = "ohos-phone1"; +const std::string DEF_LABEL1 = "PermissionFormRequireGrant"; + +class FmsFormMgrCastTempFormTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + +protected: + sptr token_; + std::shared_ptr formyMgrServ_ = DelayedSingleton::GetInstance(); + + sptr mockBundleMgr_; + sptr mockAbilityMgrServ_; +}; + +void FmsFormMgrCastTempFormTest::SetUpTestCase() +{} + +void FmsFormMgrCastTempFormTest::TearDownTestCase() +{} + +void FmsFormMgrCastTempFormTest::SetUp() +{ + formyMgrServ_->OnStart(); + + mockBundleMgr_ = new (std::nothrow) BundleMgrService(); + ASSERT_TRUE(mockBundleMgr_ != nullptr); + FormBmsHelper::GetInstance().SetBundleManager(mockBundleMgr_); + + mockAbilityMgrServ_ = new (std::nothrow) MockAbilityMgrService(); + FormAmsHelper::GetInstance().SetAbilityManager(mockAbilityMgrServ_); + + token_ = new (std::nothrow) MockFormHostClient(); + + // Permission install + std::vector permList; + Permission::PermissionDef permDef; + permDef.permissionName = PERMISSION_NAME_REQUIRE_FORM; + permDef.bundleName = FORM_PROVIDER_BUNDLE_NAME; + permDef.grantMode = Permission::GrantMode::USER_GRANT; + permDef.availableScope = Permission::AvailableScope::AVAILABLE_SCOPE_ALL; + permDef.label = DEF_LABEL1; + permDef.labelId = 1; + permDef.description = DEF_LABEL1; + permDef.descriptionId = 1; + permList.emplace_back(permDef); + Permission::PermissionKit::AddDefPermissions(permList); + Permission::PermissionKit::AddUserGrantedReqPermissions(FORM_PROVIDER_BUNDLE_NAME, {PERMISSION_NAME_REQUIRE_FORM}, + 0); + Permission::PermissionKit::GrantUserGrantedPermission(FORM_PROVIDER_BUNDLE_NAME, PERMISSION_NAME_REQUIRE_FORM, 0); +} + +void FmsFormMgrCastTempFormTest::TearDown() +{} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: CastTempForm Function + * FunctionPoints: FormMgr CastTempForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if FormMgr invoke CastTempForm works. + */ +HWTEST_F(FmsFormMgrCastTempFormTest, CastTempForm_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_cast_temp_form_test_001 start"; + + int64_t formId {FormDataMgr::GetInstance().GenerateFormId()}; + int callingUid {1}; + // cache info + FormItemInfo record1; + record1.SetFormId(formId); + record1.SetProviderBundleName(FORM_PROVIDER_BUNDLE_NAME); + record1.SetModuleName(PARAM_FORM_NAME); + record1.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + record1.SetFormName(PARAM_FORM_NAME); + record1.SetSpecificationId(PARAM_FORM_DIMENSION_VALUE); + record1.SetTemporaryFlag(true); + FormRecord retFormRec = FormDataMgr::GetInstance().AllotFormRecord(record1, callingUid); + // host object + FormItemInfo info; + FormDataMgr::GetInstance().AllotFormHostRecord(info, token_, formId, callingUid); + + ASSERT_EQ(ERR_OK, FormMgr::GetInstance().CastTempForm(formId, token_)); + token_->Wait(); + + size_t dataCnt {1}; + // form record is updated + FormRecord formInfo; + bool ret = FormDataMgr::GetInstance().GetFormRecord(formId, formInfo); + EXPECT_TRUE(ret); + size_t userUidCnt {2}; + EXPECT_EQ(userUidCnt, formInfo.formUserUids.size()); + // db data is added + std::vector formDBInfos; + FormDbCache::GetInstance().GetAllFormInfo(formDBInfos); + EXPECT_EQ(dataCnt, formDBInfos.size()); + FormDBInfo dbInfo {formDBInfos[0]}; + EXPECT_EQ(formId, dbInfo.formId); + EXPECT_EQ(userUidCnt, dbInfo.formUserUids.size()); + // host is added + FormHostRecord hostRecord; + ret = FormDataMgr::GetInstance().GetFormHostRecord(formId, hostRecord); + EXPECT_TRUE(ret); + + FormDataMgr::GetInstance().DeleteFormRecord(formId); + FormDbCache::GetInstance().DeleteFormInfo(formId); + FormDataMgr::GetInstance().DeleteHostRecord(token_, formId); + GTEST_LOG_(INFO) << "fms_form_mgr_cast_temp_form_test_001 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: CastTempForm Function + * FunctionPoints: FormMgr CastTempForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: form id <= 0 or Caller ability token is nullptr. + */ +HWTEST_F(FmsFormMgrCastTempFormTest, CastTempForm_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_cast_temp_form_test_002 start"; + // form id <= 0 + ASSERT_EQ(ERR_FORM_INVALID_PARAM, FormMgr::GetInstance().CastTempForm(0L, token_)); + // Caller ability token is nullptr + int64_t formId {FormDataMgr::GetInstance().GenerateFormId()}; + ASSERT_EQ(ERR_FORM_INVALID_PARAM, FormMgr::GetInstance().CastTempForm(formId, nullptr)); + GTEST_LOG_(INFO) << "fms_form_mgr_cast_temp_form_test_002 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: CastTempForm Function + * FunctionPoints: FormMgr CastTempForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Temp form is not in form cache. + */ +HWTEST_F(FmsFormMgrCastTempFormTest, CastTempForm_003, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_cast_temp_form_test_003 start"; + int64_t formId {FormDataMgr::GetInstance().GenerateFormId()}; + // form is not exist in cache + ASSERT_EQ(ERR_NOT_EXIST_ID, FormMgr::GetInstance().CastTempForm(formId, token_)); + GTEST_LOG_(INFO) << "fms_form_mgr_cast_temp_form_test_003 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: CastTempForm Function + * FunctionPoints: FormMgr CastTempForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Temp form is not in host. + */ +HWTEST_F(FmsFormMgrCastTempFormTest, CastTempForm_004, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_cast_temp_form_test_004 start"; + + int64_t formId {FormDataMgr::GetInstance().GenerateFormId()}; + int callingUid {1}; + // cache data + FormItemInfo record1; + record1.SetFormId(formId); + record1.SetProviderBundleName(FORM_PROVIDER_BUNDLE_NAME); + record1.SetModuleName(PARAM_FORM_NAME); + record1.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + record1.SetFormName(PARAM_FORM_NAME); + record1.SetSpecificationId(PARAM_FORM_DIMENSION_VALUE); + record1.SetTemporaryFlag(true); + FormRecord retFormRec = FormDataMgr::GetInstance().AllotFormRecord(record1, callingUid); + + ASSERT_EQ(ERR_OPERATION_FORM_NOT_SELF, FormMgr::GetInstance().CastTempForm(formId, token_)); + + FormDataMgr::GetInstance().DeleteFormRecord(formId); + FormDbCache::GetInstance().DeleteFormInfo(formId); + FormDataMgr::GetInstance().DeleteHostRecord(token_, formId); + GTEST_LOG_(INFO) << "fms_form_mgr_cast_temp_form_test_004 end"; +} +} diff --git a/services/formmgr/test/unittest/fms_form_mgr_death_callback_test/BUILD.gn b/services/formmgr/test/unittest/fms_form_mgr_death_callback_test/BUILD.gn new file mode 100644 index 0000000000..35100ba0d2 --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_mgr_death_callback_test/BUILD.gn @@ -0,0 +1,17 @@ +# Copyright (c) 2021 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/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/formmgrservice" diff --git a/services/formmgr/test/unittest/fms_form_mgr_death_callback_test/fms_form_mgr_death_callback_test.cpp b/services/formmgr/test/unittest/fms_form_mgr_death_callback_test/fms_form_mgr_death_callback_test.cpp new file mode 100644 index 0000000000..e18f830ad2 --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_mgr_death_callback_test/fms_form_mgr_death_callback_test.cpp @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2021 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 "form_ams_helper.h" +#include "form_bms_helper.h" +#define private public +#include "form_data_mgr.h" +#undef private +#include "form_db_cache.h" +#include "form_host_interface.h" +#define private public +#include "form_mgr.h" +#undef private +#include "form_mgr_service.h" +#include "if_system_ability_manager.h" +#include "inner_bundle_info.h" +#include "ipc_skeleton.h" +#include "iservice_registry.h" + +#include "mock_ability_manager.h" +#include "mock_bundle_manager.h" +#include "mock_form_death_callback.h" +#include "mock_form_host_client.h" +#include "permission/permission.h" +#include "permission/permission_kit.h" +#include "running_process_info.h" +#include "system_ability_definition.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; +using namespace OHOS::Security; + +namespace { +const std::string PERMISSION_NAME_REQUIRE_FORM = "ohos.permission.REQUIRE_FORM"; +const std::string PARAM_PROVIDER_PACKAGE_NAME = "com.form.provider.app.test.abiliy"; +const std::string FORM_PROVIDER_BUNDLE_NAME = "com.form.provider.service"; +const std::string PARAM_PROVIDER_MODULE_NAME = "com.form.provider.app.test.abiliy"; +const std::string FORM_PROVIDER_ABILITY_NAME = "com.form.provider.app.test.abiliy"; +const std::string PARAM_FORM_NAME = "com.form.name.test"; + +const std::string FORM_JS_COMPOMENT_NAME = "jsComponentName"; +const std::string FORM_PROVIDER_MODULE_SOURCE_DIR = ""; + +const std::string FORM_HOST_BUNDLE_NAME = "com.form.host.app"; + +const int32_t PARAM_FORM_DIMENSION_VALUE = 1; + +const std::string DEVICE_ID = "ohos-phone1"; +const std::string DEF_LABEL1 = "PermissionFormRequireGrant"; + +class FmsFormMgrDeathCallbackTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + +protected: + sptr token_; + std::shared_ptr formyMgrServ_ = DelayedSingleton::GetInstance(); + + sptr mockBundleMgr_; + sptr mockAbilityMgrServ_; +}; + +void FmsFormMgrDeathCallbackTest::SetUpTestCase() +{} + +void FmsFormMgrDeathCallbackTest::TearDownTestCase() +{} + +void FmsFormMgrDeathCallbackTest::SetUp() +{ + // APP_LOGI("fms_form_mgr_client_test_001 setup"); + formyMgrServ_->OnStart(); + + mockBundleMgr_ = new (std::nothrow) BundleMgrService(); + EXPECT_TRUE(mockBundleMgr_ != nullptr); + FormBmsHelper::GetInstance().SetBundleManager(mockBundleMgr_); + + mockAbilityMgrServ_ = new (std::nothrow) MockAbilityMgrService(); + FormAmsHelper::GetInstance().SetAbilityManager(mockAbilityMgrServ_); + + // APP_LOGI("fms_form_mgr_client_test_001 FormMgrService started"); + token_ = new (std::nothrow) MockFormHostClient(); + + // Permission install + std::vector permList; + Permission::PermissionDef permDef; + permDef.permissionName = PERMISSION_NAME_REQUIRE_FORM; + permDef.bundleName = FORM_PROVIDER_BUNDLE_NAME; + permDef.grantMode = Permission::GrantMode::USER_GRANT; + permDef.availableScope = Permission::AvailableScope::AVAILABLE_SCOPE_ALL; + permDef.label = DEF_LABEL1; + permDef.labelId = 1; + permDef.description = DEF_LABEL1; + permDef.descriptionId = 1; + permList.emplace_back(permDef); + Permission::PermissionKit::AddDefPermissions(permList); + Permission::PermissionKit::AddUserGrantedReqPermissions(FORM_PROVIDER_BUNDLE_NAME, {PERMISSION_NAME_REQUIRE_FORM}, + 0); + Permission::PermissionKit::GrantUserGrantedPermission(FORM_PROVIDER_BUNDLE_NAME, PERMISSION_NAME_REQUIRE_FORM, 0); +} + +void FmsFormMgrDeathCallbackTest::TearDown() +{} + +/* + * Feature: FormMgrService + * Function: FormMgr::FormMgrDeathRecipient + * SubFunction: OnRemoteDied Function + * FunctionPoints: FormMgr::FormMgrDeathRecipient OnRemoteDied interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if FormMgr::FormMgrDeathRecipient invoke OnRemoteDied works. + */ +HWTEST_F(FmsFormMgrDeathCallbackTest, OnRemoteDied_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_death_callback_test_001 start"; + // No cache + FormJsInfo formJsInfo; + Want want; + want.SetParam(Constants::PARAM_FORM_HOST_BUNDLENAME_KEY, FORM_HOST_BUNDLE_NAME) + .SetParam(Constants::PARAM_MODULE_NAME_KEY, PARAM_PROVIDER_MODULE_NAME) + .SetParam(Constants::PARAM_FORM_NAME_KEY, PARAM_FORM_NAME) + .SetParam(Constants::PARAM_FORM_DIMENSION_KEY, PARAM_FORM_DIMENSION_VALUE) + .SetElementName(DEVICE_ID, FORM_PROVIDER_BUNDLE_NAME, FORM_PROVIDER_ABILITY_NAME) + .SetParam(Constants::PARAM_FORM_TEMPORARY_KEY, false) + .SetParam(Constants::ACQUIRE_TYPE, Constants::ACQUIRE_TYPE_CREATE_FORM); + + EXPECT_EQ(ERR_OK, FormMgr::GetInstance().AddForm(0L, want, token_, formJsInfo)); + token_->Wait(); + + std::shared_ptr deathCallback = std::make_shared(); + FormMgr::GetInstance().RegisterDeathCallback(deathCallback); + EXPECT_EQ(true, FormMgr::GetInstance().CheckIsDeathCallbackRegistered(deathCallback)); + FormMgr::GetInstance().GetDeathRecipient()->OnRemoteDied(formyMgrServ_->AsObject()); + + int64_t formId = formJsInfo.formId; + + FormHostRecord hostRecord; + EXPECT_EQ(true, FormDataMgr::GetInstance().GetFormHostRecord(formId, hostRecord)); + EXPECT_EQ(true, token_->AsObject() == hostRecord.clientStub_); + EXPECT_EQ(true, FormMgr::GetRecoverStatus() == Constants::NOT_IN_RECOVERY); + + FormMgr::GetInstance().UnRegisterDeathCallback(deathCallback); + EXPECT_EQ(false, FormMgr::GetInstance().CheckIsDeathCallbackRegistered(deathCallback)); + + FormDataMgr::GetInstance().DeleteFormRecord(formId); + FormDbCache::GetInstance().DeleteFormInfo(formId); + FormDataMgr::GetInstance().DeleteHostRecord(token_, formId); + + GTEST_LOG_(INFO) << "fms_form_mgr_death_callback_test_001 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr::FormMgrDeathRecipient + * SubFunction: OnRemoteDied Function + * FunctionPoints: FormMgr::FormMgrDeathRecipient OnRemoteDied interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if FormMgr::FormMgrDeathRecipient invoke OnRemoteDied works when remote is nullptr. + */ +HWTEST_F(FmsFormMgrDeathCallbackTest, OnRemoteDied_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_death_callback_test_002 start"; + // No cache + FormJsInfo formJsInfo; + Want want; + want.SetParam(Constants::PARAM_FORM_HOST_BUNDLENAME_KEY, FORM_HOST_BUNDLE_NAME) + .SetParam(Constants::PARAM_MODULE_NAME_KEY, PARAM_PROVIDER_MODULE_NAME) + .SetParam(Constants::PARAM_FORM_NAME_KEY, PARAM_FORM_NAME) + .SetParam(Constants::PARAM_FORM_DIMENSION_KEY, PARAM_FORM_DIMENSION_VALUE) + .SetElementName(DEVICE_ID, FORM_PROVIDER_BUNDLE_NAME, FORM_PROVIDER_ABILITY_NAME) + .SetParam(Constants::PARAM_FORM_TEMPORARY_KEY, false) + .SetParam(Constants::ACQUIRE_TYPE, Constants::ACQUIRE_TYPE_CREATE_FORM); + + EXPECT_EQ(ERR_OK, FormMgr::GetInstance().AddForm(0L, want, token_, formJsInfo)); + token_->Wait(); + + std::shared_ptr deathCallback = std::make_shared(); + FormMgr::GetInstance().RegisterDeathCallback(deathCallback); + EXPECT_EQ(true, FormMgr::GetInstance().CheckIsDeathCallbackRegistered(deathCallback)); + + int beforeRecoverStatus = FormMgr::GetRecoverStatus(); + FormMgr::GetInstance().GetDeathRecipient()->OnRemoteDied(nullptr); + EXPECT_EQ(true, FormMgr::GetRecoverStatus() == beforeRecoverStatus); + + int64_t formId = formJsInfo.formId; + FormDataMgr::GetInstance().DeleteFormRecord(formId); + FormDbCache::GetInstance().DeleteFormInfo(formId); + FormDataMgr::GetInstance().DeleteHostRecord(token_, formId); + + GTEST_LOG_(INFO) << "fms_form_mgr_death_callback_test_002 end"; +} +} \ No newline at end of file diff --git a/services/formmgr/test/unittest/fms_form_mgr_delete_form_test/BUILD.gn b/services/formmgr/test/unittest/fms_form_mgr_delete_form_test/BUILD.gn new file mode 100644 index 0000000000..e20b99a0fa --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_mgr_delete_form_test/BUILD.gn @@ -0,0 +1,86 @@ +# Copyright (c) 2021 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/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/formmgrservice" + +ohos_unittest("FmsFormMgrDeleteFormTest") { + module_out_path = module_output_path + + sources = [ + "//foundation/appexecfwk/standard/interfaces/innerkits/fmskit/native/src/form_mgr.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_bundle_manager.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_form_host_client.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_form_provider_client.cpp", + ] + sources += [ "fms_form_mgr_delete_form_test.cpp" ] + + include_dirs = [ + "//third_party/zlib/contrib/minizip", + "//third_party/zlib", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/fmskit/native/include/", + "//foundation/appexecfwk/standard/common/log/include/", + "//foundation/appexecfwk/standard/services/formmgr/include", + "//foundation/appexecfwk/standard/services/bundlemgr/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base/include/", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/formmgr/", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include/", + "//foundation/distributedschedule/samgr/adapter/interfaces/innerkits/include/", + ] + + configs = [ + "${services_path}/formmgr/test:formmgr_test_config", + "//foundation/aafwk/standard/services/abilitymgr:abilityms_config", + + # "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:bundlemgr_sdk_config", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:formmgr_sdk_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/common:libappexecfwk_common", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${appexecfwk_path}/interfaces/innerkits/fmskit:fmskit_native", + "${libs_path}/libeventhandler:libeventhandler_target", + "${services_path}/formmgr:fms_target", + "//base/security/permission/interfaces/innerkits/permission_standard/permissionsdk:libpermissionsdk_standard", + "//base/startup/appspawn_standard:appspawn_socket_client", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + + #"${services_path}/bundlemgr:bms_target", + "//foundation/aafwk/standard/services/abilitymgr:abilityms_target", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/googletest:gmock_main", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":FmsFormMgrDeleteFormTest" ] +} diff --git a/services/formmgr/test/unittest/fms_form_mgr_delete_form_test/fms_form_mgr_delete_form_test.cpp b/services/formmgr/test/unittest/fms_form_mgr_delete_form_test/fms_form_mgr_delete_form_test.cpp new file mode 100644 index 0000000000..05bc3c5e86 --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_mgr_delete_form_test/fms_form_mgr_delete_form_test.cpp @@ -0,0 +1,465 @@ +/* + * Copyright (c) 2021 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 "form_ams_helper.h" +#include "form_bms_helper.h" +#include "form_data_mgr.h" +#include "form_db_cache.h" +#include "form_host_interface.h" +#define private public +#include "form_mgr.h" +#undef private +#include "form_mgr_service.h" +#include "if_system_ability_manager.h" +#include "inner_bundle_info.h" +#include "ipc_skeleton.h" +#include "iservice_registry.h" + +#include "mock_ability_manager.h" +#include "mock_bundle_manager.h" +#include "mock_form_host_client.h" +#include "permission/permission.h" +#include "permission/permission_kit.h" +#include "running_process_info.h" +#include "system_ability_definition.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; +using namespace OHOS::Security; + +namespace { +const std::string PERMISSION_NAME_REQUIRE_FORM = "ohos.permission.REQUIRE_FORM"; +const std::string PARAM_PROVIDER_PACKAGE_NAME = "com.form.provider.app.test.abiliy"; +const std::string FORM_PROVIDER_BUNDLE_NAME = "com.form.provider.service"; +const std::string PARAM_PROVIDER_MODULE_NAME = "com.form.provider.app.test.abiliy"; +const std::string FORM_PROVIDER_ABILITY_NAME = "com.form.provider.app.test.abiliy"; +const std::string PARAM_FORM_NAME = "com.form.name.test"; + +const std::string FORM_JS_COMPOMENT_NAME = "jsComponentName"; +const std::string FORM_PROVIDER_MODULE_SOURCE_DIR = ""; + +const std::string FORM_HOST_BUNDLE_NAME = "com.form.host.app"; + +const std::string DEVICE_ID = "ohos-phone1"; +const std::string DEF_LABEL1 = "PermissionFormRequireGrant"; + +class FmsFormMgrDeleteFormTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + +protected: + sptr token_; + std::shared_ptr formyMgrServ_ = DelayedSingleton::GetInstance(); + + sptr mockBundleMgr_; + sptr mockAbilityMgrServ_; +}; + +void FmsFormMgrDeleteFormTest::SetUpTestCase() +{} + +void FmsFormMgrDeleteFormTest::TearDownTestCase() +{} + +void FmsFormMgrDeleteFormTest::SetUp() +{ + formyMgrServ_->OnStart(); + + mockBundleMgr_ = new (std::nothrow) BundleMgrService(); + EXPECT_TRUE(mockBundleMgr_ != nullptr); + FormBmsHelper::GetInstance().SetBundleManager(mockBundleMgr_); + + mockAbilityMgrServ_ = new (std::nothrow) MockAbilityMgrService(); + FormAmsHelper::GetInstance().SetAbilityManager(mockAbilityMgrServ_); + + token_ = new (std::nothrow) MockFormHostClient(); + + // Permission install + std::vector permList; + Permission::PermissionDef permDef; + permDef.permissionName = PERMISSION_NAME_REQUIRE_FORM; + permDef.bundleName = FORM_PROVIDER_BUNDLE_NAME; + permDef.grantMode = Permission::GrantMode::USER_GRANT; + permDef.availableScope = Permission::AvailableScope::AVAILABLE_SCOPE_ALL; + permDef.label = DEF_LABEL1; + permDef.labelId = 1; + permDef.description = DEF_LABEL1; + permDef.descriptionId = 1; + permList.emplace_back(permDef); + Permission::PermissionKit::AddDefPermissions(permList); + Permission::PermissionKit::AddUserGrantedReqPermissions(FORM_PROVIDER_BUNDLE_NAME, {PERMISSION_NAME_REQUIRE_FORM}, + 0); + Permission::PermissionKit::GrantUserGrantedPermission(FORM_PROVIDER_BUNDLE_NAME, PERMISSION_NAME_REQUIRE_FORM, 0); +} + +void FmsFormMgrDeleteFormTest::TearDown() +{} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: DeleteForm Function + * FunctionPoints: FormMgr DeleteForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Quote of form is not 0 after delete form. + */ +HWTEST_F(FmsFormMgrDeleteFormTest, DeleteForm_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_delete_form_test_001 start"; + + int64_t formId {12001}; + int callingUid {0}; + // Create cache + FormItemInfo record1; + record1.SetFormId(formId); + record1.SetProviderBundleName(FORM_HOST_BUNDLE_NAME); + record1.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + record1.SetTemporaryFlag(false); + FormRecord retFormRec = FormDataMgr::GetInstance().AllotFormRecord(record1, callingUid); + // User Uid Add some Useruids into a form in cache + int formUserUid {1}; + FormDataMgr::GetInstance().AddFormUserUid(formId, formUserUid); + // Set form host record + retFormRec.formUserUids.emplace_back(formUserUid); + FormDBInfo formDBInfo(formId, retFormRec); + FormDbCache::GetInstance().SaveFormInfo(formDBInfo); + // Set host record + FormItemInfo info; + FormDataMgr::GetInstance().AllotFormHostRecord(info, token_, formId, callingUid); + + EXPECT_EQ(ERR_OK, FormMgr::GetInstance().DeleteForm(formId, token_)); + token_->Wait(); + + // Cache uid is not deleted yet. + FormRecord formInfo; + bool ret = FormDataMgr::GetInstance().GetFormRecord(formId, formInfo); + EXPECT_TRUE(ret); + size_t dataCnt{1}; + EXPECT_EQ(dataCnt, formInfo.formUserUids.size()); + // Database is not deleted yet. + std::vector formDBInfos; + FormDbCache::GetInstance().GetAllFormInfo(formDBInfos); + EXPECT_EQ(dataCnt, formDBInfos.size()); + FormDBInfo dbInfo {formDBInfos[0]}; + EXPECT_EQ(formId, dbInfo.formId); + EXPECT_EQ(dataCnt, dbInfo.formUserUids.size()); + // Form host record is deleted. + FormHostRecord hostRecord; + EXPECT_FALSE(FormDataMgr::GetInstance().GetFormHostRecord(formId, hostRecord)); + + FormDataMgr::GetInstance().DeleteFormRecord(formId); + FormDbCache::GetInstance().DeleteFormInfo(formId); + FormDataMgr::GetInstance().DeleteHostRecord(token_, formId); + GTEST_LOG_(INFO) << "fms_form_mgr_delete_form_test_001 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: DeleteForm Function + * FunctionPoints: FormMgr DeleteForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Quote of form is 0 after delete form. + */ +HWTEST_F(FmsFormMgrDeleteFormTest, DeleteForm_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_delete_form_test_002 start"; + + int64_t formId {12002}; + int callingUid {0}; + // Create cache + FormItemInfo record1; + record1.SetFormId(formId); + record1.SetProviderBundleName(FORM_PROVIDER_BUNDLE_NAME); + record1.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + record1.SetTemporaryFlag(false); + FormRecord retFormRec = FormDataMgr::GetInstance().AllotFormRecord(record1, callingUid); + // User Uid Add some Useruids into a form in cache + FormDBInfo formDBInfo(formId, retFormRec); + FormDbCache::GetInstance().SaveFormInfo(formDBInfo); + // Set form host record + FormItemInfo info; + FormDataMgr::GetInstance().AllotFormHostRecord(info, token_, formId, callingUid); + + EXPECT_EQ(ERR_OK, FormMgr::GetInstance().DeleteForm(formId, token_)); + token_->Wait(); + + // Cache uid is deleted. + FormRecord formInfo; + bool ret = FormDataMgr::GetInstance().GetFormRecord(formId, formInfo); + EXPECT_FALSE(ret); + // Database is deleted. + size_t dataCnt{0}; + std::vector formDBInfos; + FormDbCache::GetInstance().GetAllFormInfo(formDBInfos); + EXPECT_EQ(dataCnt, formDBInfos.size()); + // Form host record is deleted. + FormHostRecord hostRecord; + EXPECT_FALSE(FormDataMgr::GetInstance().GetFormHostRecord(formId, hostRecord)); + + FormDataMgr::GetInstance().DeleteFormRecord(formId); + FormDbCache::GetInstance().DeleteFormInfo(formId); + FormDataMgr::GetInstance().DeleteHostRecord(token_, formId); + GTEST_LOG_(INFO) << "fms_form_mgr_delete_form_test_002 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: DeleteForm Function + * FunctionPoints: FormMgr DeleteForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Test cases when some paraments are invalid + */ +HWTEST_F(FmsFormMgrDeleteFormTest, DeleteForm_003, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_delete_form_test_003 start"; + // case when formId<=0 + EXPECT_EQ(ERR_FORM_INVALID_PARAM, FormMgr::GetInstance().DeleteForm(0, token_)); + // case when token is nullptr + EXPECT_EQ(ERR_FORM_INVALID_PARAM, FormMgr::GetInstance().DeleteForm(123L, nullptr)); + GTEST_LOG_(INFO) << "fms_form_mgr_delete_form_test_003 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: DeleteForm Function + * FunctionPoints: FormMgr DeleteForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: An exception tests if check permission error. + */ +HWTEST_F(FmsFormMgrDeleteFormTest, DeleteForm_004, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_delete_form_test_004 start"; + int64_t formId {12004}; + // Remove Permission + OHOS::Security::Permission::PermissionKit::RemoveDefPermissions(FORM_PROVIDER_BUNDLE_NAME); + OHOS::Security::Permission::PermissionKit::RemoveUserGrantedReqPermissions(FORM_PROVIDER_BUNDLE_NAME, 0); + OHOS::Security::Permission::PermissionKit::RemoveSystemGrantedReqPermissions(FORM_PROVIDER_BUNDLE_NAME); + EXPECT_EQ(ERR_APPEXECFWK_FORM_PERMISSION_DENY, FormMgr::GetInstance().DeleteForm(formId, token_)); + // Permission install + std::vector permList; + Permission::PermissionDef permDef; + permDef.permissionName = PERMISSION_NAME_REQUIRE_FORM; + permDef.bundleName = FORM_PROVIDER_BUNDLE_NAME; + permDef.grantMode = Permission::GrantMode::USER_GRANT; + permDef.availableScope = Permission::AvailableScope::AVAILABLE_SCOPE_ALL; + permDef.label = DEF_LABEL1; + permDef.labelId = 1; + permDef.description = DEF_LABEL1; + permDef.descriptionId = 1; + permList.emplace_back(permDef); + Permission::PermissionKit::AddDefPermissions(permList); + Permission::PermissionKit::AddUserGrantedReqPermissions(FORM_PROVIDER_BUNDLE_NAME, {PERMISSION_NAME_REQUIRE_FORM}, + 0); + Permission::PermissionKit::GrantUserGrantedPermission(FORM_PROVIDER_BUNDLE_NAME, PERMISSION_NAME_REQUIRE_FORM, 0); + GTEST_LOG_(INFO) << "fms_form_mgr_delete_form_test_004 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: DeleteForm Function + * FunctionPoints: FormMgr DeleteForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Cases when permission is not available + */ +HWTEST_F(FmsFormMgrDeleteFormTest, DeleteForm_005, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_delete_form_test_005 start"; + int64_t formId {12005}; + int callingUid {0}; + FormItemInfo record1; + record1.SetFormId(formId); + record1.SetProviderBundleName("ERR BUNDLE NAME"); + record1.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + record1.SetTemporaryFlag(false); + FormDataMgr::GetInstance().AllotFormRecord(record1, callingUid); + Permission::PermissionKit::RemoveDefPermissions(FORM_PROVIDER_BUNDLE_NAME); + EXPECT_EQ(ERR_APPEXECFWK_FORM_PERMISSION_DENY, FormMgr::GetInstance().DeleteForm(formId, token_)); + FormDataMgr::GetInstance().DeleteFormRecord(formId); + FormDbCache::GetInstance().DeleteFormInfo(formId); + FormDataMgr::GetInstance().DeleteHostRecord(token_, formId); + GTEST_LOG_(INFO) << "fms_form_mgr_delete_form_test_005 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: DeleteForm Function + * FunctionPoints: FormMgr DeleteForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Case with no database info and form is not temporary. + */ +HWTEST_F(FmsFormMgrDeleteFormTest, DeleteForm_006, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_delete_form_test_006 start"; + + int64_t formId {12006}; + int callingUid {0}; + FormItemInfo record1; + record1.SetFormId(formId); + record1.SetProviderBundleName(FORM_HOST_BUNDLE_NAME); + record1.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + record1.SetTemporaryFlag(false); + FormDataMgr::GetInstance().AllotFormRecord(record1, callingUid); + // Set form host record + FormItemInfo info; + FormDataMgr::GetInstance().AllotFormHostRecord(info, token_, formId, callingUid); + + EXPECT_EQ(ERR_NOT_EXIST_ID, FormMgr::GetInstance().DeleteForm(formId, token_)); + + FormDataMgr::GetInstance().DeleteFormRecord(formId); + FormDbCache::GetInstance().DeleteFormInfo(formId); + FormDataMgr::GetInstance().DeleteHostRecord(token_, formId); + GTEST_LOG_(INFO) << "fms_form_mgr_delete_form_test_006 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: DeleteForm Function + * FunctionPoints: FormMgr DeleteForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Case when form with database info, not temporary form, without host record. + */ +HWTEST_F(FmsFormMgrDeleteFormTest, DeleteForm_007, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_delete_form_test_007 start"; + + int64_t formId {12007}; + int callingUid {0}; + // Create cache + FormItemInfo record1; + record1.SetFormId(formId); + record1.SetProviderBundleName(FORM_HOST_BUNDLE_NAME); + record1.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + record1.SetTemporaryFlag(false); + FormRecord retFormRec = FormDataMgr::GetInstance().AllotFormRecord(record1, callingUid); + // Set database info. + retFormRec.formUserUids.clear(); + FormDBInfo formDBInfo(formId, retFormRec); + FormDbCache::GetInstance().SaveFormInfo(formDBInfo); + // Set form host record + FormItemInfo info; + FormDataMgr::GetInstance().AllotFormHostRecord(info, token_, formId, callingUid); + + ASSERT_EQ(ERR_OPERATION_FORM_NOT_SELF, FormMgr::GetInstance().DeleteForm(formId, token_)); + + // Cache uid is not deleted yet. + FormRecord formInfo; + bool ret = FormDataMgr::GetInstance().GetFormRecord(formId, formInfo); + EXPECT_TRUE(ret); + size_t dataCnt{1}; + EXPECT_EQ(dataCnt, formInfo.formUserUids.size()); + // Database is not deleted yet. + std::vector formDBInfos; + FormDbCache::GetInstance().GetAllFormInfo(formDBInfos); + EXPECT_EQ(dataCnt, formDBInfos.size()); + FormDBInfo dbInfo {formDBInfos[0]}; + EXPECT_EQ(formId, dbInfo.formId); + dataCnt = 0; + EXPECT_EQ(dataCnt, dbInfo.formUserUids.size()); + // Form host record is not deleted. + FormHostRecord hostRecord; + EXPECT_TRUE(FormDataMgr::GetInstance().GetFormHostRecord(formId, hostRecord)); + + FormDataMgr::GetInstance().DeleteFormRecord(formId); + FormDbCache::GetInstance().DeleteFormInfo(formId); + FormDataMgr::GetInstance().DeleteHostRecord(token_, formId); + GTEST_LOG_(INFO) << "fms_form_mgr_delete_form_test_007 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: DeleteForm Function + * FunctionPoints: FormMgr DeleteForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Persistent data,abilityName or bundleName is empty. + */ +HWTEST_F(FmsFormMgrDeleteFormTest, DeleteForm_008, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_delete_form_test_008 start"; + + int64_t formId {12008}; + int callingUid {0}; + FormItemInfo record1; + record1.SetFormId(formId); + record1.SetProviderBundleName(FORM_HOST_BUNDLE_NAME); + record1.SetAbilityName(""); + record1.SetTemporaryFlag(false); + FormRecord retFormRec = FormDataMgr::GetInstance().AllotFormRecord(record1, callingUid); + // Set database info. + FormDBInfo formDBInfo(formId, retFormRec); + FormDbCache::GetInstance().SaveFormInfo(formDBInfo); + // Set form host record + FormItemInfo info; + FormDataMgr::GetInstance().AllotFormHostRecord(info, token_, formId, callingUid); + + ASSERT_EQ(ERR_CODE_COMMON, FormMgr::GetInstance().DeleteForm(formId, token_)); + + // Cache uid is not deleted yet. + FormRecord formInfo; + bool ret = FormDataMgr::GetInstance().GetFormRecord(formId, formInfo); + EXPECT_TRUE(ret); + size_t dataCnt{1}; + EXPECT_EQ(dataCnt, formInfo.formUserUids.size()); + // Database is not deleted yet. + std::vector formDBInfos; + FormDbCache::GetInstance().GetAllFormInfo(formDBInfos); + EXPECT_EQ(dataCnt, formDBInfos.size()); + FormDBInfo dbInfo {formDBInfos[0]}; + EXPECT_EQ(formId, dbInfo.formId); + EXPECT_EQ(dataCnt, dbInfo.formUserUids.size()); + // form host record is not deleted yet. + FormHostRecord hostRecord; + EXPECT_TRUE(FormDataMgr::GetInstance().GetFormHostRecord(formId, hostRecord)); + + // Database info. + FormDbCache::GetInstance().DeleteFormInfo(formId); + retFormRec.bundleName = ""; + retFormRec.abilityName = FORM_PROVIDER_ABILITY_NAME; + FormDBInfo formDBInfo1(formId, retFormRec); + FormDbCache::GetInstance().SaveFormInfo(formDBInfo1); + + EXPECT_EQ(ERR_CODE_COMMON, FormMgr::GetInstance().DeleteForm(formId, token_)); + + // Cache uid is not deleted yet. + ret = FormDataMgr::GetInstance().GetFormRecord(formId, formInfo); + EXPECT_TRUE(ret); + EXPECT_EQ(dataCnt, formInfo.formUserUids.size()); + // Database is not deleted yet. + formDBInfos.clear(); + FormDbCache::GetInstance().GetAllFormInfo(formDBInfos); + EXPECT_EQ(dataCnt, formDBInfos.size()); + dbInfo = formDBInfos[0]; + EXPECT_EQ(formId, dbInfo.formId); + EXPECT_EQ(dataCnt, dbInfo.formUserUids.size()); + // form host record is not deleted yet. + EXPECT_TRUE(FormDataMgr::GetInstance().GetFormHostRecord(formId, hostRecord)); + + FormDataMgr::GetInstance().DeleteFormRecord(formId); + FormDbCache::GetInstance().DeleteFormInfo(formId); + FormDataMgr::GetInstance().DeleteHostRecord(token_, formId); + GTEST_LOG_(INFO) << "fms_form_mgr_delete_form_test_008 end"; +} +} \ No newline at end of file diff --git a/services/formmgr/test/unittest/fms_form_mgr_lifecycle_update_test/BUILD.gn b/services/formmgr/test/unittest/fms_form_mgr_lifecycle_update_test/BUILD.gn new file mode 100644 index 0000000000..3ea0a927c2 --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_mgr_lifecycle_update_test/BUILD.gn @@ -0,0 +1,88 @@ +# Copyright (c) 2021 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/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/formmgrservice" + +ohos_unittest("FmsFormMgrLifecycleUpdateTest") { + module_out_path = module_output_path + + sources = [ + "//foundation/appexecfwk/standard/interfaces/innerkits/fmskit/native/src/form_mgr.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_bundle_manager.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_form_host_client.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/unittest/fms_form_mgr_lifecycle_update_test/fms_form_mgr_lifecycle_update_test.cpp", + ] + + include_dirs = [ + "//third_party/json/include", + "//foundation/appexecfwk/standard/common/log/include/", + "//foundation/appexecfwk/standard/services/formmgr/include", + "//foundation/appexecfwk/standard/services/bundlemgr/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base/include/", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/formmgr/", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/bundlemgr/", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include/", + "//foundation/distributedschedule/samgr/adapter/interfaces/innerkits/include/", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler/include", + "//base/notification/ces_standard/cesfwk/kits/native/include", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/include", + "//base/security/permission/interfaces/innerkits/permission_standard/permissionsdk/main/cpp/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/fmskit/native/include", + "//foundation/aafwk/standard/frameworks/kits/ability/native/include", + "//foundation/appexecfwk/standard/kits/appkit/native/app/include", + "//base/global/resmgr_standard/interfaces/innerkits/include", + ] + + configs = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:formmgr_sdk_config", + #"${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:bundlemgr_sdk_config", + #"//foundation/appexecfwk/standard/services/formmgr:formmgr_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/common:libappexecfwk_common", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${services_path}/formmgr:fms_target", + "//base/security/permission/interfaces/innerkits/permission_standard/permissionsdk:libpermissionsdk_standard", + + #"${libs_path}/libeventhandler:libeventhandler_target", + #"//base/startup/appspawn_standard:appspawn_socket_client", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/googletest:gmock_main", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +############################################################################### +group("unittest") { + testonly = true + + deps = [ ":FmsFormMgrLifecycleUpdateTest" ] +} +############################################################################### diff --git a/services/formmgr/test/unittest/fms_form_mgr_lifecycle_update_test/fms_form_mgr_lifecycle_update_test.cpp b/services/formmgr/test/unittest/fms_form_mgr_lifecycle_update_test/fms_form_mgr_lifecycle_update_test.cpp new file mode 100644 index 0000000000..86deffae18 --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_mgr_lifecycle_update_test/fms_form_mgr_lifecycle_update_test.cpp @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2021 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 "form_bms_helper.h" +#include "form_db_cache.h" +#include "form_host_interface.h" +#define private public +#include "form_mgr.h" +#include "form_mgr_service.h" +#include "form_data_mgr.h" +#undef private +#include "if_system_ability_manager.h" +#include "inner_bundle_info.h" +#include "ipc_skeleton.h" +#include "iservice_registry.h" + +#include "permission/permission.h" +#include "permission/permission_kit.h" +#include "mock_bundle_manager.h" +#include "mock_form_host_client.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; +using namespace OHOS::Security; + +namespace { +const std::string PERMISSION_NAME_REQUIRE_FORM = "ohos.permission.REQUIRE_FORM"; +const std::string FORM_PROVIDER_BUNDLE_NAME = "com.form.provider.service"; +const std::string FORM_PROVIDER_ABILITY_NAME = "com.form.provider.app.test"; +const std::string FORM_HOST_BUNDLE_NAME = "com.form.host.app"; +const std::string DEVICE_ID = "ohos-phone1"; + +const std::string DEF_LABEL1 = "PermissionFormRequireGrant"; + +class FmsFormMgrLifecycleUpdateTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + void InitFormItemInfo(int64_t formId, FormItemInfo &formItemInfo) const; + +protected: + sptr mockBundleMgr_; + std::shared_ptr formyMgrServ_ = DelayedSingleton::GetInstance(); + sptr token_; +}; + +void FmsFormMgrLifecycleUpdateTest::SetUpTestCase() +{} + +void FmsFormMgrLifecycleUpdateTest::TearDownTestCase() +{} + +void FmsFormMgrLifecycleUpdateTest::SetUp() +{ + // APP_LOGI("fms_form_mgr_enable_update_test_001 setup"); + formyMgrServ_->OnStart(); + + // mock BundleMgr + mockBundleMgr_ = new (std::nothrow) BundleMgrService(); + ASSERT_TRUE(mockBundleMgr_ != nullptr); + FormBmsHelper::GetInstance().SetBundleManager(mockBundleMgr_); + + // token + token_ = new (std::nothrow) MockFormHostClient(); + + // Permission install + std::vector permList; + Permission::PermissionDef permDef; + permDef.permissionName = PERMISSION_NAME_REQUIRE_FORM; + permDef.bundleName = FORM_PROVIDER_BUNDLE_NAME; + permDef.grantMode = Permission::GrantMode::USER_GRANT; + permDef.availableScope = Permission::AvailableScope::AVAILABLE_SCOPE_ALL; + permDef.label = DEF_LABEL1; + permDef.labelId = 1; + permDef.description = DEF_LABEL1; + permDef.descriptionId = 1; + permList.emplace_back(permDef); + Permission::PermissionKit::AddDefPermissions(permList); + Permission::PermissionKit::AddUserGrantedReqPermissions(FORM_PROVIDER_BUNDLE_NAME, {PERMISSION_NAME_REQUIRE_FORM}, + 0); + Permission::PermissionKit::GrantUserGrantedPermission(FORM_PROVIDER_BUNDLE_NAME, PERMISSION_NAME_REQUIRE_FORM, 0); +} + +void FmsFormMgrLifecycleUpdateTest::TearDown() +{} + +void FmsFormMgrLifecycleUpdateTest::InitFormItemInfo(int64_t formId, FormItemInfo &formItemInfo) const +{ + // create hapSourceDirs + std::vector hapSourceDirs; + std::string hapSourceDir = "1/2/3"; + hapSourceDirs.emplace_back(hapSourceDir); + + // create formItemInfo + formItemInfo.SetFormId(formId); + formItemInfo.SetTemporaryFlag(true); + formItemInfo.SetEnableUpdateFlag(true); + formItemInfo.SetUpdateDuration(Constants::MIN_CONFIG_DURATION); + formItemInfo.SetScheduledUpdateTime("10:30"); + formItemInfo.SetHapSourceDirs(hapSourceDirs); +} +/** + * @tc.number: FmsFormMgrLifecycleUpdateTest_LifecycleUpdate_001 + * @tc.name: LifecycleUpdate + * @tc.desc: Verify that the return value is correct. + * @tc.info: permission denied. + */ +HWTEST_F(FmsFormMgrLifecycleUpdateTest, FmsFormMgrLifecycleUpdateTest_LifecycleUpdate_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormMgrLifecycleUpdateTest_LifecycleUpdate_001 start"; + + std::vector formIds; + int32_t updateType = OHOS::AppExecFwk::FormMgrService::ENABLE_FORM_UPDATE; + + // Remove Permission + OHOS::Security::Permission::PermissionKit::RemoveDefPermissions(FORM_PROVIDER_BUNDLE_NAME); + OHOS::Security::Permission::PermissionKit::RemoveUserGrantedReqPermissions(FORM_PROVIDER_BUNDLE_NAME, 0); + OHOS::Security::Permission::PermissionKit::RemoveSystemGrantedReqPermissions(FORM_PROVIDER_BUNDLE_NAME); + + EXPECT_EQ(ERR_APPEXECFWK_FORM_PERMISSION_DENY, FormMgr::GetInstance().LifecycleUpdate(formIds, token_, updateType)); + + GTEST_LOG_(INFO) << "FmsFormMgrLifecycleUpdateTest_LifecycleUpdate_001 end"; +} + +/** + * @tc.number: FmsFormMgrLifecycleUpdateTest_LifecycleUpdate_002 + * @tc.name: LifecycleUpdate + * @tc.desc: Verify that the return value is correct. + * @tc.info: formIds is empty. + */ +HWTEST_F(FmsFormMgrLifecycleUpdateTest, FmsFormMgrLifecycleUpdateTest_LifecycleUpdate_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormMgrLifecycleUpdateTest_LifecycleUpdate_002 start"; + + std::vector formIds; + int32_t updateType = OHOS::AppExecFwk::FormMgrService::ENABLE_FORM_UPDATE; + + EXPECT_EQ(ERR_FORM_INVALID_PARAM, FormMgr::GetInstance().LifecycleUpdate(formIds, token_, updateType)); + + GTEST_LOG_(INFO) << "FmsFormMgrLifecycleUpdateTest_LifecycleUpdate_002 end"; +} + +/** + * @tc.number: FmsFormMgrLifecycleUpdateTest_LifecycleUpdate_003 + * @tc.name: LifecycleUpdate + * @tc.desc: Verify that the return value is correct. + * @tc.info: clientRecords_ is empty. + */ +HWTEST_F(FmsFormMgrLifecycleUpdateTest, FmsFormMgrLifecycleUpdateTest_LifecycleUpdate_003, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormMgrLifecycleUpdateTest_LifecycleUpdate_003 start"; + + std::vector formIds; + formIds.push_back(3); + + int32_t updateType = OHOS::AppExecFwk::FormMgrService::ENABLE_FORM_UPDATE; + + EXPECT_EQ(ERR_FORM_INVALID_PARAM, FormMgr::GetInstance().LifecycleUpdate(formIds, token_, updateType)); + + GTEST_LOG_(INFO) << "FmsFormMgrLifecycleUpdateTest_LifecycleUpdate_003 end"; +} + +/** + * @tc.number: FmsFormMgrLifecycleUpdateTest_LifecycleUpdate_004 + * @tc.name: LifecycleUpdate + * @tc.desc: Verify that the return value is correct. + * @tc.info: + * clientRecords_ is exist, but no formRecords. + * set EnableRefresh, and not pull up Provider. + */ +HWTEST_F(FmsFormMgrLifecycleUpdateTest, FmsFormMgrLifecycleUpdateTest_LifecycleUpdate_004, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormMgrLifecycleUpdateTest_LifecycleUpdate_004 start"; + + std::vector formIds; + int64_t formId = 4; + formIds.push_back(formId); + + int32_t updateType = OHOS::AppExecFwk::FormMgrService::ENABLE_FORM_UPDATE; + + // create clientRecords_ + FormHostRecord formHostRecord; + formHostRecord.SetClientStub(token_); + formHostRecord.AddForm(formId); + formHostRecord.SetNeedRefresh(formId, true); + FormDataMgr::GetInstance().clientRecords_.push_back(formHostRecord); + + EXPECT_EQ(ERR_OK, FormMgr::GetInstance().LifecycleUpdate(formIds, token_, updateType)); + + GTEST_LOG_(INFO) << "FmsFormMgrLifecycleUpdateTest_LifecycleUpdate_004 end"; +} + + +/** + * @tc.number: FmsFormMgrLifecycleUpdateTest_LifecycleUpdate_005 + * @tc.name: LifecycleUpdate + * @tc.desc: Verify that the return value is correct. + * @tc.info: + * clientRecords and formRecords(needRefresh:true) is exist. + * set EnableRefresh, and pull up Provider and update. + */ +HWTEST_F(FmsFormMgrLifecycleUpdateTest, FmsFormMgrLifecycleUpdateTest_LifecycleUpdate_005, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormMgrLifecycleUpdateTest_LifecycleUpdate_005 start"; + + std::vector formIds; + int64_t formId = 5; + formIds.push_back(formId); + + int32_t updateType = OHOS::AppExecFwk::FormMgrService::ENABLE_FORM_UPDATE; + + // create clientRecords_ + FormHostRecord formHostRecord; + formHostRecord.SetClientStub(token_); + formHostRecord.AddForm(formId); + formHostRecord.SetNeedRefresh(formId, true); + FormDataMgr::GetInstance().clientRecords_.push_back(formHostRecord); + + // create formRecords + int callingUid = 0; + FormItemInfo formItemInfo; + InitFormItemInfo(formId, formItemInfo); + FormRecord record = FormDataMgr::GetInstance().CreateFormRecord(formItemInfo, callingUid); + // needRefresh:true + record.needRefresh = true; + FormDataMgr::GetInstance().formRecords_.emplace(formId, record); + + EXPECT_EQ(ERR_OK, FormMgr::GetInstance().LifecycleUpdate(formIds, token_, updateType)); + + GTEST_LOG_(INFO) << "FmsFormMgrLifecycleUpdateTest_LifecycleUpdate_005 end"; +} + +/** + * @tc.number: FmsFormMgrLifecycleUpdateTest_LifecycleUpdate_006 + * @tc.name: LifecycleUpdate + * @tc.desc: Verify that the return value is correct. + * + * @tc.info: + * clientRecords(needRefresh:true) and formRecords(needRefresh & versionUpgrade:false) is exist. + * set EnableRefresh, and update hostRecord. + */ +HWTEST_F(FmsFormMgrLifecycleUpdateTest, FmsFormMgrLifecycleUpdateTest_LifecycleUpdate_006, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormMgrLifecycleUpdateTest_LifecycleUpdate_006 start"; + + std::vector formIds; + int64_t formId = 6; + formIds.push_back(formId); + + int32_t updateType = OHOS::AppExecFwk::FormMgrService::ENABLE_FORM_UPDATE; + + // create clientRecords_ + FormHostRecord formHostRecord; + formHostRecord.SetClientStub(token_); + formHostRecord.AddForm(formId); + // needRefresh:true + formHostRecord.SetNeedRefresh(formId, true); + FormDataMgr::GetInstance().clientRecords_.push_back(formHostRecord); + + // create formRecords + int callingUid = 0; + FormItemInfo formItemInfo; + InitFormItemInfo(formId, formItemInfo); + FormRecord record = FormDataMgr::GetInstance().CreateFormRecord(formItemInfo, callingUid); + // needRefresh:false + record.needRefresh = false; + // versionUpgrade:false + record.versionUpgrade = false; + FormDataMgr::GetInstance().formRecords_.emplace(formId, record); + + EXPECT_EQ(ERR_OK, FormMgr::GetInstance().LifecycleUpdate(formIds, token_, updateType)); + + // judge hostrecord's needRefresh_ is false. + EXPECT_EQ(false, FormDataMgr::GetInstance().clientRecords_.at(0).IsNeedRefresh(formId)); + + GTEST_LOG_(INFO) << "FmsFormMgrLifecycleUpdateTest_LifecycleUpdate_006 end"; +} +} \ No newline at end of file diff --git a/services/formmgr/test/unittest/fms_form_mgr_message_event_test/BUILD.gn b/services/formmgr/test/unittest/fms_form_mgr_message_event_test/BUILD.gn new file mode 100644 index 0000000000..0301957804 --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_mgr_message_event_test/BUILD.gn @@ -0,0 +1,86 @@ +# Copyright (c) 2021 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/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/formmgrservice" + +ohos_unittest("FmsFormMgrMessageEventTest") { + module_out_path = module_output_path + + sources = [ + "//foundation/appexecfwk/standard/interfaces/innerkits/fmskit/native/src/form_mgr.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_bundle_manager.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_form_host_client.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_form_provider_client.cpp", + ] + sources += [ "fms_form_mgr_message_event_test.cpp" ] + + include_dirs = [ + "//third_party/zlib/contrib/minizip", + "//third_party/zlib", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/fmskit/native/include/", + "//foundation/appexecfwk/standard/common/log/include/", + "//foundation/appexecfwk/standard/services/formmgr/include", + "//foundation/appexecfwk/standard/services/bundlemgr/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base/include/", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/formmgr/", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include/", + "//foundation/distributedschedule/samgr/adapter/interfaces/innerkits/include/", + ] + + configs = [ + "${services_path}/formmgr/test:formmgr_test_config", + "//foundation/aafwk/standard/services/abilitymgr:abilityms_config", + + # "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:bundlemgr_sdk_config", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:formmgr_sdk_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/common:libappexecfwk_common", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${appexecfwk_path}/interfaces/innerkits/fmskit:fmskit_native", + "${libs_path}/libeventhandler:libeventhandler_target", + "${services_path}/formmgr:fms_target", + "//base/security/permission/interfaces/innerkits/permission_standard/permissionsdk:libpermissionsdk_standard", + "//base/startup/appspawn_standard:appspawn_socket_client", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + + #"${services_path}/bundlemgr:bms_target", + "//foundation/aafwk/standard/services/abilitymgr:abilityms_target", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/googletest:gmock_main", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":FmsFormMgrMessageEventTest" ] +} diff --git a/services/formmgr/test/unittest/fms_form_mgr_message_event_test/fms_form_mgr_message_event_test.cpp b/services/formmgr/test/unittest/fms_form_mgr_message_event_test/fms_form_mgr_message_event_test.cpp new file mode 100644 index 0000000000..12d4e8395f --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_mgr_message_event_test/fms_form_mgr_message_event_test.cpp @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2021 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 "form_ams_helper.h" +#include "form_bms_helper.h" +#include "form_data_mgr.h" +#include "form_db_cache.h" +#include "form_host_interface.h" +#define private public +#include "form_mgr.h" +#undef private +#include "form_mgr_service.h" +#include "if_system_ability_manager.h" +#include "inner_bundle_info.h" +#include "ipc_skeleton.h" +#include "iservice_registry.h" + +#include "mock_ability_manager.h" +#include "mock_bundle_manager.h" +#include "mock_form_host_client.h" +#include "permission/permission.h" +#include "permission/permission_kit.h" +#include "running_process_info.h" +#include "system_ability_definition.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; +using namespace OHOS::Security; + +namespace { +const std::string PERMISSION_NAME_REQUIRE_FORM = "ohos.permission.REQUIRE_FORM"; +const std::string PARAM_PROVIDER_PACKAGE_NAME = "com.form.provider.app.test.abiliy"; +const std::string FORM_PROVIDER_BUNDLE_NAME = "com.form.provider.service"; +const std::string PARAM_PROVIDER_MODULE_NAME = "com.form.provider.app.test.abiliy"; +const std::string FORM_PROVIDER_ABILITY_NAME = "com.form.provider.app.test.abiliy"; +const std::string PARAM_FORM_NAME = "com.form.name.test"; + +const std::string FORM_JS_COMPOMENT_NAME = "jsComponentName"; +const std::string FORM_PROVIDER_MODULE_SOURCE_DIR = ""; + +const std::string FORM_HOST_BUNDLE_NAME = "com.form.host.app"; + +const std::string DEVICE_ID = "ohos-phone1"; +const std::string DEF_LABEL1 = "PermissionFormRequireGrant"; + +const std::string FORM_MESSAGE_EVENT_VALUE_1 = "event message1"; + +class FmsFormMgrMessageEventTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + +protected: + sptr token_; + std::shared_ptr formyMgrServ_ = DelayedSingleton::GetInstance(); + + sptr mockBundleMgr_; + sptr mockAbilityMgrServ_; +}; + +void FmsFormMgrMessageEventTest::SetUpTestCase() +{} + +void FmsFormMgrMessageEventTest::TearDownTestCase() +{} + +void FmsFormMgrMessageEventTest::SetUp() +{ + formyMgrServ_->OnStart(); + + mockBundleMgr_ = new (std::nothrow) BundleMgrService(); + EXPECT_TRUE(mockBundleMgr_ != nullptr); + FormBmsHelper::GetInstance().SetBundleManager(mockBundleMgr_); + + mockAbilityMgrServ_ = new (std::nothrow) MockAbilityMgrService(); + FormAmsHelper::GetInstance().SetAbilityManager(mockAbilityMgrServ_); + + token_ = new (std::nothrow) MockFormHostClient(); + + // Permission install + std::vector permList; + Permission::PermissionDef permDef; + permDef.permissionName = PERMISSION_NAME_REQUIRE_FORM; + permDef.bundleName = FORM_PROVIDER_BUNDLE_NAME; + permDef.grantMode = Permission::GrantMode::USER_GRANT; + permDef.availableScope = Permission::AvailableScope::AVAILABLE_SCOPE_ALL; + permDef.label = DEF_LABEL1; + permDef.labelId = 1; + permDef.description = DEF_LABEL1; + permDef.descriptionId = 1; + permList.emplace_back(permDef); + Permission::PermissionKit::AddDefPermissions(permList); + Permission::PermissionKit::AddUserGrantedReqPermissions(FORM_PROVIDER_BUNDLE_NAME, {PERMISSION_NAME_REQUIRE_FORM}, + 0); + Permission::PermissionKit::GrantUserGrantedPermission(FORM_PROVIDER_BUNDLE_NAME, PERMISSION_NAME_REQUIRE_FORM, 0); +} + +void FmsFormMgrMessageEventTest::TearDown() +{} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: MessageEvent Function + * FunctionPoints: FormMgr MessageEvent interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if FormMgr invoke MessageEvent works. + */ +HWTEST_F(FmsFormMgrMessageEventTest, MessageEvent_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_message_event_test_001 start"; + + int64_t formId {10000001}; + int callingUid {0}; + // Create cache + FormItemInfo record1; + record1.SetFormId(formId); + record1.SetProviderBundleName(FORM_HOST_BUNDLE_NAME); + record1.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + record1.SetTemporaryFlag(false); + FormRecord retFormRec = FormDataMgr::GetInstance().AllotFormRecord(record1, callingUid); + // User Uid Add some Useruids into a form in cache + int formUserUid {1}; + FormDataMgr::GetInstance().AddFormUserUid(formId, formUserUid); + // Set form host record + retFormRec.formUserUids.emplace_back(formUserUid); + FormDBInfo formDBInfo(formId, retFormRec); + FormDbCache::GetInstance().SaveFormInfo(formDBInfo); + // Set host record + FormItemInfo info; + FormDataMgr::GetInstance().AllotFormHostRecord(info, token_, formId, callingUid); + + Want want; + want.SetParam(Constants::PARAM_FORM_HOST_BUNDLENAME_KEY, FORM_HOST_BUNDLE_NAME); + want.SetParam(Constants::PARAM_MODULE_NAME_KEY, PARAM_PROVIDER_MODULE_NAME); + want.SetParam(Constants::PARAM_FORM_NAME_KEY, PARAM_FORM_NAME); + want.SetElementName(DEVICE_ID, FORM_PROVIDER_BUNDLE_NAME, FORM_PROVIDER_ABILITY_NAME); + want.SetParam(Constants::PARAM_MESSAGE_KEY, FORM_MESSAGE_EVENT_VALUE_1); + EXPECT_EQ(ERR_OK, FormMgr::GetInstance().MessageEvent(formId, want, token_)); + + GTEST_LOG_(INFO) << "fms_form_mgr_message_event_test_001 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: MessageEvent Function + * FunctionPoints: FormMgr MessageEvent interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: An exception tests if check permission error. + */ +HWTEST_F(FmsFormMgrMessageEventTest, MessageEvent_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_message_event_test_002 start"; + int64_t formId {10000001}; + // Remove Permission + OHOS::Security::Permission::PermissionKit::RemoveDefPermissions(FORM_PROVIDER_BUNDLE_NAME); + OHOS::Security::Permission::PermissionKit::RemoveUserGrantedReqPermissions(FORM_PROVIDER_BUNDLE_NAME, 0); + OHOS::Security::Permission::PermissionKit::RemoveSystemGrantedReqPermissions(FORM_PROVIDER_BUNDLE_NAME); + + Want want; + want.SetParam(Constants::PARAM_FORM_HOST_BUNDLENAME_KEY, FORM_HOST_BUNDLE_NAME); + want.SetParam(Constants::PARAM_MODULE_NAME_KEY, PARAM_PROVIDER_MODULE_NAME); + want.SetParam(Constants::PARAM_FORM_NAME_KEY, PARAM_FORM_NAME); + want.SetElementName(DEVICE_ID, FORM_PROVIDER_BUNDLE_NAME, FORM_PROVIDER_ABILITY_NAME); + want.SetParam(Constants::PARAM_MESSAGE_KEY, FORM_MESSAGE_EVENT_VALUE_1); + EXPECT_EQ(ERR_APPEXECFWK_FORM_PERMISSION_DENY, FormMgr::GetInstance().MessageEvent(formId, want, token_)); + // Permission install + std::vector permList; + Permission::PermissionDef permDef; + permDef.permissionName = PERMISSION_NAME_REQUIRE_FORM; + permDef.bundleName = FORM_PROVIDER_BUNDLE_NAME; + permDef.grantMode = Permission::GrantMode::USER_GRANT; + permDef.availableScope = Permission::AvailableScope::AVAILABLE_SCOPE_ALL; + permDef.label = DEF_LABEL1; + permDef.labelId = 1; + permDef.description = DEF_LABEL1; + permDef.descriptionId = 1; + permList.emplace_back(permDef); + Permission::PermissionKit::AddDefPermissions(permList); + Permission::PermissionKit::AddUserGrantedReqPermissions(FORM_PROVIDER_BUNDLE_NAME, {PERMISSION_NAME_REQUIRE_FORM}, + 0); + Permission::PermissionKit::GrantUserGrantedPermission(FORM_PROVIDER_BUNDLE_NAME, PERMISSION_NAME_REQUIRE_FORM, 0); + GTEST_LOG_(INFO) << "fms_form_mgr_message_event_test_002 end"; +} +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: MessageEvent Function + * FunctionPoints: FormMgr MessageEvent interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: An exception tests if formId == 0. + */ +HWTEST_F(FmsFormMgrMessageEventTest, MessageEvent_003, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_message_event_test_003 start"; + int64_t formId = 0; + + Want want; + want.SetParam(Constants::PARAM_FORM_HOST_BUNDLENAME_KEY, FORM_HOST_BUNDLE_NAME); + want.SetParam(Constants::PARAM_MODULE_NAME_KEY, PARAM_PROVIDER_MODULE_NAME); + want.SetParam(Constants::PARAM_FORM_NAME_KEY, PARAM_FORM_NAME); + want.SetElementName(DEVICE_ID, FORM_PROVIDER_BUNDLE_NAME, FORM_PROVIDER_ABILITY_NAME); + want.SetParam(Constants::PARAM_MESSAGE_KEY, FORM_MESSAGE_EVENT_VALUE_1); + EXPECT_EQ(ERR_APPEXECFWK_FORM_INVALID_PARAM, FormMgr::GetInstance().MessageEvent(formId, want, token_)); + GTEST_LOG_(INFO) << "fms_form_mgr_message_event_test_003 end"; +} +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: MessageEvent Function + * FunctionPoints: FormMgr MessageEvent interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: An exception tests if callerToken == nullptr. + */ +HWTEST_F(FmsFormMgrMessageEventTest, MessageEvent_004, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_message_event_test_004 start"; + int64_t formId {10000001}; + + Want want; + want.SetParam(Constants::PARAM_FORM_HOST_BUNDLENAME_KEY, FORM_HOST_BUNDLE_NAME); + want.SetParam(Constants::PARAM_MODULE_NAME_KEY, PARAM_PROVIDER_MODULE_NAME); + want.SetParam(Constants::PARAM_FORM_NAME_KEY, PARAM_FORM_NAME); + want.SetElementName(DEVICE_ID, FORM_PROVIDER_BUNDLE_NAME, FORM_PROVIDER_ABILITY_NAME); + want.SetParam(Constants::PARAM_MESSAGE_KEY, FORM_MESSAGE_EVENT_VALUE_1); + EXPECT_EQ(ERR_APPEXECFWK_FORM_INVALID_PARAM, FormMgr::GetInstance().MessageEvent(formId, want, nullptr)); + GTEST_LOG_(INFO) << "fms_form_mgr_message_event_test_004 end"; +} +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: MessageEvent Function + * FunctionPoints: FormMgr MessageEvent interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: An exception tests if message info is not exist. + */ +HWTEST_F(FmsFormMgrMessageEventTest, MessageEvent_005, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_message_event_test_005 start"; + int64_t formId {10000001}; + + Want want; + want.SetParam(Constants::PARAM_FORM_HOST_BUNDLENAME_KEY, FORM_HOST_BUNDLE_NAME); + want.SetParam(Constants::PARAM_MODULE_NAME_KEY, PARAM_PROVIDER_MODULE_NAME); + want.SetParam(Constants::PARAM_FORM_NAME_KEY, PARAM_FORM_NAME); + want.SetElementName(DEVICE_ID, FORM_PROVIDER_BUNDLE_NAME, FORM_PROVIDER_ABILITY_NAME); + + EXPECT_EQ(ERR_APPEXECFWK_FORM_INVALID_PARAM, FormMgr::GetInstance().MessageEvent(formId, want, token_)); + GTEST_LOG_(INFO) << "fms_form_mgr_message_event_test_005 end"; +} +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: MessageEvent Function + * FunctionPoints: FormMgr MessageEvent interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: An exception tests if not exist such form. + */ +HWTEST_F(FmsFormMgrMessageEventTest, MessageEvent_006, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_message_event_test_006 start"; + int64_t formId {11100002}; + + Want want; + want.SetParam(Constants::PARAM_FORM_HOST_BUNDLENAME_KEY, FORM_HOST_BUNDLE_NAME); + want.SetParam(Constants::PARAM_MODULE_NAME_KEY, PARAM_PROVIDER_MODULE_NAME); + want.SetParam(Constants::PARAM_FORM_NAME_KEY, PARAM_FORM_NAME); + want.SetElementName(DEVICE_ID, FORM_PROVIDER_BUNDLE_NAME, FORM_PROVIDER_ABILITY_NAME); + want.SetParam(Constants::PARAM_MESSAGE_KEY, FORM_MESSAGE_EVENT_VALUE_1); + EXPECT_EQ(ERR_APPEXECFWK_FORM_INFO_NOT_EXIST, FormMgr::GetInstance().MessageEvent(formId, want, token_)); + GTEST_LOG_(INFO) << "fms_form_mgr_message_event_test_006 end"; +} +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: MessageEvent Function + * FunctionPoints: FormMgr MessageEvent interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: An exception tests if cannot find target client. + */ +HWTEST_F(FmsFormMgrMessageEventTest, MessageEvent_007, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_message_event_test_007 start"; + int64_t formId {10000001}; + + Want want; + want.SetParam(Constants::PARAM_FORM_HOST_BUNDLENAME_KEY, FORM_HOST_BUNDLE_NAME); + want.SetParam(Constants::PARAM_MODULE_NAME_KEY, PARAM_PROVIDER_MODULE_NAME); + want.SetParam(Constants::PARAM_FORM_NAME_KEY, PARAM_FORM_NAME); + want.SetElementName(DEVICE_ID, FORM_PROVIDER_BUNDLE_NAME, FORM_PROVIDER_ABILITY_NAME); + want.SetParam(Constants::PARAM_MESSAGE_KEY, FORM_MESSAGE_EVENT_VALUE_1); + EXPECT_EQ(ERR_APPEXECFWK_FORM_HOST_INFO_NOT_EXIST, FormMgr::GetInstance().MessageEvent(formId, want, + new (std::nothrow) MockFormHostClient())); + GTEST_LOG_(INFO) << "fms_form_mgr_message_event_test_007 end"; +} +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: MessageEvent Function + * FunctionPoints: FormMgr MessageEvent interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: An exception tests if form is not self-owned. + */ +HWTEST_F(FmsFormMgrMessageEventTest, MessageEvent_008, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_message_event_test_008 start"; + int64_t formId2 {10000001}; + int64_t formId {10000002}; + int callingUid {0}; + // Create cache + FormItemInfo record1; + record1.SetFormId(formId); + record1.SetProviderBundleName(FORM_HOST_BUNDLE_NAME); + record1.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + record1.SetTemporaryFlag(false); + FormRecord retFormRec = FormDataMgr::GetInstance().AllotFormRecord(record1, callingUid); + // User Uid Add some Useruids into a form in cache + int formUserUid {1}; + FormDataMgr::GetInstance().AddFormUserUid(formId, formUserUid); + // Set form host record + retFormRec.formUserUids.emplace_back(formUserUid); + FormDBInfo formDBInfo(formId, retFormRec); + FormDbCache::GetInstance().SaveFormInfo(formDBInfo); + // Set host record + FormItemInfo info; + FormDataMgr::GetInstance().AllotFormHostRecord(info, token_, formId, callingUid); + + FormDataMgr::GetInstance().DeleteHostRecord(token_, formId2); + + Want want; + want.SetParam(Constants::PARAM_FORM_HOST_BUNDLENAME_KEY, FORM_HOST_BUNDLE_NAME); + want.SetParam(Constants::PARAM_MODULE_NAME_KEY, PARAM_PROVIDER_MODULE_NAME); + want.SetParam(Constants::PARAM_FORM_NAME_KEY, PARAM_FORM_NAME); + want.SetElementName(DEVICE_ID, FORM_PROVIDER_BUNDLE_NAME, FORM_PROVIDER_ABILITY_NAME); + want.SetParam(Constants::PARAM_MESSAGE_KEY, FORM_MESSAGE_EVENT_VALUE_1); + EXPECT_EQ(ERR_OPERATION_FORM_NOT_SELF, FormMgr::GetInstance().MessageEvent(formId2, want, token_)); + GTEST_LOG_(INFO) << "fms_form_mgr_message_event_test_008 end"; +} +} \ No newline at end of file diff --git a/services/formmgr/test/unittest/fms_form_mgr_notify_invisible_forms_test/BUILD.gn b/services/formmgr/test/unittest/fms_form_mgr_notify_invisible_forms_test/BUILD.gn new file mode 100644 index 0000000000..f35b3b3e96 --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_mgr_notify_invisible_forms_test/BUILD.gn @@ -0,0 +1,88 @@ +# Copyright (c) 2021 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/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/formmgrservice" + +ohos_unittest("FmsFormMgrNotifyInvisibleFormsTest") { + module_out_path = module_output_path + + sources = [ + "//foundation/appexecfwk/standard/interfaces/innerkits/fmskit/native/src/form_mgr.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_bundle_manager.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_form_host_client.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/unittest/fms_form_mgr_notify_invisible_forms_test/fms_form_mgr_notify_invisible_forms_test.cpp", + ] + + include_dirs = [ + "//third_party/json/include", + "//foundation/appexecfwk/standard/common/log/include/", + "//foundation/appexecfwk/standard/services/formmgr/include", + "//foundation/appexecfwk/standard/services/bundlemgr/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base/include/", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/formmgr/", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/bundlemgr/", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include/", + "//foundation/distributedschedule/samgr/adapter/interfaces/innerkits/include/", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler/include", + "//base/notification/ces_standard/cesfwk/kits/native/include", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/include", + "//base/security/permission/interfaces/innerkits/permission_standard/permissionsdk/main/cpp/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/fmskit/native/include", + "//foundation/aafwk/standard/frameworks/kits/ability/native/include", + "//foundation/appexecfwk/standard/kits/appkit/native/app/include", + "//base/global/resmgr_standard/interfaces/innerkits/include", + ] + + configs = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:formmgr_sdk_config", + #"${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:bundlemgr_sdk_config", + #"//foundation/appexecfwk/standard/services/formmgr:formmgr_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/common:libappexecfwk_common", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${services_path}/formmgr:fms_target", + "//base/security/permission/interfaces/innerkits/permission_standard/permissionsdk:libpermissionsdk_standard", + + #"${libs_path}/libeventhandler:libeventhandler_target", + #"//base/startup/appspawn_standard:appspawn_socket_client", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/googletest:gmock_main", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +############################################################################### +group("unittest") { + testonly = true + + deps = [ ":FmsFormMgrNotifyInvisibleFormsTest" ] +} +############################################################################### diff --git a/services/formmgr/test/unittest/fms_form_mgr_notify_invisible_forms_test/fms_form_mgr_notify_invisible_forms_test.cpp b/services/formmgr/test/unittest/fms_form_mgr_notify_invisible_forms_test/fms_form_mgr_notify_invisible_forms_test.cpp new file mode 100644 index 0000000000..d1d1d1d1dc --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_mgr_notify_invisible_forms_test/fms_form_mgr_notify_invisible_forms_test.cpp @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2021 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 +#include + +#include "app_log_wrapper.h" +#include "appexecfwk_errors.h" +#define private public +#include "form_bms_helper.h" +#include "form_mgr_service.h" +#include "form_mgr_adapter.h" +#include "form_data_mgr.h" +#include "form_mgr.h" +#undef private +#include "form_constants.h" +#include "mock_form_host_client.h" +#include "mock_bundle_manager.h" +#include "permission/permission_def.h" +#include "permission/permission_kit.h" +#include "permission/permission.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; + +namespace { +const std::string FORM_HOST_BUNDLE_NAME = "com.form.provider.service"; +const std::string FORM_PROVIDER_ABILITY_NAME = "com.form.provider.app.test.abiliy"; +const std::string PERMISSION_NAME_REQUIRE_FORM = "ohos.permission.REQUIRE_FORM"; +const std::string DEF_LABEL1 = "PermissionFormRequireGrant"; + +class FmsFormMgrNotifyInvisibleFormsTest : public testing::Test { +public: + FmsFormMgrNotifyInvisibleFormsTest() : formMgrService_(nullptr) + {} + ~FmsFormMgrNotifyInvisibleFormsTest() + {} + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +protected: + sptr token_; + sptr mockBundleMgr_; + std::shared_ptr formMgrService_ = DelayedSingleton::GetInstance(); +}; +void FmsFormMgrNotifyInvisibleFormsTest::SetUpTestCase(void) +{} + +void FmsFormMgrNotifyInvisibleFormsTest::TearDownTestCase(void) +{} + +void FmsFormMgrNotifyInvisibleFormsTest::SetUp(void) +{ + formMgrService_ = std::make_shared(); + + formMgrService_->OnStart(); + + // mock BundleMgr + mockBundleMgr_ = new (std::nothrow) BundleMgrService(); + ASSERT_TRUE(mockBundleMgr_ != nullptr); + FormBmsHelper::GetInstance().SetBundleManager(mockBundleMgr_); + + // token + token_ = new (std::nothrow) OHOS::AppExecFwk::MockFormHostClient(); + + // Permission install + std::vector permList; + OHOS::Security::Permission::PermissionDef permDef; + permDef.permissionName = PERMISSION_NAME_REQUIRE_FORM; + permDef.bundleName = FORM_HOST_BUNDLE_NAME; + permDef.grantMode = OHOS::Security::Permission::GrantMode::USER_GRANT; + permDef.availableScope = OHOS::Security::Permission::AvailableScope::AVAILABLE_SCOPE_ALL; + permDef.label = DEF_LABEL1; + permDef.labelId = 1; + permDef.description = DEF_LABEL1; + permDef.descriptionId = 1; + permList.emplace_back(permDef); + OHOS::Security::Permission::PermissionKit::AddDefPermissions(permList); + OHOS::Security::Permission::PermissionKit::AddUserGrantedReqPermissions(FORM_HOST_BUNDLE_NAME, + {PERMISSION_NAME_REQUIRE_FORM}, 0); + OHOS::Security::Permission::PermissionKit::GrantUserGrantedPermission(FORM_HOST_BUNDLE_NAME, + PERMISSION_NAME_REQUIRE_FORM, 0); +} + +void FmsFormMgrNotifyInvisibleFormsTest::TearDown(void) +{} + +/** + * @tc.number: FmsFormMgrNotifyInvisibleFormsTest_NotifyInvisibleForms_001 + * @tc.name: NotifyInvisibleForms + * @tc.desc: Verify that the return value is ERR_APPEXECFWK_FORM_PERMISSION_DENY. + * @tc.info: permission denied. + */ +HWTEST_F(FmsFormMgrNotifyInvisibleFormsTest, FmsFormMgrNotifyInvisibleFormsTest_NotifyInvisibleForms_001, +TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormMgrNotifyInvisibleFormsTest_NotifyInvisibleForms_001 start"; + + int64_t formId = 1; + std::vector formIds; + formIds.push_back(formId); + + // Remove Permission + OHOS::Security::Permission::PermissionKit::RemoveDefPermissions(FORM_HOST_BUNDLE_NAME); + OHOS::Security::Permission::PermissionKit::RemoveUserGrantedReqPermissions(FORM_HOST_BUNDLE_NAME, 0); + OHOS::Security::Permission::PermissionKit::RemoveSystemGrantedReqPermissions(FORM_HOST_BUNDLE_NAME); + + EXPECT_EQ(ERR_APPEXECFWK_FORM_PERMISSION_DENY, FormMgr::GetInstance().NotifyWhetherVisibleForms( formIds, + token_, Constants::FORM_INVISIBLE )); + GTEST_LOG_(INFO) << "FmsFormMgrNotifyInvisibleFormsTest_NotifyInvisibleForms_001 end"; +} + +/** + * @tc.number: FmsFormMgrNotifyInvisibleFormsTest_NotifyInvisibleForms_002 + * @tc.name: NotifyInvisibleForms + * @tc.desc: Verify that the return value is ERR_APPEXECFWK_FORM_INVALID_PARAM. + * @tc.info: callerToken is nullptr. + */ +HWTEST_F(FmsFormMgrNotifyInvisibleFormsTest, FmsFormMgrNotifyInvisibleFormsTest_NotifyInvisibleForms_002, +TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormMgrNotifyInvisibleFormsTest_NotifyInvisibleForms_002 start"; + + int64_t formId = 2; + std::vector formIds; + formIds.push_back(formId); + + // creat formRecords_ + FormItemInfo iteminfo; + iteminfo.formId_ = formId; + iteminfo.providerBundleName_ = FORM_HOST_BUNDLE_NAME; + iteminfo.abilityName_ = FORM_PROVIDER_ABILITY_NAME; + FormDataMgr::GetInstance().AllotFormRecord(iteminfo, 0); + + // clear callerToken + token_ = nullptr; + + EXPECT_EQ(ERR_APPEXECFWK_FORM_INVALID_PARAM, FormMgr::GetInstance().NotifyWhetherVisibleForms( formIds, + token_, Constants::FORM_INVISIBLE )); + GTEST_LOG_(INFO) << "FmsFormMgrNotifyInvisibleFormsTest_NotifyInvisibleForms_002 end"; +} + +/** + * @tc.number: FmsFormMgrNotifyInvisibleFormsTest_NotifyInvisibleForms_003 + * @tc.name: NotifyInvisibleForms + * @tc.desc: Verify that the return value is ERR_OK. + * @tc.info: form record is not found. + */ +HWTEST_F(FmsFormMgrNotifyInvisibleFormsTest, FmsFormMgrNotifyInvisibleFormsTest_NotifyInvisibleForms_003, +TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormMgrNotifyInvisibleFormsTest_NotifyInvisibleForms_003 start"; + + int64_t formId = 3; + std::vector formIds; + formIds.push_back(formId); + + EXPECT_EQ(ERR_OK, FormMgr::GetInstance().NotifyWhetherVisibleForms( formIds, token_, Constants::FORM_INVISIBLE )); + GTEST_LOG_(INFO) << "FmsFormMgrNotifyInvisibleFormsTest_NotifyInvisibleForms_003 end"; +} + +/** + * @tc.number: FmsFormMgrNotifyInvisibleFormsTest_NotifyInvisibleForms_004 + * @tc.name: NotifyInvisibleForms + * @tc.desc: Verify that the return value is ERR_OK. + * @tc.info: host form record is not found. + */ +HWTEST_F(FmsFormMgrNotifyInvisibleFormsTest, FmsFormMgrNotifyInvisibleFormsTest_NotifyInvisibleForms_004, +TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormMgrNotifyInvisibleFormsTest_NotifyInvisibleForms_004 start"; + + int64_t formId = 4; + std::vector formIds; + formIds.push_back(formId); + + // creat formRecords_ + FormItemInfo iteminfo; + iteminfo.formId_ = formId; + iteminfo.providerBundleName_ = FORM_HOST_BUNDLE_NAME; + iteminfo.abilityName_ = FORM_PROVIDER_ABILITY_NAME; + FormDataMgr::GetInstance().AllotFormRecord(iteminfo, 0); + + EXPECT_EQ(ERR_OK, FormMgr::GetInstance().NotifyWhetherVisibleForms( formIds, token_, Constants::FORM_INVISIBLE )); + GTEST_LOG_(INFO) << "FmsFormMgrNotifyInvisibleFormsTest_NotifyInvisibleForms_004 end"; +} + +/** + * @tc.number: FmsFormMgrNotifyInvisibleFormsTest_NotifyInvisibleForms_005 + * @tc.name: NotifyInvisibleForms + * @tc.desc: Verify that the return value is ERR_OK. + * @tc.info: host form record is found, but formVisibleNotify is false. + */ +HWTEST_F(FmsFormMgrNotifyInvisibleFormsTest, FmsFormMgrNotifyInvisibleFormsTest_NotifyInvisibleForms_005, +TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormMgrNotifyInvisibleFormsTest_NotifyInvisibleForms_005 start"; + + int64_t formId = 5; + std::vector formIds; + formIds.push_back(formId); + + // creat formRecords_ + FormItemInfo iteminfo; + iteminfo.formId_ = formId; + iteminfo.providerBundleName_ = FORM_HOST_BUNDLE_NAME; + iteminfo.abilityName_ = FORM_PROVIDER_ABILITY_NAME; + iteminfo.formVisibleNotify_ = false; + FormDataMgr::GetInstance().AllotFormRecord(iteminfo, 0); + + // creat clientRecords_ + FormDataMgr::GetInstance().AllotFormHostRecord(iteminfo, token_, formId, 0); + + EXPECT_EQ(ERR_OK, FormMgr::GetInstance().NotifyWhetherVisibleForms( formIds, token_, Constants::FORM_INVISIBLE )); + GTEST_LOG_(INFO) << "FmsFormMgrNotifyInvisibleFormsTest_NotifyInvisibleForms_005 end"; +} + +/** + * @tc.number: FmsFormMgrNotifyInvisibleFormsTest_NotifyInvisibleForms_006 + * @tc.name: NotifyInvisibleForms + * @tc.desc: Verify that the return value is ERR_OK. + * @tc.info: host form record is found, formVisibleNotify is true, it is a SystemApp. + */ +HWTEST_F(FmsFormMgrNotifyInvisibleFormsTest, FmsFormMgrNotifyInvisibleFormsTest_NotifyInvisibleForms_006, +TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormMgrNotifyInvisibleFormsTest_NotifyInvisibleForms_006 start"; + + int64_t formId = 6; + std::vector formIds; + formIds.push_back(formId); + + // creat formRecords_ + FormItemInfo iteminfo; + iteminfo.formId_ = formId; + iteminfo.providerBundleName_ = FORM_HOST_BUNDLE_NAME; + iteminfo.abilityName_ = FORM_PROVIDER_ABILITY_NAME; + iteminfo.formVisibleNotify_ = true; + FormDataMgr::GetInstance().AllotFormRecord(iteminfo, 0); + + // creat clientRecords_ + FormDataMgr::GetInstance().AllotFormHostRecord(iteminfo, token_, formId, 0); + + EXPECT_EQ(ERR_OK, FormMgr::GetInstance().NotifyWhetherVisibleForms( formIds, token_, Constants::FORM_INVISIBLE )); + GTEST_LOG_(INFO) << "FmsFormMgrNotifyInvisibleFormsTest_NotifyInvisibleForms_006 end"; +} + +/** + * @tc.number: FmsFormMgrNotifyInvisibleFormsTest_NotifyInvisibleForms_007 + * @tc.name: NotifyInvisibleForms + * @tc.desc: Verify that the return value is ERR_OK. + * @tc.info: it is not a SystemApp. + */ +HWTEST_F(FmsFormMgrNotifyInvisibleFormsTest, FmsFormMgrNotifyInvisibleFormsTest_NotifyInvisibleForms_007, +TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormMgrNotifyInvisibleFormsTest_NotifyInvisibleForms_007 start"; + + int64_t formId = 7; + std::string mockBundleName = "com.form.host.app600"; + std::vector formIds; + formIds.push_back(formId); + + // creat formRecords_ + FormItemInfo iteminfo; + iteminfo.formId_ = formId; + iteminfo.providerBundleName_ = mockBundleName; + iteminfo.abilityName_ = FORM_PROVIDER_ABILITY_NAME; + iteminfo.formVisibleNotify_ = true; + FormDataMgr::GetInstance().AllotFormRecord(iteminfo, 0); + + // creat clientRecords_ + FormDataMgr::GetInstance().AllotFormHostRecord(iteminfo, token_, formId, 0); + + // Permission install (mockBundleName) + std::vector permList; + OHOS::Security::Permission::PermissionDef permDef; + permDef.permissionName = PERMISSION_NAME_REQUIRE_FORM; + permDef.bundleName = mockBundleName; + permDef.grantMode = OHOS::Security::Permission::GrantMode::USER_GRANT; + permDef.availableScope = OHOS::Security::Permission::AvailableScope::AVAILABLE_SCOPE_ALL; + permDef.label = DEF_LABEL1; + permDef.labelId = 1; + permDef.description = DEF_LABEL1; + permDef.descriptionId = 1; + permList.emplace_back(permDef); + OHOS::Security::Permission::PermissionKit::AddDefPermissions(permList); + OHOS::Security::Permission::PermissionKit::AddUserGrantedReqPermissions(mockBundleName, + {PERMISSION_NAME_REQUIRE_FORM}, 0); + OHOS::Security::Permission::PermissionKit::GrantUserGrantedPermission(mockBundleName, + PERMISSION_NAME_REQUIRE_FORM, 0); + + EXPECT_EQ(ERR_OK, FormMgr::GetInstance().NotifyWhetherVisibleForms( formIds, token_, Constants::FORM_INVISIBLE )); + GTEST_LOG_(INFO) << "FmsFormMgrNotifyInvisibleFormsTest_NotifyInvisibleForms_007 end"; +} +} diff --git a/services/formmgr/test/unittest/fms_form_mgr_notify_visible_forms_test/BUILD.gn b/services/formmgr/test/unittest/fms_form_mgr_notify_visible_forms_test/BUILD.gn new file mode 100644 index 0000000000..82f7bb2820 --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_mgr_notify_visible_forms_test/BUILD.gn @@ -0,0 +1,88 @@ +# Copyright (c) 2021 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/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/formmgrservice" + +ohos_unittest("FmsFormMgrNotifyVisibleFormsTest") { + module_out_path = module_output_path + + sources = [ + "//foundation/appexecfwk/standard/interfaces/innerkits/fmskit/native/src/form_mgr.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_bundle_manager.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_form_host_client.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/unittest/fms_form_mgr_notify_visible_forms_test/fms_form_mgr_notify_visible_forms_test.cpp", + ] + + include_dirs = [ + "//third_party/json/include", + "//foundation/appexecfwk/standard/common/log/include/", + "//foundation/appexecfwk/standard/services/formmgr/include", + "//foundation/appexecfwk/standard/services/bundlemgr/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base/include/", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/formmgr/", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/bundlemgr/", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include/", + "//foundation/distributedschedule/samgr/adapter/interfaces/innerkits/include/", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler/include", + "//base/notification/ces_standard/cesfwk/kits/native/include", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/include", + "//base/security/permission/interfaces/innerkits/permission_standard/permissionsdk/main/cpp/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/fmskit/native/include", + "//foundation/aafwk/standard/frameworks/kits/ability/native/include", + "//foundation/appexecfwk/standard/kits/appkit/native/app/include", + "//base/global/resmgr_standard/interfaces/innerkits/include", + ] + + configs = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:formmgr_sdk_config", + #"${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:bundlemgr_sdk_config", + #"//foundation/appexecfwk/standard/services/formmgr:formmgr_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/common:libappexecfwk_common", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${services_path}/formmgr:fms_target", + "//base/security/permission/interfaces/innerkits/permission_standard/permissionsdk:libpermissionsdk_standard", + + #"${libs_path}/libeventhandler:libeventhandler_target", + #"//base/startup/appspawn_standard:appspawn_socket_client", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/googletest:gmock_main", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +############################################################################### +group("unittest") { + testonly = true + + deps = [ ":FmsFormMgrNotifyVisibleFormsTest" ] +} +############################################################################### diff --git a/services/formmgr/test/unittest/fms_form_mgr_notify_visible_forms_test/fms_form_mgr_notify_visible_forms_test.cpp b/services/formmgr/test/unittest/fms_form_mgr_notify_visible_forms_test/fms_form_mgr_notify_visible_forms_test.cpp new file mode 100644 index 0000000000..83f9d5a588 --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_mgr_notify_visible_forms_test/fms_form_mgr_notify_visible_forms_test.cpp @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2021 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 +#include + +#include "app_log_wrapper.h" +#include "appexecfwk_errors.h" +#define private public +#include "form_bms_helper.h" +#include "form_constants.h" +#include "form_mgr_service.h" +#include "form_mgr_adapter.h" +#include "form_data_mgr.h" +#include "form_mgr.h" +#undef private +#include "mock_form_host_client.h" +#include "mock_bundle_manager.h" +#include "permission/permission_def.h" +#include "permission/permission_kit.h" +#include "permission/permission.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; + +namespace { +const std::string NON_SYSTEM_APP_BUNDLE_NAME = "com.form.host.app600"; +const std::string FORM_PROVIDER_BUNDLE_NAME = "com.form.provider.service"; +const std::string FORM_PROVIDER_ABILITY_NAME = "com.form.provider.app.test.abiliy"; +const std::string PERMISSION_NAME_REQUIRE_FORM = "ohos.permission.REQUIRE_FORM"; +const std::string DEF_LABEL1 = "PermissionFormRequireGrant"; + +class FmsFormMgrNotifyVisibleFormsTest : public testing::Test { +public: + FmsFormMgrNotifyVisibleFormsTest() : formMgrService_(nullptr) + {} + ~FmsFormMgrNotifyVisibleFormsTest() + {} + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +protected: + sptr token_; + sptr mockBundleMgr_; + std::shared_ptr formMgrService_ = DelayedSingleton::GetInstance(); +}; +void FmsFormMgrNotifyVisibleFormsTest::SetUpTestCase(void) +{} + +void FmsFormMgrNotifyVisibleFormsTest::TearDownTestCase(void) +{} + +void FmsFormMgrNotifyVisibleFormsTest::SetUp(void) +{ + formMgrService_ = std::make_shared(); + formMgrService_->OnStart(); + + mockBundleMgr_ = new (std::nothrow) BundleMgrService(); + ASSERT_TRUE(mockBundleMgr_ != nullptr); + FormBmsHelper::GetInstance().SetBundleManager(mockBundleMgr_); + token_ = new (std::nothrow) MockFormHostClient(); + + // Permission install + std::vector permList; + OHOS::Security::Permission::PermissionDef permDef; + permDef.permissionName = PERMISSION_NAME_REQUIRE_FORM; + permDef.bundleName = FORM_PROVIDER_BUNDLE_NAME; + permDef.grantMode = OHOS::Security::Permission::GrantMode::USER_GRANT; + permDef.availableScope = OHOS::Security::Permission::AvailableScope::AVAILABLE_SCOPE_ALL; + permDef.label = DEF_LABEL1; + permDef.labelId = 1; + permDef.description = DEF_LABEL1; + permDef.descriptionId = 1; + permList.emplace_back(permDef); + OHOS::Security::Permission::PermissionKit::AddDefPermissions(permList); + OHOS::Security::Permission::PermissionKit::AddUserGrantedReqPermissions(FORM_PROVIDER_BUNDLE_NAME, + {PERMISSION_NAME_REQUIRE_FORM}, 0); + OHOS::Security::Permission::PermissionKit::GrantUserGrantedPermission(FORM_PROVIDER_BUNDLE_NAME, + PERMISSION_NAME_REQUIRE_FORM, 0); +} + +void FmsFormMgrNotifyVisibleFormsTest::TearDown(void) +{} + +/** + * @tc.number: FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_001 + * @tc.name: NotifyVisibleForms + * @tc.desc: Verify that the return code is ERR_APPEXECFWK_FORM_PERMISSION_DENY. + * @tc.info: The permission denied occurred. + */ +HWTEST_F(FmsFormMgrNotifyVisibleFormsTest, FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_001 start"; + + std::vector formIds; + formIds.push_back(100); + + // Remove permission. + OHOS::Security::Permission::PermissionKit::RemoveDefPermissions(FORM_PROVIDER_BUNDLE_NAME); + OHOS::Security::Permission::PermissionKit::RemoveUserGrantedReqPermissions(FORM_PROVIDER_BUNDLE_NAME, 0); + OHOS::Security::Permission::PermissionKit::RemoveSystemGrantedReqPermissions(FORM_PROVIDER_BUNDLE_NAME); + + EXPECT_EQ(ERR_APPEXECFWK_FORM_PERMISSION_DENY, FormMgr::GetInstance().NotifyWhetherVisibleForms(formIds, token_, + Constants::FORM_VISIBLE)); + + GTEST_LOG_(INFO) << "FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_001 end"; +} + +/** + * @tc.number: FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_002 + * @tc.name: NotifyVisibleForms + * @tc.desc: Verify that the return code is ERR_APPEXECFWK_FORM_INVALID_PARAM. + * @tc.info: The callerToken is nullptr. + */ +HWTEST_F(FmsFormMgrNotifyVisibleFormsTest, FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_002 start"; + + // set the callerToken to nullptr. + token_ = nullptr; + + // create formIds + int64_t formId1 = 301; + int64_t formId2 = 302; + std::vector formIds; + formIds.push_back(formId1); + formIds.push_back(formId2); + + // create formRecords + FormItemInfo formiteminfo1; + formiteminfo1.SetFormId(formId1); + formiteminfo1.SetProviderBundleName(FORM_PROVIDER_BUNDLE_NAME); + formiteminfo1.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + formiteminfo1.SetTemporaryFlag(false); + FormDataMgr::GetInstance().AllotFormRecord(formiteminfo1, 0); + + FormItemInfo formiteminfo2; + formiteminfo2.SetFormId(formId2); + formiteminfo2.SetProviderBundleName(FORM_PROVIDER_BUNDLE_NAME); + formiteminfo2.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + formiteminfo2.SetTemporaryFlag(false); + FormDataMgr::GetInstance().AllotFormRecord(formiteminfo2, 0); + + EXPECT_EQ(ERR_APPEXECFWK_FORM_INVALID_PARAM, FormMgr::GetInstance().NotifyWhetherVisibleForms(formIds, token_, + Constants::FORM_VISIBLE)); + + GTEST_LOG_(INFO) << "FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_002 end"; +} + +/** + * @tc.number: FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_003 + * @tc.name: NotifyVisibleForms + * @tc.desc: Verify that the return value is ERR_OK. + * @tc.info: Create two formId and push formIds, but only create one form record. + */ +HWTEST_F(FmsFormMgrNotifyVisibleFormsTest, FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_003, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_003 start"; + + // create formIds + int64_t formId1 = 401; + int64_t formId2 = 402; + std::vector formIds; + formIds.push_back(formId1); + formIds.push_back(formId2); + + // create formRecords + FormItemInfo formiteminfo1; + formiteminfo1.SetFormId(formId1); + formiteminfo1.SetProviderBundleName(FORM_PROVIDER_BUNDLE_NAME); + formiteminfo1.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + formiteminfo1.SetFormVisibleNotify(true); + formiteminfo1.SetTemporaryFlag(false); + FormDataMgr::GetInstance().AllotFormRecord(formiteminfo1, 0); + FormDataMgr::GetInstance().SetNeedRefresh(formId1, true); + + // create formHostRecord + FormDataMgr::GetInstance().AllotFormHostRecord(formiteminfo1, token_, formId1, 0); + + EXPECT_EQ(ERR_OK, FormMgr::GetInstance().NotifyWhetherVisibleForms(formIds, token_, Constants::FORM_VISIBLE)); + + GTEST_LOG_(INFO) << "FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_003 end"; +} + +/** + * @tc.number: FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_004 + * @tc.name: NotifyVisibleForms + * @tc.desc: Verify that the return value is ERR_OK. + * @tc.info: Create two formId and push formIds, but only create one form host record. + */ +HWTEST_F(FmsFormMgrNotifyVisibleFormsTest, FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_004, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_004 start"; + + // create formIds + int64_t formId1 = 501; + int64_t formId2 = 502; + std::vector formIds; + formIds.push_back(formId1); + formIds.push_back(formId2); + + // create formRecords + FormItemInfo formiteminfo1; + formiteminfo1.SetFormId(formId1); + formiteminfo1.SetProviderBundleName(FORM_PROVIDER_BUNDLE_NAME); + formiteminfo1.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + formiteminfo1.SetFormVisibleNotify(true); + formiteminfo1.SetTemporaryFlag(false); + FormDataMgr::GetInstance().AllotFormRecord(formiteminfo1, 0); + FormDataMgr::GetInstance().SetNeedRefresh(formId1, true); + + FormItemInfo formiteminfo2; + formiteminfo2.SetFormId(formId2); + formiteminfo2.SetProviderBundleName(FORM_PROVIDER_BUNDLE_NAME); + formiteminfo2.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + formiteminfo2.SetFormVisibleNotify(true); + formiteminfo2.SetTemporaryFlag(false); + FormDataMgr::GetInstance().AllotFormRecord(formiteminfo2, 0); + FormDataMgr::GetInstance().SetNeedRefresh(formId2, true); + + // create formHostRecord + FormDataMgr::GetInstance().AllotFormHostRecord(formiteminfo1, token_, formId1, 0); + + EXPECT_EQ(ERR_OK, FormMgr::GetInstance().NotifyWhetherVisibleForms(formIds, token_, Constants::FORM_VISIBLE)); + + GTEST_LOG_(INFO) << "FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_004 end"; +} + +/** + * @tc.number: FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_005 + * @tc.name: NotifyVisibleForms + * @tc.desc: Verify that the return value is ERR_OK. + * @tc.info: Create two formId and push formIds, two form records and two form host records. + */ +HWTEST_F(FmsFormMgrNotifyVisibleFormsTest, FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_005, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_005 start"; + + // create formIds + int64_t formId1 = 601; + int64_t formId2 = 602; + std::vector formIds; + formIds.push_back(formId1); + formIds.push_back(formId2); + + // create formRecords + FormItemInfo formiteminfo1; + formiteminfo1.SetFormId(formId1); + formiteminfo1.SetProviderBundleName(FORM_PROVIDER_BUNDLE_NAME); + formiteminfo1.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + formiteminfo1.SetFormVisibleNotify(true); + formiteminfo1.SetTemporaryFlag(false); + FormDataMgr::GetInstance().AllotFormRecord(formiteminfo1, 0); + FormDataMgr::GetInstance().SetNeedRefresh(formId1, true); + + FormItemInfo formiteminfo2; + formiteminfo2.SetFormId(formId2); + formiteminfo2.SetProviderBundleName(FORM_PROVIDER_BUNDLE_NAME); + formiteminfo2.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + formiteminfo2.SetFormVisibleNotify(true); + formiteminfo2.SetTemporaryFlag(false); + FormDataMgr::GetInstance().AllotFormRecord(formiteminfo2, 0); + FormDataMgr::GetInstance().SetNeedRefresh(formId2, true); + + // create formHostRecord + FormDataMgr::GetInstance().AllotFormHostRecord(formiteminfo1, token_, formId1, 0); + FormDataMgr::GetInstance().AllotFormHostRecord(formiteminfo2, token_, formId2, 0); + + EXPECT_EQ(ERR_OK, FormMgr::GetInstance().NotifyWhetherVisibleForms(formIds, token_, Constants::FORM_VISIBLE)); + GTEST_LOG_(INFO) << "FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_005 end"; +} + +/** + * @tc.number: FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_006 + * @tc.name: NotifyVisibleForms + * @tc.desc: Verify that the return value is ERR_OK. + * @tc.info: The NeedRefresh is false. + */ +HWTEST_F(FmsFormMgrNotifyVisibleFormsTest, FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_006, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_006 start"; + + // create formIds + int64_t formId = 700; + std::vector formIds; + formIds.push_back(formId); + + // create formRecords + FormItemInfo formiteminfo1; + formiteminfo1.SetFormId(formId); + formiteminfo1.SetProviderBundleName(FORM_PROVIDER_BUNDLE_NAME); + formiteminfo1.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + formiteminfo1.SetFormVisibleNotify(true); + formiteminfo1.SetTemporaryFlag(false); + FormDataMgr::GetInstance().AllotFormRecord(formiteminfo1, 0); + FormDataMgr::GetInstance().SetNeedRefresh(formId, false); + + // create formHostRecord + FormDataMgr::GetInstance().AllotFormHostRecord(formiteminfo1, token_, formId, 0); + + EXPECT_EQ(ERR_OK, FormMgr::GetInstance().NotifyWhetherVisibleForms(formIds, token_, Constants::FORM_VISIBLE)); + GTEST_LOG_(INFO) << "FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_006 end"; +} + +/** + * @tc.number: FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_007 + * @tc.name: NotifyVisibleForms + * @tc.desc: Verify that the return value is ERR_OK. + * @tc.info: The FormVisibleNotify is false. + */ +HWTEST_F(FmsFormMgrNotifyVisibleFormsTest, FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_007, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_007 start"; + + // create formIds + int64_t formId = 800; + std::vector formIds; + formIds.push_back(formId); + + // create formRecords + FormItemInfo formiteminfo1; + formiteminfo1.SetFormId(formId); + formiteminfo1.SetProviderBundleName(FORM_PROVIDER_BUNDLE_NAME); + formiteminfo1.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + formiteminfo1.SetFormVisibleNotify(false); + formiteminfo1.SetTemporaryFlag(false); + FormDataMgr::GetInstance().AllotFormRecord(formiteminfo1, 0); + FormDataMgr::GetInstance().SetNeedRefresh(formId, true); + + // create formHostRecord + FormDataMgr::GetInstance().AllotFormHostRecord(formiteminfo1, token_, formId, 0); + + EXPECT_EQ(ERR_OK, FormMgr::GetInstance().NotifyWhetherVisibleForms(formIds, token_, Constants::FORM_VISIBLE)); + GTEST_LOG_(INFO) << "FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_007 end"; +} + +/** + * @tc.number: FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_008 + * @tc.name: NotifyVisibleForms + * @tc.desc: Verify that the return value is ERR_OK. + * @tc.info: The form provider is not a system app. + */ +HWTEST_F(FmsFormMgrNotifyVisibleFormsTest, FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_008, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_008 start"; + + // create formIds + int64_t formId = 900; + std::vector formIds; + formIds.push_back(formId); + + // create formRecords + FormItemInfo formiteminfo1; + formiteminfo1.SetFormId(formId); + formiteminfo1.SetProviderBundleName(NON_SYSTEM_APP_BUNDLE_NAME); + formiteminfo1.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + formiteminfo1.SetFormVisibleNotify(true); + formiteminfo1.SetTemporaryFlag(false); + FormDataMgr::GetInstance().AllotFormRecord(formiteminfo1, 0); + FormDataMgr::GetInstance().SetNeedRefresh(formId, true); + + // create formHostRecord + FormDataMgr::GetInstance().AllotFormHostRecord(formiteminfo1, token_, formId, 0); + + // Permission install + std::vector permList; + OHOS::Security::Permission::PermissionDef permDef; + permDef.permissionName = PERMISSION_NAME_REQUIRE_FORM; + permDef.bundleName = NON_SYSTEM_APP_BUNDLE_NAME; + permDef.grantMode = OHOS::Security::Permission::GrantMode::USER_GRANT; + permDef.availableScope = OHOS::Security::Permission::AvailableScope::AVAILABLE_SCOPE_ALL; + permDef.label = DEF_LABEL1; + permDef.labelId = 1; + permDef.description = DEF_LABEL1; + permDef.descriptionId = 1; + permList.emplace_back(permDef); + OHOS::Security::Permission::PermissionKit::AddDefPermissions(permList); + OHOS::Security::Permission::PermissionKit::AddUserGrantedReqPermissions(NON_SYSTEM_APP_BUNDLE_NAME, + {PERMISSION_NAME_REQUIRE_FORM}, 0); + OHOS::Security::Permission::PermissionKit::GrantUserGrantedPermission(NON_SYSTEM_APP_BUNDLE_NAME, + PERMISSION_NAME_REQUIRE_FORM, 0); + + EXPECT_EQ(ERR_OK, FormMgr::GetInstance().NotifyWhetherVisibleForms(formIds, token_, Constants::FORM_VISIBLE)); + GTEST_LOG_(INFO) << "FmsFormMgrNotifyVisibleFormsTest_NotifyVisibleForms_008 end"; +} +} diff --git a/services/formmgr/test/unittest/fms_form_mgr_release_form_test/BUILD.gn b/services/formmgr/test/unittest/fms_form_mgr_release_form_test/BUILD.gn new file mode 100644 index 0000000000..6eead96a0b --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_mgr_release_form_test/BUILD.gn @@ -0,0 +1,82 @@ +# Copyright (c) 2021 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/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/formmgrservice" + +ohos_unittest("FmsFormMgrReleaseFormTest") { + module_out_path = module_output_path + + sources = [ + "//foundation/appexecfwk/standard/interfaces/innerkits/fmskit/native/src/form_mgr.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_bundle_manager.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_form_host_client.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_form_provider_client.cpp", + ] + sources += [ "fms_form_mgr_release_form_test.cpp" ] + + include_dirs = [ + "//third_party/zlib/contrib/minizip", + "//third_party/zlib", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/fmskit/native/include/", + "//foundation/appexecfwk/standard/common/log/include/", + "//foundation/appexecfwk/standard/services/formmgr/include", + "//foundation/appexecfwk/standard/services/bundlemgr/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base/include/", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/formmgr/", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include/", + "//foundation/distributedschedule/samgr/adapter/interfaces/innerkits/include/", + ] + + configs = [ + "${services_path}/bundlemgr/test:bundlemgr_test_config", + "${services_path}/formmgr/test:formmgr_test_config", + "//foundation/aafwk/standard/services/abilitymgr:abilityms_config", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:formmgr_sdk_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/common:libappexecfwk_common", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${appexecfwk_path}/interfaces/innerkits/fmskit:fmskit_native", + "${libs_path}/libeventhandler:libeventhandler_target", + "${services_path}/formmgr:fms_target", + "//base/security/permission/interfaces/innerkits/permission_standard/permissionsdk:libpermissionsdk_standard", + "//base/startup/appspawn_standard:appspawn_socket_client", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/googletest:gmock_main", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":FmsFormMgrReleaseFormTest" ] +} diff --git a/services/formmgr/test/unittest/fms_form_mgr_release_form_test/fms_form_mgr_release_form_test.cpp b/services/formmgr/test/unittest/fms_form_mgr_release_form_test/fms_form_mgr_release_form_test.cpp new file mode 100644 index 0000000000..1ec263f000 --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_mgr_release_form_test/fms_form_mgr_release_form_test.cpp @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2021 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 "app_log_wrapper.h" +#include "appexecfwk_errors.h" +#include "form_bms_helper.h" +#include "form_cache_mgr.h" +#include "form_data_mgr.h" +#include "form_db_cache.h" +#include "form_db_info.h" +#define private public +#include "form_mgr.h" +#undef private +#include "form_mgr_service.h" +#include "if_system_ability_manager.h" +#include "ipc_skeleton.h" +#include "iservice_registry.h" +#include "mock_bundle_manager.h" +#include "mock_form_token.h" +#include "mock_form_host_client.h" +#include "permission/permission_kit.h" +#include "permission/permission.h" +#include "running_process_info.h" +#include "system_ability_definition.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; +using namespace OHOS::Security; + +namespace { +const std::string PERMISSION_NAME_REQUIRE_FORM = "ohos.permission.REQUIRE_FORM"; +const std::string FORM_PROVIDER_BUNDLE_NAME = "com.form.provider.service"; +const std::string FORM_PROVIDER_ABILITY_NAME = "com.form.provider.app.test"; +const std::string FORM_HOST_BUNDLE_NAME = "com.form.host.app"; +const std::string DEVICE_ID = "ohos-phone1"; + +const std::string DEF_LABEL1 = "PermissionFormRequireGrant"; + +class FmsFormMgrReleaseFormTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + +protected: + sptr token_; + std::shared_ptr formyMgrServ_ = DelayedSingleton::GetInstance(); + sptr mockBundleMgr_; +}; + +void FmsFormMgrReleaseFormTest::SetUpTestCase() +{} + +void FmsFormMgrReleaseFormTest::TearDownTestCase() +{} + +void FmsFormMgrReleaseFormTest::SetUp() +{ + formyMgrServ_->OnStart(); + mockBundleMgr_ = new (std::nothrow) BundleMgrService(); + ASSERT_TRUE(mockBundleMgr_ != nullptr); + FormBmsHelper::GetInstance().SetBundleManager(mockBundleMgr_); + token_ = new (std::nothrow) MockFormHostClient(); + + // Permission install + std::vector permList; + Permission::PermissionDef permDef; + permDef.permissionName = PERMISSION_NAME_REQUIRE_FORM; + permDef.bundleName = FORM_PROVIDER_BUNDLE_NAME; + permDef.grantMode = Permission::GrantMode::USER_GRANT; + permDef.availableScope = Permission::AvailableScope::AVAILABLE_SCOPE_ALL; + permDef.label = DEF_LABEL1; + permDef.labelId = 1; + permDef.description = DEF_LABEL1; + permDef.descriptionId = 1; + permList.emplace_back(permDef); + Permission::PermissionKit::AddDefPermissions(permList); + Permission::PermissionKit::AddUserGrantedReqPermissions(FORM_PROVIDER_BUNDLE_NAME, {PERMISSION_NAME_REQUIRE_FORM}, + 0); + Permission::PermissionKit::GrantUserGrantedPermission(FORM_PROVIDER_BUNDLE_NAME, PERMISSION_NAME_REQUIRE_FORM, 0); +} + +void FmsFormMgrReleaseFormTest::TearDown() +{} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: ReleaseForm Function + * FunctionPoints: FormMgr ReleaseForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Quote of form is not 0 after release form. + */ +HWTEST_F(FmsFormMgrReleaseFormTest, ReleaseForm_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_release_test_001 start"; + + int64_t formId = FormDataMgr::GetInstance().GenerateFormId(); + + FormItemInfo record1; + record1.SetFormId(formId); + record1.SetProviderBundleName(FORM_PROVIDER_BUNDLE_NAME); + record1.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + record1.SetTemporaryFlag(false); + FormDataMgr::GetInstance().AllotFormRecord(record1, 0); + int64_t formId2 = FormDataMgr::GetInstance().GenerateFormId(); + FormItemInfo record2; + record2.SetFormId(formId2); + record2.SetProviderBundleName(FORM_PROVIDER_BUNDLE_NAME); + record2.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + record2.SetTemporaryFlag(false); + FormDataMgr::GetInstance().AllotFormRecord(record2, 1); + FormItemInfo itemInfo; + FormDataMgr::GetInstance().AllotFormHostRecord(itemInfo, token_, formId, 0); + + EXPECT_EQ(ERR_OK, FormMgr::GetInstance().ReleaseForm(formId, token_, true)); + + // Cache uid is not deleted yet. + FormRecord formInfo; + bool ret = FormDataMgr::GetInstance().GetFormRecord(formId, formInfo); + EXPECT_FALSE(ret); + ret = FormDataMgr::GetInstance().GetFormRecord(formId2, formInfo); + EXPECT_TRUE(ret); + // Form host record is deleted. + FormHostRecord hostRecord; + EXPECT_FALSE(FormDataMgr::GetInstance().GetFormHostRecord(formId, hostRecord)); + + FormDataMgr::GetInstance().DeleteFormRecord(formId); + FormDataMgr::GetInstance().DeleteFormRecord(formId2); + FormDbCache::GetInstance().DeleteFormInfo(formId); + FormDbCache::GetInstance().DeleteFormInfo(formId2); + FormDataMgr::GetInstance().DeleteHostRecord(token_, formId2); + GTEST_LOG_(INFO) << "fms_form_mgr_release_test_001 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: ReleaseForm Function + * FunctionPoints: FormMgr ReleaseForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Quote of form is 0 after delete form. + */ +HWTEST_F(FmsFormMgrReleaseFormTest, ReleaseForm_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_release_test_002 start"; + + int64_t formId1 = FormDataMgr::GetInstance().GenerateFormId(); + int64_t formId2 = FormDataMgr::GetInstance().GenerateFormId(); + FormItemInfo record1; + record1.SetFormId(formId1); + record1.SetProviderBundleName(FORM_PROVIDER_BUNDLE_NAME); + record1.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + record1.SetTemporaryFlag(false); + FormDataMgr::GetInstance().AllotFormRecord(record1, 0); + + FormItemInfo record2; + record2.SetFormId(formId2); + record2.SetProviderBundleName(FORM_PROVIDER_BUNDLE_NAME); + record2.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + record2.SetTemporaryFlag(false); + FormDataMgr::GetInstance().AllotFormRecord(record2, 0); + + FormItemInfo itemInfo; + FormDataMgr::GetInstance().AllotFormHostRecord(itemInfo, token_, formId1, 0); + + FormCacheMgr::GetInstance().AddData(formId1, "test data 1"); + FormCacheMgr::GetInstance().AddData(formId2, "test data 2"); + + EXPECT_EQ(ERR_OK, FormMgr::GetInstance().ReleaseForm(formId1, token_, true)); + + FormDataMgr::GetInstance().DeleteFormRecord(formId1); + FormDataMgr::GetInstance().DeleteFormRecord(formId2); + FormDbCache::GetInstance().DeleteFormInfo(formId1); + FormDbCache::GetInstance().DeleteFormInfo(formId2); + FormDataMgr::GetInstance().DeleteHostRecord(token_, formId1); + GTEST_LOG_(INFO) << "fms_form_mgr_release_test_002 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: ReleaseForm Function + * FunctionPoints: FormMgr ReleaseForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: An exception tests if check error. + */ +HWTEST_F(FmsFormMgrReleaseFormTest, ReleaseForm_003, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_release_test_003 start"; + int64_t formId = FormDataMgr::GetInstance().GenerateFormId(); + // formId<=0 + EXPECT_EQ(ERR_FORM_INVALID_PARAM, FormMgr::GetInstance().ReleaseForm(0L, token_, false)); + // sptr is nullptr + EXPECT_EQ(ERR_FORM_INVALID_PARAM, FormMgr::GetInstance().ReleaseForm(formId, nullptr, false)); + + // Remove Permission + OHOS::Security::Permission::PermissionKit::RemoveDefPermissions(FORM_PROVIDER_BUNDLE_NAME); + OHOS::Security::Permission::PermissionKit::RemoveUserGrantedReqPermissions(FORM_PROVIDER_BUNDLE_NAME, 0); + OHOS::Security::Permission::PermissionKit::RemoveSystemGrantedReqPermissions(FORM_PROVIDER_BUNDLE_NAME); + EXPECT_EQ(ERR_APPEXECFWK_FORM_PERMISSION_DENY, FormMgr::GetInstance().ReleaseForm(formId, token_, false)); + // Permission install + std::vector permList; + Permission::PermissionDef permDef; + permDef.permissionName = PERMISSION_NAME_REQUIRE_FORM; + permDef.bundleName = FORM_PROVIDER_BUNDLE_NAME; + permDef.grantMode = Permission::GrantMode::USER_GRANT; + permDef.availableScope = Permission::AvailableScope::AVAILABLE_SCOPE_ALL; + permDef.label = DEF_LABEL1; + permDef.labelId = 1; + permDef.description = DEF_LABEL1; + permDef.descriptionId = 1; + permList.emplace_back(permDef); + Permission::PermissionKit::AddDefPermissions(permList); + Permission::PermissionKit::AddUserGrantedReqPermissions(FORM_PROVIDER_BUNDLE_NAME, {PERMISSION_NAME_REQUIRE_FORM}, + 0); + Permission::PermissionKit::GrantUserGrantedPermission(FORM_PROVIDER_BUNDLE_NAME, PERMISSION_NAME_REQUIRE_FORM, 0); + GTEST_LOG_(INFO) << "fms_form_mgr_release_test_003 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: ReleaseForm Function + * FunctionPoints: FormMgr ReleaseForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: An exception tests if formId is not exist in cache. + */ +HWTEST_F(FmsFormMgrReleaseFormTest, ReleaseForm_004, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_release_test_004 start"; + int64_t formId = FormDataMgr::GetInstance().GenerateFormId(); + EXPECT_EQ(ERR_NOT_EXIST_ID, FormMgr::GetInstance().ReleaseForm(formId, token_, true)); + GTEST_LOG_(INFO) << "fms_form_mgr_release_test_004 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: ReleaseForm Function + * FunctionPoints: FormMgr ReleaseForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: An exception tests if formId is not exist in host. + */ +HWTEST_F(FmsFormMgrReleaseFormTest, ReleaseForm_005, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_release_test_005 start"; + int64_t formId = FormDataMgr::GetInstance().GenerateFormId(); + FormItemInfo record; + record.SetFormId(formId); + record.SetProviderBundleName(FORM_PROVIDER_BUNDLE_NAME); + record.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + record.SetTemporaryFlag(false); + FormDataMgr::GetInstance().AllotFormRecord(record, 0); + EXPECT_EQ(ERR_OPERATION_FORM_NOT_SELF, FormMgr::GetInstance().ReleaseForm(formId, token_, true)); + GTEST_LOG_(INFO) << "fms_form_mgr_release_test_005 end"; +} +} \ No newline at end of file diff --git a/services/formmgr/test/unittest/fms_form_mgr_request_form_test/BUILD.gn b/services/formmgr/test/unittest/fms_form_mgr_request_form_test/BUILD.gn new file mode 100644 index 0000000000..cf85c44057 --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_mgr_request_form_test/BUILD.gn @@ -0,0 +1,81 @@ +# Copyright (c) 2021 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/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/formmgrservice" + +ohos_unittest("FmsFormMgrRequestFormTest") { + module_out_path = module_output_path + + sources = [ + "//foundation/appexecfwk/standard/interfaces/innerkits/fmskit/native/src/form_mgr.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_bundle_manager.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_form_host_client.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_form_provider_client.cpp", + ] + sources += [ "fms_form_mgr_request_form_test.cpp" ] + + include_dirs = [ + "//third_party/zlib/contrib/minizip", + "//third_party/zlib", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/fmskit/native/include/", + "//foundation/appexecfwk/standard/common/log/include/", + "//foundation/appexecfwk/standard/services/formmgr/include", + "//foundation/appexecfwk/standard/services/bundlemgr/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base/include/", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/formmgr/", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include/", + "//foundation/distributedschedule/samgr/adapter/interfaces/innerkits/include/", + ] + + configs = [ + "${services_path}/bundlemgr/test:bundlemgr_test_config", + "${services_path}/formmgr/test:formmgr_test_config", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:formmgr_sdk_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/common:libappexecfwk_common", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${appexecfwk_path}/interfaces/innerkits/fmskit:fmskit_native", + "${libs_path}/libeventhandler:libeventhandler_target", + "${services_path}/formmgr:fms_target", + "//base/security/permission/interfaces/innerkits/permission_standard/permissionsdk:libpermissionsdk_standard", + "//base/startup/appspawn_standard:appspawn_socket_client", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/googletest:gmock_main", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":FmsFormMgrRequestFormTest" ] +} diff --git a/services/formmgr/test/unittest/fms_form_mgr_request_form_test/fms_form_mgr_request_form_test.cpp b/services/formmgr/test/unittest/fms_form_mgr_request_form_test/fms_form_mgr_request_form_test.cpp new file mode 100644 index 0000000000..f6d4824741 --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_mgr_request_form_test/fms_form_mgr_request_form_test.cpp @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2021 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 "app_log_wrapper.h" +#include "appexecfwk_errors.h" +#include "form_data_mgr.h" +#define private public +#include "form_mgr.h" +#undef private +#include "form_mgr_service.h" +#include "form_ams_helper.h" +#include "form_bms_helper.h" +#include "if_system_ability_manager.h" +#include "ipc_skeleton.h" +#include "iservice_registry.h" +#include "permission/permission_kit.h" +#include "permission/permission.h" +#include "running_process_info.h" +#include "mock_bundle_manager.h" +#include "mock_ability_manager.h" +#include "system_ability_definition.h" +#include "../../mock/include/mock_form_token.h" +#include "../../mock/include/mock_form_host_client.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; +using namespace OHOS::Security; + +namespace { +const std::string PERMISSION_NAME_REQUIRE_FORM = "ohos.permission.REQUIRE_FORM"; +const std::string FORM_PROVIDER_BUNDLE_NAME = "com.form.provider.service"; +const std::string FORM_PROVIDER_ABILITY_NAME = "com.form.provider.app.test"; +const std::string FORM_HOST_BUNDLE_NAME = "com.form.host.app"; +const std::string DEVICE_ID = "ohos-phone1"; + +const std::string DEF_LABEL1 = "PermissionFormRequireGrant"; + +class FmsFormMgrRequestFormTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + +protected: + sptr mockAbilityMgrServ_; + sptr mockBundleMgr_; + sptr token_; + std::shared_ptr formyMgrServ_ = DelayedSingleton::GetInstance(); +}; + +void FmsFormMgrRequestFormTest::SetUpTestCase() +{} + +void FmsFormMgrRequestFormTest::TearDownTestCase() +{} + +void FmsFormMgrRequestFormTest::SetUp() +{ + formyMgrServ_->OnStart(); + + token_ = new (std::nothrow) MockFormHostClient(); + + mockBundleMgr_ = new (std::nothrow) BundleMgrService(); + ASSERT_TRUE(mockBundleMgr_ != nullptr); + FormBmsHelper::GetInstance().SetBundleManager(mockBundleMgr_); + + mockAbilityMgrServ_ = new (std::nothrow) MockAbilityMgrService(); + FormAmsHelper::GetInstance().SetAbilityManager(mockAbilityMgrServ_); + // Permission install + std::vector permList; + Permission::PermissionDef permDef; + permDef.permissionName = PERMISSION_NAME_REQUIRE_FORM; + permDef.bundleName = FORM_PROVIDER_BUNDLE_NAME; + permDef.grantMode = Permission::GrantMode::USER_GRANT; + permDef.availableScope = Permission::AvailableScope::AVAILABLE_SCOPE_ALL; + permDef.label = DEF_LABEL1; + permDef.labelId = 1; + permDef.description = DEF_LABEL1; + permDef.descriptionId = 1; + permList.emplace_back(permDef); + Permission::PermissionKit::AddDefPermissions(permList); + Permission::PermissionKit::AddUserGrantedReqPermissions(FORM_PROVIDER_BUNDLE_NAME, {PERMISSION_NAME_REQUIRE_FORM}, + 0); + Permission::PermissionKit::GrantUserGrantedPermission(FORM_PROVIDER_BUNDLE_NAME, PERMISSION_NAME_REQUIRE_FORM, 0); +} + +void FmsFormMgrRequestFormTest::TearDown() +{} + +/* + * Feature: FormMgrService + * Function: FormMgrClient + * SubFunction: RequestForm Function + * FunctionPoints: FormMgrClient RequestForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Nomal case: Verify if FormMgrClient invoke RequestForm works. + */ +HWTEST_F(FmsFormMgrRequestFormTest, RequestForm_001, TestSize.Level0) +{ + APP_LOGI("fms_form_mgr_request_test_001 start"); + + int64_t formId {0X0000FFFF00000000}; + int callingUid {0}; + // Create cache + FormItemInfo record1; + record1.SetFormId(formId); + record1.SetProviderBundleName(FORM_HOST_BUNDLE_NAME); + record1.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + record1.SetTemporaryFlag(false); + FormRecord retFormRec = FormDataMgr::GetInstance().AllotFormRecord(record1, callingUid); + // Set database info. + retFormRec.formUserUids.clear(); + // Set form host record + FormItemInfo info; + FormDataMgr::GetInstance().AllotFormHostRecord(info, token_, formId, callingUid); + Want want; + EXPECT_EQ(ERR_OK, FormMgr::GetInstance().RequestForm(formId, token_, want)); + + token_->Wait(); + FormDataMgr::GetInstance().DeleteFormRecord(formId); + FormDataMgr::GetInstance().DeleteHostRecord(token_, formId); + APP_LOGI("fms_form_mgr_request_test_001 end"); +} + +/* + * Feature: FormMgrService + * Function: FormMgrClient + * SubFunction: RequestForm Function + * FunctionPoints: FormMgrClient RequestForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Abnomal case: Verify permission deny. + */ +HWTEST_F(FmsFormMgrRequestFormTest, RequestForm_002, TestSize.Level0) +{ + APP_LOGI("fms_form_mgr_request_test_002 start"); + + int64_t formId {0X0000FFAF00000000}; + FormItemInfo itemInfo; + FormDataMgr::GetInstance().AllotFormHostRecord(itemInfo, token_, formId, 0); + + Want want; + OHOS::Security::Permission::PermissionKit::RemoveDefPermissions(FORM_PROVIDER_BUNDLE_NAME); + OHOS::Security::Permission::PermissionKit::RemoveUserGrantedReqPermissions(FORM_PROVIDER_BUNDLE_NAME, 0); + OHOS::Security::Permission::PermissionKit::RemoveSystemGrantedReqPermissions(FORM_PROVIDER_BUNDLE_NAME); + EXPECT_EQ(ERR_APPEXECFWK_FORM_PERMISSION_DENY, FormMgr::GetInstance().RequestForm(formId, token_, want)); + // Permission install + std::vector permList; + Permission::PermissionDef permDef; + permDef.permissionName = PERMISSION_NAME_REQUIRE_FORM; + permDef.bundleName = FORM_PROVIDER_BUNDLE_NAME; + permDef.grantMode = Permission::GrantMode::USER_GRANT; + permDef.availableScope = Permission::AvailableScope::AVAILABLE_SCOPE_ALL; + permDef.label = DEF_LABEL1; + permDef.labelId = 1; + permDef.description = DEF_LABEL1; + permDef.descriptionId = 1; + permList.emplace_back(permDef); + Permission::PermissionKit::AddDefPermissions(permList); + Permission::PermissionKit::AddUserGrantedReqPermissions(FORM_PROVIDER_BUNDLE_NAME, {PERMISSION_NAME_REQUIRE_FORM}, + 0); + Permission::PermissionKit::GrantUserGrantedPermission(FORM_PROVIDER_BUNDLE_NAME, PERMISSION_NAME_REQUIRE_FORM, 0); + token_->Wait(); + FormDataMgr::GetInstance().DeleteFormRecord(formId); + FormDataMgr::GetInstance().DeleteHostRecord(token_, formId); + APP_LOGI("fms_form_mgr_request_test_002 end"); +} + +/* + * Feature: FormMgrService + * Function: FormMgrClient + * SubFunction: RequestForm Function + * FunctionPoints: FormMgrClient RequestForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Abnomal case: Verify invalid parameter. + */ +HWTEST_F(FmsFormMgrRequestFormTest, RequestForm_003, TestSize.Level0) +{ + APP_LOGI("fms_form_mgr_request_test_003 start"); + + int64_t formId {0X00AAAAFF00000000}; + FormItemInfo record; + int callingUid {0}; + record.SetFormId(formId); + record.SetProviderBundleName(FORM_PROVIDER_BUNDLE_NAME); + record.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + record.SetTemporaryFlag(false); + FormRecord retFormRec = FormDataMgr::GetInstance().AllotFormRecord(record, callingUid); + + Want want; + EXPECT_EQ(ERR_FORM_INVALID_PARAM, FormMgr::GetInstance().RequestForm(formId, token_, want)); + + token_->Wait(); + FormDataMgr::GetInstance().DeleteFormRecord(formId); + FormDataMgr::GetInstance().DeleteHostRecord(token_, formId); + APP_LOGI("fms_form_mgr_request_test_003 end"); +} + +/* + * Feature: FormMgrService + * Function: FormMgrClient + * SubFunction: RequestForm Function + * FunctionPoints: FormMgrClient RequestForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Abnomal case: Verify form not self. + */ +HWTEST_F(FmsFormMgrRequestFormTest, RequestForm_004, TestSize.Level0) +{ + APP_LOGI("fms_form_mgr_request_test_004 start"); + int64_t formId {0X000ABCFF00000000}; + int64_t fakeFormId {0X0ABCDEFF00000000}; + FormItemInfo record; + int callingUid {0}; + record.SetFormId(formId); + record.SetProviderBundleName(FORM_PROVIDER_BUNDLE_NAME); + record.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + record.SetTemporaryFlag(false); + FormRecord retFormRec = FormDataMgr::GetInstance().AllotFormRecord(record, callingUid); + + FormItemInfo itemInfo; + FormDataMgr::GetInstance().AllotFormHostRecord(itemInfo, token_, fakeFormId, 0); + + Want want; + EXPECT_EQ(ERR_OPERATION_FORM_NOT_SELF, FormMgr::GetInstance().RequestForm(formId, token_, want)); + + token_->Wait(); + FormDataMgr::GetInstance().DeleteFormRecord(formId); + FormDataMgr::GetInstance().DeleteHostRecord(token_, formId); + APP_LOGI("fms_form_mgr_request_test_004 end"); +} +} \ No newline at end of file diff --git a/services/formmgr/test/unittest/fms_form_mgr_update_form_test/BUILD.gn b/services/formmgr/test/unittest/fms_form_mgr_update_form_test/BUILD.gn new file mode 100644 index 0000000000..372c883790 --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_mgr_update_form_test/BUILD.gn @@ -0,0 +1,86 @@ +# Copyright (c) 2021 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/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/formmgrservice" + +ohos_unittest("FmsFormMgrUpdateFormTest") { + module_out_path = module_output_path + + sources = [ + "//foundation/appexecfwk/standard/interfaces/innerkits/fmskit/native/src/form_mgr.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_bundle_manager.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_form_host_client.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_form_provider_client.cpp", + ] + sources += [ "fms_form_mgr_update_form_test.cpp" ] + + include_dirs = [ + "//third_party/zlib/contrib/minizip", + "//third_party/zlib", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/fmskit/native/include/", + "//foundation/appexecfwk/standard/common/log/include/", + "//foundation/appexecfwk/standard/services/formmgr/include", + "//foundation/appexecfwk/standard/services/bundlemgr/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base/include/", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/formmgr/", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include/", + "//foundation/distributedschedule/samgr/adapter/interfaces/innerkits/include/", + ] + + configs = [ + "${services_path}/formmgr/test:formmgr_test_config", + "//foundation/aafwk/standard/services/abilitymgr:abilityms_config", + + # "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:bundlemgr_sdk_config", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:formmgr_sdk_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/common:libappexecfwk_common", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${appexecfwk_path}/interfaces/innerkits/fmskit:fmskit_native", + "${libs_path}/libeventhandler:libeventhandler_target", + "${services_path}/formmgr:fms_target", + "//base/security/permission/interfaces/innerkits/permission_standard/permissionsdk:libpermissionsdk_standard", + "//base/startup/appspawn_standard:appspawn_socket_client", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + + #"${services_path}/bundlemgr:bms_target", + "//foundation/aafwk/standard/services/abilitymgr:abilityms_target", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/googletest:gmock_main", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":FmsFormMgrUpdateFormTest" ] +} diff --git a/services/formmgr/test/unittest/fms_form_mgr_update_form_test/fms_form_mgr_update_form_test.cpp b/services/formmgr/test/unittest/fms_form_mgr_update_form_test/fms_form_mgr_update_form_test.cpp new file mode 100644 index 0000000000..0f051fc1b0 --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_mgr_update_form_test/fms_form_mgr_update_form_test.cpp @@ -0,0 +1,400 @@ +/* + * Copyright (c) 2021 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 "form_ams_helper.h" +#include "form_bms_helper.h" +#include "form_data_mgr.h" +#include "form_host_interface.h" +#define private public +#include "form_mgr.h" +#undef private +#include "form_mgr_service.h" +#include "if_system_ability_manager.h" +#include "inner_bundle_info.h" +#include "ipc_skeleton.h" +#include "iservice_registry.h" + +#include "mock_ability_manager.h" +#include "mock_bundle_manager.h" +#include "mock_form_host_client.h" +#include "permission/permission_kit.h" +#include "permission/permission.h" +#include "running_process_info.h" +#include "system_ability_definition.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; +using namespace OHOS::Security; + +namespace { +const std::string PERMISSION_NAME_REQUIRE_FORM = "ohos.permission.REQUIRE_FORM"; +const std::string PARAM_PROVIDER_PACKAGE_NAME = "com.form.provider.app.test.abiliy"; +const std::string FORM_PROVIDER_BUNDLE_NAME = "com.form.provider.service"; +const std::string PARAM_PROVIDER_MODULE_NAME = "com.form.provider.app.test.abiliy"; +const std::string FORM_PROVIDER_ABILITY_NAME = "com.form.provider.app.test.abiliy"; +const std::string PARAM_FORM_NAME = "com.form.name.test"; +const std::string FORM_JS_COMPOMENT_NAME = "jsComponentName"; +const std::string FORM_PROVIDER_MODULE_SOURCE_DIR = ""; +const std::string FORM_HOST_BUNDLE_NAME = "com.form.host.app"; +const std::string DEVICE_ID = "ohos-phone1"; +const std::string DEF_LABEL1 = "PermissionFormRequireGrant"; + +class FmsFormMgrUpdateFormTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + +protected: + sptr token_; + std::shared_ptr formyMgrServ_ = DelayedSingleton::GetInstance(); + + sptr mockBundleMgr_; + sptr mockAbilityMgrServ_; +}; + +void FmsFormMgrUpdateFormTest::SetUpTestCase() +{} + +void FmsFormMgrUpdateFormTest::TearDownTestCase() +{} + +void FmsFormMgrUpdateFormTest::SetUp() +{ + APP_LOGI("fms_form_mgr_client_updateForm_test_001 setup"); + + formyMgrServ_->OnStart(); + + mockBundleMgr_ = new (std::nothrow) BundleMgrService(); + ASSERT_TRUE(mockBundleMgr_ != nullptr); + FormBmsHelper::GetInstance().SetBundleManager(mockBundleMgr_); + + mockAbilityMgrServ_ = new (std::nothrow) MockAbilityMgrService(); + FormAmsHelper::GetInstance().SetAbilityManager(mockAbilityMgrServ_); + + token_ = new (std::nothrow) MockFormHostClient(); + + // Permission install + std::vector permList; + Permission::PermissionDef permDef; + permDef.permissionName = PERMISSION_NAME_REQUIRE_FORM; + permDef.bundleName = FORM_PROVIDER_BUNDLE_NAME; + permDef.grantMode = Permission::GrantMode::USER_GRANT; + permDef.availableScope = Permission::AvailableScope::AVAILABLE_SCOPE_ALL; + permDef.label = DEF_LABEL1; + permDef.labelId = 1; + permDef.description = DEF_LABEL1; + permDef.descriptionId = 1; + permList.emplace_back(permDef); + Permission::PermissionKit::AddDefPermissions(permList); + Permission::PermissionKit::AddUserGrantedReqPermissions(FORM_PROVIDER_BUNDLE_NAME, {PERMISSION_NAME_REQUIRE_FORM}, + 0); + Permission::PermissionKit::GrantUserGrantedPermission(FORM_PROVIDER_BUNDLE_NAME, PERMISSION_NAME_REQUIRE_FORM, 0); +} + +void FmsFormMgrUpdateFormTest::TearDown() +{} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: UpdateForm Function + * FunctionPoints: FormMgr UpdateForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if FormMgr invoke UpdateForm works. + */ +HWTEST_F(FmsFormMgrUpdateFormTest, UpdateForm_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_client_updateForm_test_001 start"; + + // param editor + int64_t formId {100L}; + int32_t callingUid {0}; + std::string bandleName = FORM_HOST_BUNDLE_NAME; + FormProviderData formProviderData = FormProviderData(std::string("{\"city\": \"beijing001\"}")); + + // add formRecord + FormItemInfo formItemInfo; + formItemInfo.SetFormId(formId); + formItemInfo.SetProviderBundleName(FORM_HOST_BUNDLE_NAME); + formItemInfo.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + formItemInfo.SetTemporaryFlag(false); + FormDataMgr::GetInstance().AllotFormRecord(formItemInfo, callingUid); + + FormItemInfo formItemInfo1; + formItemInfo1.SetFormId(1000L); + formItemInfo1.SetProviderBundleName(FORM_HOST_BUNDLE_NAME); + formItemInfo1.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + formItemInfo1.SetTemporaryFlag(true); + FormDataMgr::GetInstance().AllotFormRecord(formItemInfo1, callingUid); + + // add formHostRecord + FormItemInfo itemInfo; + FormDataMgr::GetInstance().AllotFormHostRecord(itemInfo, token_, formId, callingUid); + + // test exec + EXPECT_EQ(ERR_OK, FormMgr::GetInstance().UpdateForm(formId, bandleName, formProviderData)); + + token_->Wait(); + + GTEST_LOG_(INFO) << "fms_form_mgr_client_updateForm_test_001 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: UpdateForm Function + * FunctionPoints: FormMgr UpdateForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if FormMgr invoke UpdateForm works when permission denied. + */ +HWTEST_F(FmsFormMgrUpdateFormTest, UpdateForm_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_client_updateForm_test_002 start"; + + // param editor + int64_t formId {200L}; + int32_t callingUid {0}; + std::string bandleName = FORM_HOST_BUNDLE_NAME; + FormProviderData formProviderData = FormProviderData(std::string("{\"city\": \"beijing002\"}")); + + // add formRecord + FormItemInfo formItemInfo; + formItemInfo.SetFormId(formId); + formItemInfo.SetProviderBundleName(FORM_HOST_BUNDLE_NAME); + formItemInfo.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + formItemInfo.SetTemporaryFlag(false); + FormDataMgr::GetInstance().AllotFormRecord(formItemInfo, callingUid); + + // add formHostRecord + FormItemInfo itemInfo; + FormDataMgr::GetInstance().AllotFormHostRecord(itemInfo, token_, formId, callingUid); + + // del permission + Permission::PermissionKit::RevokeUserGrantedPermission(FORM_PROVIDER_BUNDLE_NAME, PERMISSION_NAME_REQUIRE_FORM, + callingUid); + + // test exec + EXPECT_EQ(ERR_APPEXECFWK_FORM_PERMISSION_DENY, FormMgr::GetInstance().UpdateForm(formId, bandleName, + formProviderData)); + + // add permission + Permission::PermissionKit::GrantUserGrantedPermission(FORM_PROVIDER_BUNDLE_NAME, PERMISSION_NAME_REQUIRE_FORM, + callingUid); + + GTEST_LOG_(INFO) << "fms_form_mgr_client_updateForm_test_002 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: UpdateForm Function + * FunctionPoints: FormMgr UpdateForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if FormMgr invoke UpdateForm works when passing bandleName is empty. + */ +HWTEST_F(FmsFormMgrUpdateFormTest, UpdateForm_003, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_client_updateForm_test_003 start"; + + // param editor + int64_t formId {300L}; + int32_t callingUid {0}; + std::string bandleName = ""; + FormProviderData formProviderData; + + // add formRecord + FormItemInfo formItemInfo; + formItemInfo.SetFormId(formId); + formItemInfo.SetProviderBundleName(FORM_HOST_BUNDLE_NAME); + formItemInfo.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + formItemInfo.SetTemporaryFlag(false); + FormDataMgr::GetInstance().AllotFormRecord(formItemInfo, callingUid); + + // add formHostRecord + FormItemInfo itemInfo; + FormDataMgr::GetInstance().AllotFormHostRecord(itemInfo, token_, formId, callingUid); + + // test exec + EXPECT_EQ(ERR_FORM_INVALID_PARAM, FormMgr::GetInstance().UpdateForm(formId, bandleName, formProviderData)); + + GTEST_LOG_(INFO) << "fms_form_mgr_client_updateForm_test_003 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: UpdateForm Function + * FunctionPoints: FormMgr UpdateForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if FormMgr invoke UpdateForm works when bandleName not match. + */ +HWTEST_F(FmsFormMgrUpdateFormTest, UpdateForm_004, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_client_updateForm_test_004 start"; + + // param editor + int64_t formId {400L}; + int32_t callingUid {0}; + std::string bandleName = FORM_PROVIDER_BUNDLE_NAME; + FormProviderData formProviderData = FormProviderData(std::string("{\"city\": \"beijing004\"}")); + + // add formRecord + FormItemInfo formItemInfo; + formItemInfo.SetFormId(formId); + formItemInfo.SetProviderBundleName(FORM_HOST_BUNDLE_NAME); + formItemInfo.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + formItemInfo.SetTemporaryFlag(false); + FormDataMgr::GetInstance().AllotFormRecord(formItemInfo, callingUid); + + // add formHostRecord + FormItemInfo itemInfo; + FormDataMgr::GetInstance().AllotFormHostRecord(itemInfo, token_, formId, callingUid); + + // test exec + EXPECT_EQ(ERR_FORM_INVALID_PARAM, FormMgr::GetInstance().UpdateForm(formId, bandleName, formProviderData)); + + GTEST_LOG_(INFO) << "fms_form_mgr_client_updateForm_test_004 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: UpdateForm Function + * FunctionPoints: FormMgr UpdateForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if FormMgr invoke UpdateForm works when not under current user. + */ +HWTEST_F(FmsFormMgrUpdateFormTest, UpdateForm_005, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_client_updateForm_test_005 start"; + + // param editor + int64_t formId {500L}; + int32_t callingUid {1}; + std::string bandleName = FORM_HOST_BUNDLE_NAME; + FormProviderData formProviderData = FormProviderData(std::string("{\"city\": \"beijing005\"}")); + + // add formRecord + FormItemInfo formItemInfo; + formItemInfo.SetFormId(formId); + formItemInfo.SetProviderBundleName(FORM_HOST_BUNDLE_NAME); + formItemInfo.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + formItemInfo.SetTemporaryFlag(false); + FormDataMgr::GetInstance().AllotFormRecord(formItemInfo, callingUid); + + // add formHostRecord + FormItemInfo itemInfo; + FormDataMgr::GetInstance().AllotFormHostRecord(itemInfo, token_, formId, callingUid); + + // test exec + EXPECT_EQ(ERR_NOT_EXIST_ID, FormMgr::GetInstance().UpdateForm(formId, bandleName, formProviderData)); + + GTEST_LOG_(INFO) << "fms_form_mgr_client_updateForm_test_005 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: UpdateForm Function + * FunctionPoints: FormMgr UpdateForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if FormMgr invoke UpdateForm works when the updated form is not your own. + */ +HWTEST_F(FmsFormMgrUpdateFormTest, UpdateForm_006, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_client_updateForm_test_006 start"; + + // param editor + int64_t formId {600L}; + int32_t callingUid {0}; + std::string bandleName = "com.form.host.app600"; + FormProviderData formProviderData = FormProviderData(std::string("{\"city\": \"beijing006\"}")); + + // add formRecord + FormItemInfo formItemInfo; + formItemInfo.SetFormId(formId); + formItemInfo.SetProviderBundleName(FORM_HOST_BUNDLE_NAME); + formItemInfo.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + formItemInfo.SetTemporaryFlag(false); + FormDataMgr::GetInstance().AllotFormRecord(formItemInfo, callingUid); + + // add formHostRecord + FormItemInfo itemInfo; + FormDataMgr::GetInstance().AllotFormHostRecord(itemInfo, token_, formId, callingUid); + + // test exec + EXPECT_EQ(ERR_FORM_INVALID_PARAM, FormMgr::GetInstance().UpdateForm(formId, bandleName, formProviderData)); + + GTEST_LOG_(INFO) << "fms_form_mgr_client_updateForm_test_006 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: UpdateForm Function + * FunctionPoints: FormMgr UpdateForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if FormMgr invoke UpdateForm works. + */ +HWTEST_F(FmsFormMgrUpdateFormTest, UpdateForm_007, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_client_updateForm_test_007 start"; + + // param editor + int64_t formId {700L}; + int32_t callingUid {0}; + std::string bandleName = FORM_HOST_BUNDLE_NAME; + std::string jsonData = std::string("{"); + for (int i = 0; i < 1024; i = i + 1) { + jsonData = jsonData + std::string("\"city" + std::to_string(i) + "\"" + ":" + "\"beijing007\""); + if (i != 1023) { + jsonData = jsonData + std::string(", "); + } + } + jsonData = jsonData + std::string("}"); + FormProviderData formProviderData = FormProviderData(jsonData); + + // add formRecord + FormItemInfo formItemInfo; + formItemInfo.SetFormId(formId); + formItemInfo.SetProviderBundleName(FORM_HOST_BUNDLE_NAME); + formItemInfo.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + formItemInfo.SetTemporaryFlag(false); + FormRecord formRecord = FormDataMgr::GetInstance().AllotFormRecord(formItemInfo, callingUid); + formRecord.versionUpgrade = true; + + FormItemInfo formItemInfo1; + formItemInfo1.SetFormId(7000L); + formItemInfo1.SetProviderBundleName(FORM_HOST_BUNDLE_NAME); + formItemInfo1.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + formItemInfo1.SetTemporaryFlag(true); + FormRecord formRecord1 = FormDataMgr::GetInstance().AllotFormRecord(formItemInfo1, callingUid); + + // add formHostRecord + FormItemInfo itemInfo; + FormDataMgr::GetInstance().AllotFormHostRecord(itemInfo, token_, formId, callingUid); + + // test exec + EXPECT_EQ(ERR_OK, FormMgr::GetInstance().UpdateForm(formId, bandleName, formProviderData)); + + token_->Wait(); + + GTEST_LOG_(INFO) << "fms_form_mgr_client_updateForm_test_007 end"; +} +} \ No newline at end of file diff --git a/services/formmgr/test/unittest/fms_form_provider_data_test/BUILD.gn b/services/formmgr/test/unittest/fms_form_provider_data_test/BUILD.gn new file mode 100644 index 0000000000..32cbcbf7e4 --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_provider_data_test/BUILD.gn @@ -0,0 +1,65 @@ +# Copyright (c) 2021 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/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/formmgrservice" + +ohos_unittest("FmsFormProviderDataTest") { + module_out_path = module_output_path + + sources = [ "//foundation/appexecfwk/standard/services/formmgr/test/unittest/fms_form_provider_data_test/fms_form_provider_data_test.cpp" ] + + include_dirs = [ + "//third_party/json/include", + "//foundation/appexecfwk/standard/common/log/include/", + "//foundation/appexecfwk/standard/services/formmgr/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base/include/", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/formmgr/", + + #"//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/bundlemgr/", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include/", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler/include", + ] + + configs = [ "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:formmgr_sdk_config" ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/common:libappexecfwk_common", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${services_path}/formmgr:fms_target", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +############################################################################### +group("unittest") { + testonly = true + + deps = [ ":FmsFormProviderDataTest" ] +} +############################################################################### diff --git a/services/formmgr/test/unittest/fms_form_provider_data_test/fms_form_provider_data_test.cpp b/services/formmgr/test/unittest/fms_form_provider_data_test/fms_form_provider_data_test.cpp new file mode 100644 index 0000000000..31c9bd4191 --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_provider_data_test/fms_form_provider_data_test.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2021 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 +#include +#include +#include +#include + +#include "app_log_wrapper.h" +#define private public +#include "form_provider_data.h" +#undef private +#include "nlohmann/json.hpp" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; + +namespace { +const char* FORM_DB_DATA_BASE_FILE_DIR = "/data/formmgr"; +const int32_t four = 4; +const int32_t ten = 10; +const int32_t eleven = 11; + +class FmsFormProviderDataTest : public testing::Test { +public: + void SetUp(); + void Test(); + bool InitJsonData(); + bool InitJsonData2(); + bool CreateJsonFileByJsonData1(const nlohmann::json &jsonData); + bool CreateJsonFileByJsonData2(const nlohmann::json &jsonData); + bool CreateMergeJsonFileByJsonData3(const nlohmann::json &jsonData); + // bool createJsonFileByStringData(); + + nlohmann::json jsonData_; +}; +void FmsFormProviderDataTest::SetUp() +{ + DIR *dirptr = opendir(FORM_DB_DATA_BASE_FILE_DIR); + if (dirptr == nullptr) { + APP_LOGW("%{public}s, opendir is fail", __func__); + if (-1 == mkdir(FORM_DB_DATA_BASE_FILE_DIR, S_IRWXU)) { + APP_LOGE("%{public}s, dir create fail", __func__); + return; + } + } else { + closedir(dirptr); + } +} + +bool FmsFormProviderDataTest::InitJsonData() +{ + nlohmann::json tmpJson; + tmpJson["name"] = "li"; + tmpJson["age"] = ten; + jsonData_["0"] = tmpJson; + return true; +} + +bool FmsFormProviderDataTest::InitJsonData2() +{ + nlohmann::json tmpJson; + tmpJson["name"] = "wang"; + tmpJson["age"] = eleven; + jsonData_["1"] = tmpJson; + return true; +} + +bool FmsFormProviderDataTest::CreateJsonFileByJsonData1(const nlohmann::json &jsonData) +{ + std::ofstream o("/data/formmgr/ByJsonFile1.json"); + o.close(); + + std::fstream f("/data/formmgr/ByJsonFile1.json"); + if(f.good() == false) { + return false; + } + + f << std::setw(four) << jsonData << std::endl; + + f.close(); + return true; +} + +bool FmsFormProviderDataTest::CreateJsonFileByJsonData2(const nlohmann::json &jsonData) +{ + std::ofstream o("/data/formmgr/ByJsonFile2.json"); + o.close(); + + std::fstream f("/data/formmgr/ByJsonFile2.json"); + if(f.good() == false) { + return false; + } + + f << std::setw(four) << jsonData << std::endl; + + f.close(); + return true; +} + +bool FmsFormProviderDataTest::CreateMergeJsonFileByJsonData3(const nlohmann::json &jsonData) +{ + std::ofstream o("/data/formmgr/ByJsonFile3.json"); + o.close(); + + std::fstream f("/data/formmgr/ByJsonFile3.json"); + if(f.good() == false) { + return false; + } + + f << std::setw(four) << jsonData << std::endl; + + f.close(); + return true; +} + +HWTEST_F(FmsFormProviderDataTest, FmsFormProviderDataTest_001, TestSize.Level0) // create +{ + GTEST_LOG_(INFO) << "FmsFormProviderDataTest_001 start"; + EXPECT_EQ(true, InitJsonData()); + FormProviderData formProviderData(jsonData_); + EXPECT_EQ(true, CreateJsonFileByJsonData1(formProviderData.jsonFormProviderData_)); + GTEST_LOG_(INFO) << "FmsFormProviderDataTest_001 end"; +} + +HWTEST_F(FmsFormProviderDataTest, FmsFormProviderDataTest_002, TestSize.Level0) // test constructor with string +{ + GTEST_LOG_(INFO) << "FmsFormProviderDataTest_002 start"; + EXPECT_EQ(true, InitJsonData()); + FormProviderData formProviderData(jsonData_.dump()); + EXPECT_EQ(true, CreateJsonFileByJsonData2(formProviderData.jsonFormProviderData_)); + GTEST_LOG_(INFO) << "FmsFormProviderDataTest_002 end"; +} + +HWTEST_F(FmsFormProviderDataTest, FmsFormProviderDataTest_003, TestSize.Level0) // test GetDataString +{ + GTEST_LOG_(INFO) << "FmsFormProviderDataTest_003 start"; + EXPECT_EQ(true, InitJsonData()); + FormProviderData formProviderData(jsonData_); + GTEST_LOG_(INFO) << "print:" < +#include "form_ams_helper.h" +#include "form_bms_helper.h" +#define private public +#include "form_data_mgr.h" +#include "form_db_cache.h" +#include "form_refresh_limiter.h" +#include "form_host_interface.h" +#include "form_mgr.h" +#undef private +#include "form_mgr_service.h" +#include "form_provider_mgr.h" +#include "if_system_ability_manager.h" +#include "inner_bundle_info.h" +#include "ipc_skeleton.h" +#include "iservice_registry.h" + +#include "mock_ability_manager.h" +#include "mock_bundle_manager.h" +#include "mock_form_host_client.h" +#include "permission/permission_kit.h" +#include "permission/permission.h" +#include "running_process_info.h" +#include "system_ability_definition.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; +using namespace OHOS::Security; + +namespace { +const std::string PERMISSION_NAME_REQUIRE_FORM = "ohos.permission.REQUIRE_FORM"; +const std::string PARAM_PROVIDER_PACKAGE_NAME = "com.form.provider.app.test.abiliy"; +const std::string FORM_PROVIDER_BUNDLE_NAME = "com.form.provider.service"; +const std::string PARAM_PROVIDER_MODULE_NAME = "com.form.provider.app.test.abiliy"; +const std::string FORM_PROVIDER_ABILITY_NAME = "com.form.provider.app.test.abiliy"; +const std::string PARAM_FORM_NAME = "com.form.name.test"; + +const std::string FORM_JS_COMPOMENT_NAME = "jsComponentName"; +const std::string FORM_PROVIDER_MODULE_SOURCE_DIR = ""; + +const std::string FORM_HOST_BUNDLE_NAME = "com.form.host.app"; + +const std::string DEVICE_ID = "ohos-phone1"; +const std::string DEF_LABEL1 = "PermissionFormRequireGrant"; + +class FmsFormProviderMgrTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + +protected: + sptr token_; + std::shared_ptr formyMgrServ_ = DelayedSingleton::GetInstance(); + + sptr mockBundleMgr_; + sptr mockAbilityMgrServ_; +}; + +void FmsFormProviderMgrTest::SetUpTestCase() +{} + +void FmsFormProviderMgrTest::TearDownTestCase() +{} + +void FmsFormProviderMgrTest::SetUp() +{ + // APP_LOGI("fms_form_mgr_client_test_001 setup"); + formyMgrServ_->OnStart(); + + mockBundleMgr_ = new (std::nothrow) BundleMgrService(); + EXPECT_TRUE(mockBundleMgr_ != nullptr); + FormBmsHelper::GetInstance().SetBundleManager(mockBundleMgr_); + + mockAbilityMgrServ_ = new (std::nothrow) MockAbilityMgrService(); + FormAmsHelper::GetInstance().SetAbilityManager(mockAbilityMgrServ_); + + // APP_LOGI("fms_form_mgr_client_test_001 FormMgrService started"); + token_ = new (std::nothrow) MockFormHostClient(); + + // Permission install + std::vector permList; + Permission::PermissionDef permDef; + permDef.permissionName = PERMISSION_NAME_REQUIRE_FORM; + permDef.bundleName = FORM_PROVIDER_BUNDLE_NAME; + permDef.grantMode = Permission::GrantMode::USER_GRANT; + permDef.availableScope = Permission::AvailableScope::AVAILABLE_SCOPE_ALL; + permDef.label = DEF_LABEL1; + permDef.labelId = 1; + permDef.description = DEF_LABEL1; + permDef.descriptionId = 1; + permList.emplace_back(permDef); + Permission::PermissionKit::AddDefPermissions(permList); + Permission::PermissionKit::AddUserGrantedReqPermissions(FORM_PROVIDER_BUNDLE_NAME, {PERMISSION_NAME_REQUIRE_FORM}, + 0); + Permission::PermissionKit::GrantUserGrantedPermission(FORM_PROVIDER_BUNDLE_NAME, PERMISSION_NAME_REQUIRE_FORM, 0); +} + +void FmsFormProviderMgrTest::TearDown() +{} + +/* + * Feature: FmsFormProviderMgr + * Function: FormMgr + * SubFunction: AcquireForm Function + * FunctionPoints: FormMgr AcquireForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if AcquireForm works with invalid formid. + */ + +HWTEST_F(FmsFormProviderMgrTest, AcquireForm_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_provider_test_001 start"; + int64_t formId = 0x114514aa00000000; + FormProviderInfo formProviderInfo; + EXPECT_EQ(ERR_FORM_INVALID_PARAM, FormProviderMgr::GetInstance().AcquireForm(-114514L, formProviderInfo)); + int callingUid {0}; + FormItemInfo record; + record.SetFormId(formId); + FormRecord realFormRecord = FormDataMgr::GetInstance().AllotFormRecord(record, callingUid); + FormItemInfo info; + FormDataMgr::GetInstance().AllotFormHostRecord(info, token_, formId, callingUid); + GTEST_LOG_(INFO) << "fms_form_mgr_provider_test_001 end"; +} + +/* + * Feature: FmsFormProviderMgr + * Function: FormMgr + * SubFunction: AcquireForm Function + * FunctionPoints: FormMgr AcquireForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if AcquireForm works without formrecord. + */ + +HWTEST_F(FmsFormProviderMgrTest, AcquireForm_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_provider_test_002 start"; + int64_t formId = 0x11451aaa00000000; + FormProviderInfo formProviderInfo; + EXPECT_EQ(ERR_APPEXECFWK_FORM_INFO_NOT_EXIST,FormProviderMgr::GetInstance().AcquireForm(formId,formProviderInfo)); + int callingUid {0}; + FormItemInfo record; + record.SetFormId(formId); + FormRecord realFormRecord = FormDataMgr::GetInstance().AllotFormRecord(record, callingUid); + FormItemInfo info; + FormDataMgr::GetInstance().AllotFormHostRecord(info, token_, formId, callingUid); + GTEST_LOG_(INFO) << "fms_form_mgr_provider_test_002 end"; +} + + +/* + * Feature: FmsFormProviderMgr + * Function: FormMgr + * SubFunction: AcquireForm Function + * FunctionPoints: FormMgr AcquireForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if AcquireForm works without form host record. + */ + +HWTEST_F(FmsFormProviderMgrTest, AcquireForm_003, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_provider_test_003 start"; + int64_t formId = 0x1145aaaa00000000; + FormProviderInfo formProviderInfo; + int callingUid {0}; + FormItemInfo record; + record.SetFormId(formId); + FormRecord realFormRecord = FormDataMgr::GetInstance().AllotFormRecord(record, callingUid); + EXPECT_EQ(ERR_APPEXECFWK_FORM_HOST_INFO_NOT_EXIST, + FormProviderMgr::GetInstance().AcquireForm(formId,formProviderInfo)); + FormItemInfo info; + FormDataMgr::GetInstance().AllotFormHostRecord(info, token_, formId, callingUid); + GTEST_LOG_(INFO) << "fms_form_mgr_provider_test_003 end"; +} + + +/* + * Feature: FmsFormProviderMgr + * Function: FormMgr + * SubFunction: RefreshForm Function + * FunctionPoints: FormMgr RefreshForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if RefreshForm works without form host record. + */ + +HWTEST_F(FmsFormProviderMgrTest, RefreshForm_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_provider_test_004 start"; + int64_t formId = 0x1145aaaa00001200; + Want want; + int callingUid {0}; + EXPECT_EQ(ERR_APPEXECFWK_FORM_INFO_NOT_EXIST, FormProviderMgr::GetInstance().RefreshForm(formId, want)); + FormItemInfo record; + record.SetFormId(formId); + record.SetModuleName(PARAM_FORM_NAME); + record.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + FormRecord realFormRecord = FormDataMgr::GetInstance().AllotFormRecord(record, callingUid); + FormItemInfo info; + FormDataMgr::GetInstance().AllotFormHostRecord(info, token_, formId, callingUid); + GTEST_LOG_(INFO) << "fms_form_mgr_provider_test_004 end"; +} + +/* + * Feature: FmsFormProviderMgr + * Function: FormMgr + * SubFunction: RefreshForm Function + * FunctionPoints: FormMgr RefreshForm interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if RefreshForm works without form host record. + */ + +HWTEST_F(FmsFormProviderMgrTest, RefreshForm_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_mgr_provider_test_005 start"; + int64_t formId = 0x114514aa00000000; + Want want; + want.SetParam(Constants::KEY_IS_TIMER, true); + int callingUid {0}; + FormItemInfo record; + record.SetFormId(formId); + record.SetModuleName(PARAM_FORM_NAME); + record.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + FormRecord realFormRecord = FormDataMgr::GetInstance().AllotFormRecord(record, callingUid); + FormItemInfo info; + FormDataMgr::GetInstance().AllotFormHostRecord(info, token_, formId, callingUid); + EXPECT_EQ(ERR_APPEXECFWK_FORM_SUPPLIER_DEL_FAIL, FormProviderMgr::GetInstance().RefreshForm(formId, want)); + GTEST_LOG_(INFO) << "fms_form_mgr_provider_test_005 end"; +} +} \ No newline at end of file diff --git a/services/formmgr/test/unittest/fms_form_set_next_refresh_test/BUILD.gn b/services/formmgr/test/unittest/fms_form_set_next_refresh_test/BUILD.gn new file mode 100644 index 0000000000..16adef3efe --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_set_next_refresh_test/BUILD.gn @@ -0,0 +1,87 @@ +# Copyright (c) 2021 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/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/formmgrservice" + +ohos_unittest("FmsFormSetNextRefreshTest") { + module_out_path = module_output_path + + sources = [ + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_bundle_manager.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/unittest/fms_form_set_next_refresh_test/fms_form_set_next_refresh_test.cpp", + ] + + include_dirs = [ + "//third_party/json/include", + "//foundation/appexecfwk/standard/common/log/include/", + "//foundation/appexecfwk/standard/services/formmgr/include", + "//foundation/appexecfwk/standard/services/bundlemgr/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/formmgr/", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/bundlemgr/", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include/", + "//foundation/distributedschedule/samgr/adapter/interfaces/innerkits/include/", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler/include", + "//base/notification/ces_standard/cesfwk/kits/native/include", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/include", + "//base/security/permission/interfaces/innerkits/permission_standard/permissionsdk/main/cpp/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/fmskit/native/include/", + ] + + configs = [ + "${services_path}/formmgr/test:formmgr_test_config", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:formmgr_sdk_config", + + #"${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:bundlemgr_sdk_config", + #"//foundation/appexecfwk/standard/services/formmgr:formmgr_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/common:libappexecfwk_common", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${appexecfwk_path}/interfaces/innerkits/fmskit:fmskit_native", + "${services_path}/formmgr:fms_target", + "//base/security/permission/interfaces/innerkits/permission_standard/permissionsdk:libpermissionsdk_standard", + + #"${libs_path}/libeventhandler:libeventhandler_target", + #"//base/startup/appspawn_standard:appspawn_socket_client", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/googletest:gmock_main", + "//utils/native/base:utils", + ] + + external_deps = [ + "ces_standard:cesfwk_core", + "ces_standard:cesfwk_innerkits", + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +############################################################################### +group("unittest") { + testonly = true + + deps = [ ":FmsFormSetNextRefreshTest" ] +} +############################################################################### diff --git a/services/formmgr/test/unittest/fms_form_set_next_refresh_test/fms_form_set_next_refresh_test.cpp b/services/formmgr/test/unittest/fms_form_set_next_refresh_test/fms_form_set_next_refresh_test.cpp new file mode 100644 index 0000000000..76a978a789 --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_set_next_refresh_test/fms_form_set_next_refresh_test.cpp @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2021 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 +#include + +#include "app_log_wrapper.h" +#include "appexecfwk_errors.h" +#define private public +#include "form_bms_helper.h" +#include "form_constants.h" +#include "form_timer_mgr.h" +#include "form_mgr_service.h" +#include "form_mgr_adapter.h" +#include "form_data_mgr.h" +#undef private +#include "mock_bundle_manager.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; + +namespace { +const std::string FORM_HOST_BUNDLE_NAME = "com.form.provider.service"; +const std::string FORM_PROVIDER_ABILITY_NAME = "com.form.provider.app.test.abiliy"; +const std::string PERMISSION_NAME_REQUIRE_FORM = "ohos.permission.REQUIRE_FORM"; +const std::string DEF_LABEL1 = "PermissionFormRequireGrant"; + +class FmsFormSetNextRefreshTest : public testing::Test { +public: + FmsFormSetNextRefreshTest() : formSetNextRefresh_(nullptr) + {} + ~FmsFormSetNextRefreshTest() + {} + std::shared_ptr formSetNextRefresh_ = DelayedSingleton::GetInstance(); + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +protected: + sptr mockBundleMgr_; +}; +void FmsFormSetNextRefreshTest::SetUpTestCase(void) +{} + +void FmsFormSetNextRefreshTest::TearDownTestCase(void) +{} + +void FmsFormSetNextRefreshTest::SetUp(void) +{ + formSetNextRefresh_ = std::make_shared(); + + formSetNextRefresh_->OnStart(); + + // mock BundleMgr + mockBundleMgr_ = new (std::nothrow) BundleMgrService(); + ASSERT_TRUE(mockBundleMgr_ != nullptr); + FormBmsHelper::GetInstance().SetBundleManager(mockBundleMgr_); +} + +void FmsFormSetNextRefreshTest::TearDown(void) +{} + + +/** + * @tc.number: FmsFormSetNextRefreshTest_SetNextRefreshTime_001 + * @tc.name: SetNextRefreshTime + * @tc.desc: Verify that the return value is true.(formId is invalid) + */ +HWTEST_F(FmsFormSetNextRefreshTest, FmsFormSetNextRefreshTest_SetNextRefreshTime_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormSetNextRefreshTest_SetNextRefreshTime_001 start"; + int64_t formId = 0; // invalid formId + int64_t nextTime = Constants::MIN_NEXT_TIME; + + EXPECT_EQ(ERR_FORM_INVALID_PARAM, formSetNextRefresh_->SetNextRefreshTime(formId, nextTime)); + GTEST_LOG_(INFO) << "FmsFormSetNextRefreshTest_SetNextRefreshTime_001 end"; +} + +/** + * @tc.number: FmsFormSetNextRefreshTest_SetNextRefreshTime_002 + * @tc.name: SetNextRefreshTime + * @tc.desc: Verify that the return value is true.(not found in form record) + */ +HWTEST_F(FmsFormSetNextRefreshTest, FmsFormSetNextRefreshTest_SetNextRefreshTime_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormSetNextRefreshTest_SetNextRefreshTime_002 start"; + int64_t formId = 2; + int64_t nextTime = Constants::MIN_NEXT_TIME; + + EXPECT_EQ(ERR_APPEXECFWK_FORM_INFO_NOT_EXIST, formSetNextRefresh_->SetNextRefreshTime(formId, nextTime)); + GTEST_LOG_(INFO) << "FmsFormSetNextRefreshTest_SetNextRefreshTime_002 end"; +} + +/** + * @tc.number: FmsFormSetNextRefreshTest_SetNextRefreshTime_003 + * @tc.name: SetNextRefreshTime + * @tc.desc: Verify that the return value is true.(BundleName is found in form record, but no dynamicRefreshTask) + */ +HWTEST_F(FmsFormSetNextRefreshTest, FmsFormSetNextRefreshTest_SetNextRefreshTime_003, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormSetNextRefreshTest_SetNextRefreshTime_003 start"; + int64_t formId = 3; + int64_t nextTime = Constants::MIN_NEXT_TIME; + + // check dynamicRefreshTasks_ + EXPECT_EQ(true, FormTimerMgr::GetInstance().dynamicRefreshTasks_.empty()); + + // creat formRecords_ + FormItemInfo iteminfo; + iteminfo.formId_ = formId; + iteminfo.providerBundleName_ = FORM_HOST_BUNDLE_NAME; + iteminfo.abilityName_ = FORM_PROVIDER_ABILITY_NAME; + FormDataMgr::GetInstance().AllotFormRecord(iteminfo, 0); + + EXPECT_EQ(ERR_OK, formSetNextRefresh_->SetNextRefreshTime(formId, nextTime)); + + // check dynamicRefreshTasks_ + EXPECT_EQ(false, FormTimerMgr::GetInstance().dynamicRefreshTasks_.empty()); + + GTEST_LOG_(INFO) << "FmsFormSetNextRefreshTest_SetNextRefreshTime_003 end"; +} + +/** + * @tc.number: FmsFormSetNextRefreshTest_SetNextRefreshTime_004 + * @tc.name: SetNextRefreshTime + * @tc.desc: Verify that the return value is true.(BundleName is not found in form record) + */ +HWTEST_F(FmsFormSetNextRefreshTest, FmsFormSetNextRefreshTest_SetNextRefreshTime_004, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormSetNextRefreshTest_SetNextRefreshTime_004 start"; + int64_t formId = 4; + int64_t nextTime = Constants::MIN_NEXT_TIME; + + // creat formRecords_ + FormItemInfo iteminfo; + iteminfo.formId_ = formId; + iteminfo.providerBundleName_ = "other_bundleName"; + iteminfo.abilityName_ = FORM_PROVIDER_ABILITY_NAME; + FormDataMgr::GetInstance().AllotFormRecord(iteminfo, 0); + + EXPECT_EQ(ERR_OPERATION_FORM_NOT_SELF, formSetNextRefresh_->SetNextRefreshTime(formId, nextTime)); + GTEST_LOG_(INFO) << "FmsFormSetNextRefreshTest_SetNextRefreshTime_004 end"; +} + +/** + * @tc.number: FmsFormSetNextRefreshTest_SetNextRefreshTime_005 + * @tc.name: SetNextRefreshTime + * @tc.desc: Verify that the return value is true.(have dynamicRefreshTask , have IntervalTimerTasks) + */ +HWTEST_F(FmsFormSetNextRefreshTest, FmsFormSetNextRefreshTest_SetNextRefreshTime_005, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormSetNextRefreshTest_SetNextRefreshTime_005 start"; + int64_t formId = 5; + int64_t nextTime = Constants::MIN_NEXT_TIME; + + // creat formRecords_ + FormItemInfo iteminfo; + iteminfo.formId_ = formId; + iteminfo.providerBundleName_ = FORM_HOST_BUNDLE_NAME; + iteminfo.abilityName_ = FORM_PROVIDER_ABILITY_NAME; + FormDataMgr::GetInstance().AllotFormRecord(iteminfo, 0); + + // Creat dynamicRefreshTasks_ + DynamicRefreshItem theItem; + theItem.formId = formId; + theItem.settedTime = 1; + FormTimerMgr::GetInstance().dynamicRefreshTasks_.clear(); + FormTimerMgr::GetInstance().dynamicRefreshTasks_.emplace_back(theItem); + // check dynamicRefreshTasks_ + EXPECT_EQ(1, FormTimerMgr::GetInstance().dynamicRefreshTasks_.at(0).settedTime); + + // Create IntervalTimerTasks_ + FormTimer task; + task.formId = formId; + task.isEnable = true; + FormTimerMgr::GetInstance().AddIntervalTimer(task); + + EXPECT_EQ(ERR_OK, formSetNextRefresh_->SetNextRefreshTime(formId, nextTime)); + // check dynamicRefreshTasks_ + EXPECT_EQ(true, FormTimerMgr::GetInstance().dynamicRefreshTasks_.at(0).settedTime != 1); + + GTEST_LOG_(INFO) << "FmsFormSetNextRefreshTest_SetNextRefreshTime_005 end"; +} + +/** + * @tc.number: FmsFormSetNextRefreshTest_SetNextRefreshTime_006 + * @tc.name: SetNextRefreshTime + * @tc.desc: Verify that the return value is true.(timerRefreshedCount >= 50) + */ +HWTEST_F(FmsFormSetNextRefreshTest, FmsFormSetNextRefreshTest_SetNextRefreshTime_006, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FmsFormSetNextRefreshTest_SetNextRefreshTime_006 start"; + + int64_t formId = 6; + int64_t nextTime = Constants::MIN_NEXT_TIME; + + // creat formRecords_ + FormItemInfo iteminfo; + iteminfo.formId_ = formId; + iteminfo.providerBundleName_ = FORM_HOST_BUNDLE_NAME; + iteminfo.abilityName_ = FORM_PROVIDER_ABILITY_NAME; + FormDataMgr::GetInstance().AllotFormRecord(iteminfo, 0); + + // set timerRefreshedCount + FormTimerMgr::GetInstance().refreshLimiter_.AddItem(formId); + auto iter = FormTimerMgr::GetInstance().refreshLimiter_.limiterMap_.find(formId); + if (iter == FormTimerMgr::GetInstance().refreshLimiter_.limiterMap_.end()) { + GTEST_LOG_(INFO) << "not found in limiterMap_!!!"; + } else { + iter->second.refreshCount = Constants::LIMIT_COUNT; + } + EXPECT_EQ(ERR_MAX_REFRESH, formSetNextRefresh_->SetNextRefreshTime(formId, nextTime)); + + GTEST_LOG_(INFO) << "FmsFormSetNextRefreshTest_SetNextRefreshTime_006 end"; +} +} diff --git a/services/formmgr/test/unittest/fms_form_sys_event_receiver_test/BUILD.gn b/services/formmgr/test/unittest/fms_form_sys_event_receiver_test/BUILD.gn new file mode 100644 index 0000000000..e2ef825955 --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_sys_event_receiver_test/BUILD.gn @@ -0,0 +1,88 @@ +# Copyright (c) 2021 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/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/formmgrservice" + +ohos_unittest("FmsFormSysEventReceiverTest") { + module_out_path = module_output_path + + sources = [ + "//foundation/appexecfwk/standard/interfaces/innerkits/fmskit/native/src/form_mgr.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_bundle_manager.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_form_host_client.cpp", + "//foundation/appexecfwk/standard/services/formmgr/test/mock/src/mock_form_provider_client.cpp", + ] + sources += [ "fms_form_sys_event_receiver_test.cpp" ] + + include_dirs = [ + "//third_party/zlib/contrib/minizip", + "//third_party/zlib", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/fmskit/native/include/", + "//foundation/appexecfwk/standard/common/log/include/", + "//foundation/appexecfwk/standard/services/formmgr/include", + "//foundation/appexecfwk/standard/services/bundlemgr/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base/include/", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/formmgr/", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include/", + "//foundation/distributedschedule/samgr/adapter/interfaces/innerkits/include/", + ] + + configs = [ + "${services_path}/formmgr/test:formmgr_test_config", + "//foundation/aafwk/standard/services/abilitymgr:abilityms_config", + + # "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:bundlemgr_sdk_config", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:formmgr_sdk_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/common:libappexecfwk_common", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${appexecfwk_path}/interfaces/innerkits/fmskit:fmskit_native", + "${libs_path}/libeventhandler:libeventhandler_target", + "${services_path}/formmgr:fms_target", + "//base/security/permission/interfaces/innerkits/permission_standard/permissionsdk:libpermissionsdk_standard", + "//base/startup/appspawn_standard:appspawn_socket_client", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + + #"${services_path}/bundlemgr:bms_target", + "//foundation/aafwk/standard/services/abilitymgr:abilityms_target", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/googletest:gmock_main", + "//utils/native/base:utils", + ] + + external_deps = [ + "ces_standard:cesfwk_core", + "ces_standard:cesfwk_innerkits", + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":FmsFormSysEventReceiverTest" ] +} diff --git a/services/formmgr/test/unittest/fms_form_sys_event_receiver_test/fms_form_sys_event_receiver_test.cpp b/services/formmgr/test/unittest/fms_form_sys_event_receiver_test/fms_form_sys_event_receiver_test.cpp new file mode 100644 index 0000000000..66aaa586a5 --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_sys_event_receiver_test/fms_form_sys_event_receiver_test.cpp @@ -0,0 +1,473 @@ +/* + * Copyright (c) 2021 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 "common_event_manager.h" +#include "common_event_data.h" +#include "common_event_support.h" +#include "form_ams_helper.h" +#include "form_constants.h" +#define private public +#include "form_data_mgr.h" +#include "form_db_cache.h" +#include "form_host_interface.h" +#include "form_mgr.h" +#undef private +#include "form_mgr_service.h" +#include "form_refresh_limiter.h" +#include "form_sys_event_receiver.h" +#include "if_system_ability_manager.h" +#include "inner_bundle_info.h" +#include "ipc_skeleton.h" +#include "form_bms_helper.h" +#include "iservice_registry.h" + +#include "mock_ability_manager.h" +#include "mock_bundle_manager.h" +#include "mock_form_host_client.h" +#include "permission/permission_kit.h" +#include "permission/permission.h" +#include "running_process_info.h" +#include "system_ability_definition.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; +using namespace OHOS::Security; + +namespace { +const std::string PERMISSION_NAME_REQUIRE_FORM = "ohos.permission.REQUIRE_FORM"; +const std::string PARAM_PROVIDER_PACKAGE_NAME = "com.form.provider.app.test.abiliy"; +const std::string FORM_PROVIDER_BUNDLE_NAME = "com.form.provider.service"; +const std::string PARAM_PROVIDER_MODULE_NAME = "com.form.provider.app.test.abiliy"; +const std::string FORM_PROVIDER_ABILITY_NAME = "com.form.provider.app.test.abiliy"; +const std::string PARAM_FORM_NAME = "com.form.name.test"; + +const std::string FORM_JS_COMPOMENT_NAME = "jsComponentName"; +const std::string FORM_PROVIDER_MODULE_SOURCE_DIR = ""; + +const std::string FORM_HOST_BUNDLE_NAME = "com.form.host.app"; + +const int32_t PARAM_FORM_DIMENSION_VALUE = 1; + +const std::string KEY_UID = "uid"; +const std::string KEY_BUNDLE_NAME = "bundleName"; +const std::string DEVICE_ID = "ohos-phone1"; +const std::string DEF_LABEL1 = "PermissionFormRequireGrant"; + +class FmsFormSysEventReceiverTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + void CreateEventData(std::string bundle, int64_t formId, int callingUid, std::string actionType, EventFwk::CommonEventData &eventData); + void CreateFormRecordAndFormInfo(std::string bundle, int64_t formId, int callingUid); + void ClearFormRecord(int64_t formId); + +protected: + sptr token_; + std::shared_ptr formyMgrServ_ = DelayedSingleton::GetInstance(); + + sptr mockBundleMgr_; + sptr mockAbilityMgrServ_; +}; + +void FmsFormSysEventReceiverTest::SetUpTestCase() +{} + +void FmsFormSysEventReceiverTest::TearDownTestCase() +{} + +void FmsFormSysEventReceiverTest::SetUp() +{ + // APP_LOGI("fms_form_mgr_client_test_001 setup"); + formyMgrServ_->OnStart(); + + mockBundleMgr_ = new (std::nothrow) BundleMgrService(); + EXPECT_TRUE(mockBundleMgr_ != nullptr); + FormBmsHelper::GetInstance().SetBundleManager(mockBundleMgr_); + + mockAbilityMgrServ_ = new (std::nothrow) MockAbilityMgrService(); + FormAmsHelper::GetInstance().SetAbilityManager(mockAbilityMgrServ_); + + // APP_LOGI("fms_form_mgr_client_test_001 FormMgrService started"); + token_ = new (std::nothrow) MockFormHostClient(); + + // Permission install + std::vector permList; + Permission::PermissionDef permDef; + permDef.permissionName = PERMISSION_NAME_REQUIRE_FORM; + permDef.bundleName = FORM_PROVIDER_BUNDLE_NAME; + permDef.grantMode = Permission::GrantMode::USER_GRANT; + permDef.availableScope = Permission::AvailableScope::AVAILABLE_SCOPE_ALL; + permDef.label = DEF_LABEL1; + permDef.labelId = 1; + permDef.description = DEF_LABEL1; + permDef.descriptionId = 1; + permList.emplace_back(permDef); + Permission::PermissionKit::AddDefPermissions(permList); + Permission::PermissionKit::AddUserGrantedReqPermissions(FORM_PROVIDER_BUNDLE_NAME, {PERMISSION_NAME_REQUIRE_FORM}, + 0); + Permission::PermissionKit::GrantUserGrantedPermission(FORM_PROVIDER_BUNDLE_NAME, PERMISSION_NAME_REQUIRE_FORM, 0); +} + +void FmsFormSysEventReceiverTest::TearDown() +{} + +void FmsFormSysEventReceiverTest::CreateEventData(std::string bundle, int64_t formId, int callingUid, std::string actionType, EventFwk::CommonEventData &eventData) +{ + Want want; + want.SetAction(actionType); + want.SetParam(KEY_BUNDLE_NAME, bundle); + want.SetParam(KEY_UID, callingUid); + eventData.SetWant(want); +} + +void FmsFormSysEventReceiverTest::CreateFormRecordAndFormInfo(std::string bundle, int64_t formId, int callingUid) +{ + FormItemInfo record; + record.SetFormId(formId); + record.SetProviderBundleName(bundle); + record.SetModuleName(PARAM_FORM_NAME); + record.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + record.SetFormName(PARAM_FORM_NAME); + record.SetSpecificationId(PARAM_FORM_DIMENSION_VALUE); + record.SetTemporaryFlag(true); + + FormDataMgr::GetInstance().AllotFormRecord(record, callingUid); + + FormRecord realFormRecord; + FormDataMgr::GetInstance().GetFormRecord(formId, realFormRecord); + + FormDBInfo formDBInfo(formId, realFormRecord); + FormDbCache::GetInstance().SaveFormInfo(formDBInfo); + + FormDataMgr::GetInstance().AllotFormHostRecord(record, token_, formId, callingUid); +} + +void FmsFormSysEventReceiverTest::ClearFormRecord(int64_t formId) +{ + FormDataMgr::GetInstance().DeleteFormRecord(formId); + FormDbCache::GetInstance().DeleteFormInfo(formId); + FormDataMgr::GetInstance().DeleteHostRecord(token_, formId); +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: OnReceiveEvent Functionss + * FunctionPoints: FormMgr OnReceiveEvent interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if HandleProviderRemoved works. + */ + +HWTEST_F(FmsFormSysEventReceiverTest, OnReceiveEvent_001, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_sys_event_receiver_test_001 start"; + std::string bundle = FORM_PROVIDER_BUNDLE_NAME; + int64_t formId = 0x0ffabcff00000000; + int callingUid {0}; + + FormItemInfo record; + record.SetFormId(formId); + record.SetProviderBundleName(bundle); + record.SetModuleName(PARAM_FORM_NAME); + record.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + record.SetFormName(PARAM_FORM_NAME); + record.SetSpecificationId(PARAM_FORM_DIMENSION_VALUE); + record.SetTemporaryFlag(false); + Want want; + want.SetAction(EventFwk::CommonEventSupport::COMMON_EVENT_ABILITY_REMOVED); + want.SetParam(KEY_BUNDLE_NAME, bundle); + FormRecord realFormRecord = FormDataMgr::GetInstance().AllotFormRecord(record, callingUid); + // Set database info + FormDBInfo formDBInfo(formId, realFormRecord); + std::vector allFormInfo; + FormDbCache::GetInstance().SaveFormInfo(formDBInfo); + // Set form host record + FormItemInfo info; + FormDataMgr::GetInstance().AllotFormHostRecord(info, token_, formId, callingUid); + EventFwk::CommonEventData eventData; + eventData.SetWant(want); + FormSysEventReceiver testCase; + testCase.OnReceiveEvent(eventData); + FormDbCache::GetInstance().GetAllFormInfo(allFormInfo); + EXPECT_EQ(ERR_APPEXECFWK_FORM_JSON_DELETE_FAIL, FormDbCache::GetInstance().DeleteFormInfo(formId)); + FormDataMgr::GetInstance().DeleteFormRecord(formId); + FormDbCache::GetInstance().DeleteFormInfo(formId); + FormDataMgr::GetInstance().DeleteHostRecord(token_, formId); + GTEST_LOG_(INFO) << "fms_form_sys_event_receiver_test_001 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: OnReceiveEvent Functionss + * FunctionPoints: FormMgr OnReceiveEvent interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if HandleBundleDataCleared works. + * [COMMON_EVENT_PACKAGE_DATA_CLEARED] want's uid is 0. formrecord's uid is 15. + */ + +HWTEST_F(FmsFormSysEventReceiverTest, OnReceiveEvent_002, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_sys_event_receiver_test_002 start"; + std::string bundle = FORM_PROVIDER_BUNDLE_NAME; + int64_t formId = 0x0ffabcff00000000; + int callingUid {15}; + std::string actionType = EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_DATA_CLEARED; + EventFwk::CommonEventData eventData; + int callingUidForWant = 0; + CreateEventData(bundle, formId, callingUidForWant, actionType, eventData); + CreateFormRecordAndFormInfo(bundle, formId, callingUid); + + FormSysEventReceiver testCase; + testCase.OnReceiveEvent(eventData); + + FormRecord tempFormRecord; + ASSERT_TRUE(FormDataMgr::GetInstance().GetFormRecord(formId, tempFormRecord)); + + ClearFormRecord(formId); + GTEST_LOG_(INFO) << "fms_form_sys_event_receiver_test_002 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: OnReceiveEvent Functionss + * FunctionPoints: FormMgr OnReceiveEvent interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if HandleBundleDataCleared works. + * [COMMON_EVENT_PACKAGE_DATA_CLEARED] want's uid and formrecord's and hostrecord's uid is 15. + */ + +HWTEST_F(FmsFormSysEventReceiverTest, OnReceiveEvent_003, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_sys_event_receiver_test_003 start"; + + std::string bundle = FORM_PROVIDER_BUNDLE_NAME; + int64_t formId = 0x0ffabcdf00000000; + int callingUid {15}; + std::string actionType = EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_DATA_CLEARED; + EventFwk::CommonEventData eventData; + CreateEventData(bundle, formId, callingUid, actionType, eventData); + CreateFormRecordAndFormInfo(bundle, formId, callingUid); + + FormRecord tempFormRecord; + ASSERT_TRUE(FormDataMgr::GetInstance().GetFormRecord(formId, tempFormRecord)); + + FormSysEventReceiver testCase; + testCase.OnReceiveEvent(eventData); + + ASSERT_FALSE(FormDataMgr::GetInstance().GetFormRecord(formId, tempFormRecord)); + + ClearFormRecord(formId); + + GTEST_LOG_(INFO) << "fms_form_sys_event_receiver_test_003 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: OnReceiveEvent Functionss + * FunctionPoints: FormMgr OnReceiveEvent interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if HandleBundleDataCleared works. + */ + +HWTEST_F(FmsFormSysEventReceiverTest, OnReceiveEvent_004, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_sys_event_receiver_test_004 start"; + EventFwk::CommonEventData eventData; + std::string bundle = FORM_PROVIDER_BUNDLE_NAME; + int callingUid {15}; + Want want; + FormRecord tempFormRecord; + eventData.SetWant(want); + want.SetParam(KEY_BUNDLE_NAME, bundle); + want.SetParam(KEY_UID, callingUid); + FormSysEventReceiver testCase; + testCase.OnReceiveEvent(eventData); + + GTEST_LOG_(INFO) << "fms_form_sys_event_receiver_test_004 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: OnReceiveEvent Functionss + * FunctionPoints: FormMgr OnReceiveEvent interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if HandleBundleDataCleared works. + * invalid action. + */ + +HWTEST_F(FmsFormSysEventReceiverTest, OnReceiveEvent_005, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_sys_event_receiver_test_005 start"; + + std::string bundle = FORM_PROVIDER_BUNDLE_NAME; + int64_t formId = 0x0ffabcdf00000000; + int callingUid {15}; + std::string actionType = EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_DATA_CLEARED + "ERROR"; + EventFwk::CommonEventData eventData; + CreateEventData(bundle, formId, callingUid, actionType, eventData); + + FormSysEventReceiver testCase; + testCase.OnReceiveEvent(eventData); + + GTEST_LOG_(INFO) << "fms_form_sys_event_receiver_test_005 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: OnReceiveEvent Functionss + * FunctionPoints: FormMgr OnReceiveEvent interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if HandleBundleDataCleared works. + * [COMMON_EVENT_PACKAGE_DATA_CLEARED] There is 2 callingUids. + */ +HWTEST_F(FmsFormSysEventReceiverTest, OnReceiveEvent_006, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_sys_event_receiver_test_006 start"; + + std::string bundle = FORM_PROVIDER_BUNDLE_NAME; + int64_t formId = 0x0ffabcdf00000000; + int callingUid {15}; + std::string actionType = EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_DATA_CLEARED; + EventFwk::CommonEventData eventData; + CreateEventData(bundle, formId, callingUid, actionType, eventData); + + //CreateFormRecordAndFormInfo + FormItemInfo record; + record.SetFormId(formId); + record.SetProviderBundleName(bundle); + record.SetModuleName(PARAM_FORM_NAME); + record.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); + record.SetFormName(PARAM_FORM_NAME); + record.SetSpecificationId(PARAM_FORM_DIMENSION_VALUE); + record.SetTemporaryFlag(true); + FormDataMgr::GetInstance().AllotFormRecord(record, callingUid); + ////AddFormUserUid + int new_callingUid = 150; + FormDataMgr::GetInstance().AddFormUserUid(formId, new_callingUid); + FormRecord realFormRecord; + FormDataMgr::GetInstance().GetFormRecord(formId, realFormRecord); + FormDBInfo formDBInfo(formId, realFormRecord); + FormDbCache::GetInstance().SaveFormInfo(formDBInfo); + FormDataMgr::GetInstance().AllotFormHostRecord(record, token_, formId, callingUid); + + FormRecord tempFormRecord; + ASSERT_TRUE(FormDataMgr::GetInstance().GetFormRecord(formId, tempFormRecord)); + + FormSysEventReceiver testCase; + testCase.OnReceiveEvent(eventData); + + ASSERT_TRUE(FormDataMgr::GetInstance().GetFormRecord(formId, tempFormRecord)); + + ClearFormRecord(formId); + + GTEST_LOG_(INFO) << "fms_form_sys_event_receiver_test_006 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: OnReceiveEvent Functionss + * FunctionPoints: FormMgr OnReceiveEvent interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if HandleProviderUpdated works. + * [COMMON_EVENT_ABILITY_UPDATED] ProviderFormUpdated return false. delete formrecord. + */ + +HWTEST_F(FmsFormSysEventReceiverTest, OnReceiveEvent_007, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_sys_event_receiver_test_007 start"; + + std::string bundle = FORM_PROVIDER_BUNDLE_NAME; + int64_t formId = 0x0ffabcdf00000000; + int callingUid {15}; + std::string actionType = EventFwk::CommonEventSupport::COMMON_EVENT_ABILITY_UPDATED; + EventFwk::CommonEventData eventData; + CreateEventData(bundle, formId, callingUid, actionType, eventData); + CreateFormRecordAndFormInfo(bundle, formId, callingUid); + + FormRecord tempFormRecord; + ASSERT_TRUE(FormDataMgr::GetInstance().GetFormRecord(formId, tempFormRecord)); + + FormSysEventReceiver testCase; + testCase.OnReceiveEvent(eventData); + + ASSERT_FALSE(FormDataMgr::GetInstance().GetFormRecord(formId, tempFormRecord)); + + ClearFormRecord(formId); + + GTEST_LOG_(INFO) << "fms_form_sys_event_receiver_test_007 end"; +} + +/* + * Feature: FormMgrService + * Function: FormMgr + * SubFunction: OnReceiveEvent Functionss + * FunctionPoints: FormMgr OnReceiveEvent interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if HandleProviderUpdated works. + * [COMMON_EVENT_ABILITY_UPDATED] ProviderFormUpdated return true. refresh form. + */ + +HWTEST_F(FmsFormSysEventReceiverTest, OnReceiveEvent_008, TestSize.Level0) +{ + GTEST_LOG_(INFO) << "fms_form_sys_event_receiver_test_008 start"; + + std::string bundle = FORM_PROVIDER_BUNDLE_NAME; + int64_t formId = 0x0ffabcdf00000000; + int callingUid {15}; + std::string actionType = EventFwk::CommonEventSupport::COMMON_EVENT_ABILITY_UPDATED; + EventFwk::CommonEventData eventData; + CreateEventData(bundle, formId, callingUid, actionType, eventData); + + //CreateFormRecordAndFormInfo + FormItemInfo record; + record.SetFormId(formId); + record.SetProviderBundleName(bundle); + record.SetModuleName(PARAM_PROVIDER_MODULE_NAME); // model name + record.SetAbilityName(FORM_PROVIDER_ABILITY_NAME); //ability name + record.SetFormName(PARAM_FORM_NAME); //form name + record.SetSpecificationId(PARAM_FORM_DIMENSION_VALUE); + record.SetTemporaryFlag(true); + + FormDataMgr::GetInstance().AllotFormRecord(record, callingUid); + FormRecord realFormRecord; + FormDataMgr::GetInstance().GetFormRecord(formId, realFormRecord); + FormDBInfo formDBInfo(formId, realFormRecord); + FormDbCache::GetInstance().SaveFormInfo(formDBInfo); + FormDataMgr::GetInstance().AllotFormHostRecord(record, token_, formId, callingUid); + + FormRecord tempFormRecord; + ASSERT_TRUE(FormDataMgr::GetInstance().GetFormRecord(formId, tempFormRecord)); + + FormSysEventReceiver testCase; + testCase.OnReceiveEvent(eventData); + + ASSERT_TRUE(FormDataMgr::GetInstance().GetFormRecord(formId, tempFormRecord)); + + ClearFormRecord(formId); + + GTEST_LOG_(INFO) << "fms_form_sys_event_receiver_test_008 end"; +} + +} \ No newline at end of file diff --git a/services/formmgr/test/unittest/fms_form_timer_mgr_test/BUILD.gn b/services/formmgr/test/unittest/fms_form_timer_mgr_test/BUILD.gn new file mode 100644 index 0000000000..6cf9c8dbff --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_timer_mgr_test/BUILD.gn @@ -0,0 +1,64 @@ +# Copyright (c) 2021 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/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/formmgrservice" + +ohos_unittest("FmsFormTimerMgrTest") { + module_out_path = module_output_path + + sources = [ "fms_form_timer_mgr_test.cpp" ] + + include_dirs = [ + "//foundation/appexecfwk/standard/common/log/include/", + "//foundation/appexecfwk/standard/services/formmgr/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base/include/", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/formmgr/", + ] + + configs = [ + "${services_path}/formmgr/test:formmgr_test_config", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:formmgr_sdk_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/common:libappexecfwk_common", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${services_path}/formmgr:fms_target", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler:libeventhandler", + "//third_party/googletest:gmock_main", + "//utils/native/base:utils", + ] + + external_deps = [ + "ces_standard:cesfwk_core", + "ces_standard:cesfwk_innerkits", + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":FmsFormTimerMgrTest" ] +} diff --git a/services/formmgr/test/unittest/fms_form_timer_mgr_test/fms_form_timer_mgr_test.cpp b/services/formmgr/test/unittest/fms_form_timer_mgr_test/fms_form_timer_mgr_test.cpp new file mode 100644 index 0000000000..efb9fe31a7 --- /dev/null +++ b/services/formmgr/test/unittest/fms_form_timer_mgr_test/fms_form_timer_mgr_test.cpp @@ -0,0 +1,600 @@ +/* + * Copyright (c) 2021 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 + +#include "common_event.h" +#include "common_event_manager.h" +#include "common_event_support.h" +#include "form_constants.h" +#include "form_refresh_limiter.h" +#include "form_timer_mgr.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; + +namespace { +const int64_t PARAM_FORM_ID_VALUE_1 = 20210712; +const int64_t PARAM_FORM_ID_VALUE_2 = 20210713; +const int64_t PARAM_FORM_ID_VALUE_3 = 20210714; +const int64_t PARAM_FORM_ID_VALUE_4 = 20210715; +const int64_t PARAM_FORM_ID_VALUE_5 = 20210716; +const int64_t PARAM_FORM_ID_VALUE_6 = 20210717; + +class FmsFormTimerMgrTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + +protected: +}; + +void FmsFormTimerMgrTest::SetUpTestCase() {} +void FmsFormTimerMgrTest::TearDownTestCase() {} +void FmsFormTimerMgrTest::SetUp() {} +void FmsFormTimerMgrTest::TearDown() {} + +/** + * @tc.number: Fms_FormTimerMgr_0001 + * @tc.name: AddFormTimer. + * @tc.desc: Add duration form timer. + */ +HWTEST_F(FmsFormTimerMgrTest, Fms_FormTimerMgr_0001, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0001 start"; + bool isOk = FormTimerMgr::GetInstance().AddFormTimer(PARAM_FORM_ID_VALUE_1, 1 * Constants::MIN_PERIOD); + EXPECT_EQ(isOk, true); + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0001 end"; +} + +/** + * @tc.number: Fms_FormTimerMgr_0002 + * @tc.name: AddFormTimer. + * @tc.desc: Add scheduled form timer. + */ +HWTEST_F(FmsFormTimerMgrTest, Fms_FormTimerMgr_0002, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0002 start"; + bool isOk = FormTimerMgr::GetInstance().AddFormTimer(PARAM_FORM_ID_VALUE_2, 2, 50); + EXPECT_EQ(isOk, true); + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0002 end"; +} + +/** + * @tc.number: Fms_FormTimerMgr_0003 + * @tc.name: RemoveFormTimer. + * @tc.desc: Delete form timer. + */ +HWTEST_F(FmsFormTimerMgrTest, Fms_FormTimerMgr_0003, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0003 start"; + bool isAddOk1 = FormTimerMgr::GetInstance().AddFormTimer(PARAM_FORM_ID_VALUE_3, 336 * Constants::MIN_PERIOD); + EXPECT_EQ(isAddOk1, true); + bool isAddOk2 = FormTimerMgr::GetInstance().AddFormTimer(PARAM_FORM_ID_VALUE_4, 3, 30); + EXPECT_EQ(isAddOk2, true); + bool isDelOk1 = FormTimerMgr::GetInstance().RemoveFormTimer(PARAM_FORM_ID_VALUE_3); + EXPECT_EQ(isDelOk1, true); + bool isDelOk2 = FormTimerMgr::GetInstance().RemoveFormTimer(PARAM_FORM_ID_VALUE_4); + EXPECT_EQ(isDelOk2, true); + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0003 end"; +} +/** + * @tc.number: Fms_FormTimerMgr_0004 + * @tc.name: UpdateFormTimer. + * @tc.desc: Update form timer(TYPE_INTERVAL_CHANGE). + */ +HWTEST_F(FmsFormTimerMgrTest, Fms_FormTimerMgr_0004, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0004 start"; + bool isAddOk1 = FormTimerMgr::GetInstance().AddFormTimer(PARAM_FORM_ID_VALUE_1, 3 * Constants::MIN_PERIOD); + EXPECT_EQ(isAddOk1, true); + + // TYPE_INTERVAL_CHANGE + FormTimerCfg timerCfg1; + timerCfg1.enableUpdate = true; + timerCfg1.updateDuration = 2 * Constants::MIN_PERIOD; + bool isUpdateOk1 = FormTimerMgr::GetInstance().UpdateFormTimer(PARAM_FORM_ID_VALUE_1, + UpdateType::TYPE_INTERVAL_CHANGE, timerCfg1); + EXPECT_EQ(isUpdateOk1, true); + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0004 end"; +} +/** + * @tc.number: Fms_FormTimerMgr_0005 + * @tc.name: UpdateFormTimer. + * @tc.desc: Update form timer(TYPE_ATTIME_CHANGE). + */ +HWTEST_F(FmsFormTimerMgrTest, Fms_FormTimerMgr_0005, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0005 start"; + bool isAddOk2 = FormTimerMgr::GetInstance().AddFormTimer(PARAM_FORM_ID_VALUE_2, 3, 30); + EXPECT_EQ(isAddOk2, true); + + // TYPE_ATTIME_CHANGE + FormTimerCfg timerCfg2; + timerCfg2.enableUpdate = true; + timerCfg2.updateAtHour = 6; + timerCfg2.updateAtMin = 55; + bool isUpdateOk2 = FormTimerMgr::GetInstance().UpdateFormTimer(PARAM_FORM_ID_VALUE_2, + UpdateType::TYPE_ATTIME_CHANGE, timerCfg2); + EXPECT_EQ(isUpdateOk2, true); + + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0005 end"; +} +/** + * @tc.number: Fms_FormTimerMgr_0006 + * @tc.name: UpdateFormTimer. + * @tc.desc: Update form timer(TYPE_INTERVAL_TO_ATTIME). + */ +HWTEST_F(FmsFormTimerMgrTest, Fms_FormTimerMgr_0006, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0006 start"; + bool isAddOk3 = FormTimerMgr::GetInstance().AddFormTimer(PARAM_FORM_ID_VALUE_3, 6 * Constants::MIN_PERIOD); + EXPECT_EQ(isAddOk3, true); + + // TYPE_INTERVAL_TO_ATTIME + FormTimerCfg timerCfg3; + timerCfg3.enableUpdate = true; + timerCfg3.updateAtHour = 8; + timerCfg3.updateAtMin = 25; + bool isUpdateOk3 = FormTimerMgr::GetInstance().UpdateFormTimer(PARAM_FORM_ID_VALUE_3, + UpdateType::TYPE_INTERVAL_TO_ATTIME, timerCfg3); + EXPECT_EQ(isUpdateOk3, true); + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0006 end"; +} +/** + * @tc.number: Fms_FormTimerMgr_0007 + * @tc.name: UpdateFormTimer. + * @tc.desc: Update form timer(TYPE_ATTIME_TO_INTERVAL). + */ +HWTEST_F(FmsFormTimerMgrTest, Fms_FormTimerMgr_0007, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0007 start"; + bool isAddOk4 = FormTimerMgr::GetInstance().AddFormTimer(PARAM_FORM_ID_VALUE_4, 10, 30); + EXPECT_EQ(isAddOk4, true); + + // TYPE_ATTIME_TO_INTERVAL + FormTimerCfg timerCfg4; + timerCfg4.enableUpdate = true; + timerCfg4.updateDuration = 5 * Constants::MIN_PERIOD; + bool isUpdateOk4 = FormTimerMgr::GetInstance().UpdateFormTimer(PARAM_FORM_ID_VALUE_4, + UpdateType::TYPE_ATTIME_TO_INTERVAL, timerCfg4); + EXPECT_EQ(isUpdateOk4, true); + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0007 end"; +} +/** + * @tc.number: Fms_FormTimerMgr_0008 + * @tc.name: TimerReceiver::OnReceiveEvent. + * @tc.desc: Receive common event(COMMON_EVENT_TIME_CHANGED). + */ +HWTEST_F(FmsFormTimerMgrTest, Fms_FormTimerMgr_0008, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0008 start"; + bool isAddOk5 = FormTimerMgr::GetInstance().AddFormTimer(PARAM_FORM_ID_VALUE_1, 11, 30); + EXPECT_EQ(isAddOk5, true); + + /* Publish */ + + // make a want + AAFwk::Want want; + want.SetAction(EventFwk::CommonEventSupport::COMMON_EVENT_TIME_CHANGED); + // make common event data + EventFwk::CommonEventData data; + data.SetWant(want); + // publish a common event + bool publishResult = EventFwk::CommonEventManager::PublishCommonEvent(data); + EXPECT_EQ(publishResult, true); + + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0008 end"; +} + +/** + * @tc.number: Fms_FormTimerMgr_0009 + * @tc.name: TimerReceiver::OnReceiveEvent. + * @tc.desc: Receive common event(COMMON_EVENT_TIMEZONE_CHANGED). + */ +HWTEST_F(FmsFormTimerMgrTest, Fms_FormTimerMgr_0009, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0009 start"; + bool isAddOk5 = FormTimerMgr::GetInstance().AddFormTimer(PARAM_FORM_ID_VALUE_2, 11, 30); + EXPECT_EQ(isAddOk5, true); + + /* Publish */ + + // make a want + AAFwk::Want want; + want.SetAction(EventFwk::CommonEventSupport::COMMON_EVENT_TIMEZONE_CHANGED); + // make common event data + EventFwk::CommonEventData data; + data.SetWant(want); + // publish a common event + bool publishResult = EventFwk::CommonEventManager::PublishCommonEvent(data); + EXPECT_EQ(publishResult, true); + + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0009 end"; +} +/** + * @tc.number: Fms_FormTimerMgr_0010 + * @tc.name: TimerReceiver::OnReceiveEvent. + * @tc.desc: Receive common event(ACTION_UPDATEATTIMER - TYPE_RESET_LIMIT). + */ +HWTEST_F(FmsFormTimerMgrTest, Fms_FormTimerMgr_0010, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0010 start"; + bool isAddOk5 = FormTimerMgr::GetInstance().AddFormTimer(PARAM_FORM_ID_VALUE_3, 11, 30); + EXPECT_EQ(isAddOk5, true); + + /* Publish */ + + // make a want + AAFwk::Want want; + want.SetAction(Constants::ACTION_UPDATEATTIMER); + want.SetParam(Constants::KEY_ACTION_TYPE, Constants::TYPE_RESET_LIMIT); + // make common event data + EventFwk::CommonEventData data; + data.SetWant(want); + // publish a common event + bool publishResult = EventFwk::CommonEventManager::PublishCommonEvent(data); + EXPECT_EQ(publishResult, true); + + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0010 end"; +} + +/** + * @tc.number: Fms_FormTimerMgr_0011 + * @tc.name: TimerReceiver::OnReceiveEvent. + * @tc.desc: Receive common event(ACTION_UPDATEATTIMER - TYPE_STATIC_UPDATE). + */ +HWTEST_F(FmsFormTimerMgrTest, Fms_FormTimerMgr_0011, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0011 start"; + bool isAddOk5 = FormTimerMgr::GetInstance().AddFormTimer(PARAM_FORM_ID_VALUE_4, 11, 30); + EXPECT_EQ(isAddOk5, true); + + /* Publish */ + + // make a want + AAFwk::Want want; + want.SetAction(Constants::ACTION_UPDATEATTIMER); + want.SetParam(Constants::KEY_ACTION_TYPE, Constants::TYPE_STATIC_UPDATE); + want.SetParam(Constants::KEY_WAKEUP_TIME, 90L); + // make common event data + EventFwk::CommonEventData data; + data.SetWant(want); + // publish a common event + bool publishResult = EventFwk::CommonEventManager::PublishCommonEvent(data); + EXPECT_EQ(publishResult, true); + + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0011 end"; +} +/** + * @tc.number: Fms_FormTimerMgr_0012 + * @tc.name: TimerReceiver::OnReceiveEvent. + * @tc.desc: Receive common event(ACTION_UPDATEATTIMER - TYPE_DYNAMIC_UPDATE). + */ +HWTEST_F(FmsFormTimerMgrTest, Fms_FormTimerMgr_0012, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0012 start"; + bool isAddOk5 = FormTimerMgr::GetInstance().AddFormTimer(PARAM_FORM_ID_VALUE_5, 11, 30); + EXPECT_EQ(isAddOk5, true); + + /* Publish */ + + // make a want + AAFwk::Want want; + want.SetAction(Constants::ACTION_UPDATEATTIMER); + want.SetParam(Constants::KEY_ACTION_TYPE, Constants::TYPE_DYNAMIC_UPDATE); + want.SetParam(Constants::KEY_WAKEUP_TIME, 90L); + // make common event data + EventFwk::CommonEventData data; + data.SetWant(want); + // publish a common event + bool publishResult = EventFwk::CommonEventManager::PublishCommonEvent(data); + EXPECT_EQ(publishResult, true); + + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0012 end"; +} + +/** + * @tc.number: Fms_FormTimerMgr_0013 + * @tc.name: AddFormTimer. + * @tc.desc: Add duration form timer. + */ +HWTEST_F(FmsFormTimerMgrTest, Fms_FormTimerMgr_0013, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0013 start"; + bool isOk = FormTimerMgr::GetInstance().AddFormTimer(PARAM_FORM_ID_VALUE_1, 0); + EXPECT_EQ(isOk, false); + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0013 end"; +} + +/** + * @tc.number: Fms_FormTimerMgr_0014 + * @tc.name: AddFormTimer. + * @tc.desc: Add scheduled form timer. + */ +HWTEST_F(FmsFormTimerMgrTest, Fms_FormTimerMgr_0014, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0014 start"; + bool isOk = FormTimerMgr::GetInstance().AddFormTimer(PARAM_FORM_ID_VALUE_2, 0, 60); + EXPECT_EQ(isOk, false); + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0014 end"; +} + +/** + * @tc.number: Fms_FormTimerMgr_0015 + * @tc.name: UpdateFormTimer. + * @tc.desc: Update form timer(TYPE_INTERVAL_CHANGE). + */ +HWTEST_F(FmsFormTimerMgrTest, Fms_FormTimerMgr_0015, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0015 start"; + bool isAddOk1 = FormTimerMgr::GetInstance().AddFormTimer(PARAM_FORM_ID_VALUE_1, 3 * Constants::MIN_PERIOD); + EXPECT_EQ(isAddOk1, true); + + // TYPE_INTERVAL_CHANGE + FormTimerCfg timerCfg1; + timerCfg1.enableUpdate = true; + timerCfg1.updateDuration = 0; + bool isUpdateOk1 = FormTimerMgr::GetInstance().UpdateFormTimer(PARAM_FORM_ID_VALUE_1, + UpdateType::TYPE_INTERVAL_CHANGE, timerCfg1); + EXPECT_EQ(isUpdateOk1, false); + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0015 end"; +} +/** + * @tc.number: Fms_FormTimerMgr_0016 + * @tc.name: UpdateFormTimer. + * @tc.desc: Update form timer(TYPE_ATTIME_CHANGE). + */ +HWTEST_F(FmsFormTimerMgrTest, Fms_FormTimerMgr_0016, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0016 start"; + bool isAddOk2 = FormTimerMgr::GetInstance().AddFormTimer(PARAM_FORM_ID_VALUE_2, 3, 30); + EXPECT_EQ(isAddOk2, true); + + // TYPE_ATTIME_CHANGE + FormTimerCfg timerCfg2; + timerCfg2.enableUpdate = true; + timerCfg2.updateAtHour = 0; + timerCfg2.updateAtMin = 60; + bool isUpdateOk2 = FormTimerMgr::GetInstance().UpdateFormTimer(PARAM_FORM_ID_VALUE_2, + UpdateType::TYPE_ATTIME_CHANGE, timerCfg2); + EXPECT_EQ(isUpdateOk2, false); + + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0016 end"; +} +/** + * @tc.number: Fms_FormTimerMgr_0017 + * @tc.name: UpdateFormTimer. + * @tc.desc: Update form timer(TYPE_INTERVAL_TO_ATTIME). + */ +HWTEST_F(FmsFormTimerMgrTest, Fms_FormTimerMgr_0017, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0017 start"; + bool isAddOk3 = FormTimerMgr::GetInstance().AddFormTimer(PARAM_FORM_ID_VALUE_3, 6 * Constants::MIN_PERIOD); + EXPECT_EQ(isAddOk3, true); + + // TYPE_INTERVAL_TO_ATTIME + FormTimerCfg timerCfg3; + timerCfg3.enableUpdate = true; + timerCfg3.updateAtHour = 0; + timerCfg3.updateAtMin = 60; + bool isUpdateOk3 = FormTimerMgr::GetInstance().UpdateFormTimer(PARAM_FORM_ID_VALUE_3, + UpdateType::TYPE_INTERVAL_TO_ATTIME, timerCfg3); + EXPECT_EQ(isUpdateOk3, false); + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0017 end"; +} +/** + * @tc.number: Fms_FormTimerMgr_0018 + * @tc.name: UpdateFormTimer. + * @tc.desc: Update form timer(TYPE_ATTIME_TO_INTERVAL). + */ +HWTEST_F(FmsFormTimerMgrTest, Fms_FormTimerMgr_0018, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0018 start"; + bool isAddOk4 = FormTimerMgr::GetInstance().AddFormTimer(PARAM_FORM_ID_VALUE_4, 10, 30); + EXPECT_EQ(isAddOk4, true); + + // TYPE_ATTIME_TO_INTERVAL + FormTimerCfg timerCfg4; + timerCfg4.enableUpdate = true; + timerCfg4.updateDuration = 0; + bool isUpdateOk4 = FormTimerMgr::GetInstance().UpdateFormTimer(PARAM_FORM_ID_VALUE_4, + UpdateType::TYPE_ATTIME_TO_INTERVAL, timerCfg4); + EXPECT_EQ(isUpdateOk4, false); + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0018 end"; +} + +/** + * @tc.number: Fms_FormTimerMgr_0019 + * @tc.name: FormRefreshLimiter::AddItem. + * @tc.desc: AddItem success. + */ +HWTEST_F(FmsFormTimerMgrTest, Fms_FormTimerMgr_0019, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0019 start"; + + FormRefreshLimiter refreshLimiter; + bool isAddOk = refreshLimiter.AddItem(PARAM_FORM_ID_VALUE_1); + EXPECT_EQ(isAddOk, true); + + EXPECT_EQ(refreshLimiter.GetItemCount(), 1); + + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0019 end"; +} + +/** + * @tc.number: Fms_FormTimerMgr_0020 + * @tc.name: FormRefreshLimiter::DeleteItem. + * @tc.desc: DeleteItem success. + */ +HWTEST_F(FmsFormTimerMgrTest, Fms_FormTimerMgr_0020, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0020 start"; + + FormRefreshLimiter refreshLimiter; + refreshLimiter.DeleteItem(PARAM_FORM_ID_VALUE_6); + EXPECT_EQ(refreshLimiter.GetItemCount(), 0); + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0020 end"; +} + +/** + * @tc.number: Fms_FormTimerMgr_0021 + * @tc.name: FormRefreshLimiter::IsEnableRefresh. + * @tc.desc: IsEnableRefresh. + */ +HWTEST_F(FmsFormTimerMgrTest, Fms_FormTimerMgr_0021, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0021 start"; + + FormRefreshLimiter refreshLimiter; + bool isAddOk = refreshLimiter.AddItem(PARAM_FORM_ID_VALUE_6); + EXPECT_EQ(isAddOk, true); + bool isEnableRefresh = refreshLimiter.IsEnableRefresh(PARAM_FORM_ID_VALUE_6); + EXPECT_EQ(isEnableRefresh, true); + + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0021 end"; +} + +/** + * @tc.number: Fms_FormTimerMgr_0022 + * @tc.name: FormRefreshLimiter::Increase. + * @tc.desc: Increase refreshCount. + */ +HWTEST_F(FmsFormTimerMgrTest, Fms_FormTimerMgr_0022, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0022 start"; + + FormRefreshLimiter refreshLimiter; + bool isAddOk = refreshLimiter.AddItem(PARAM_FORM_ID_VALUE_6); + EXPECT_EQ(isAddOk, true); + + refreshLimiter.Increase(PARAM_FORM_ID_VALUE_6); + + int count = refreshLimiter.GetRefreshCount(PARAM_FORM_ID_VALUE_6); + EXPECT_EQ(count, 1); + + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0022 end"; +} + +/** + * @tc.number: Fms_FormTimerMgr_0023 + * @tc.name: FormRefreshLimiter::ResetLimit. + * @tc.desc: ResetLimit. + */ +HWTEST_F(FmsFormTimerMgrTest, Fms_FormTimerMgr_0023, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0023 start"; + + FormRefreshLimiter refreshLimiter; + bool isAddOk = refreshLimiter.AddItem(PARAM_FORM_ID_VALUE_6); + EXPECT_EQ(isAddOk, true); + + refreshLimiter.Increase(PARAM_FORM_ID_VALUE_6); + + refreshLimiter.ResetLimit(); + + int count = refreshLimiter.GetRefreshCount(PARAM_FORM_ID_VALUE_6); + EXPECT_EQ(count, 0); + + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0023 end"; +} + +/** + * @tc.number: Fms_FormTimerMgr_0024 + * @tc.name: FormRefreshLimiter::Increase. + * @tc.desc: report refresh to 50 count. + */ +HWTEST_F(FmsFormTimerMgrTest, Fms_FormTimerMgr_0024, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0024 start"; + + FormRefreshLimiter refreshLimiter; + bool isAddOk = refreshLimiter.AddItem(PARAM_FORM_ID_VALUE_6); + EXPECT_EQ(isAddOk, true); + for(int iIndex = 0; iIndex < Constants::LIMIT_COUNT; iIndex++){ + refreshLimiter.Increase(PARAM_FORM_ID_VALUE_6); + } + + int count = refreshLimiter.GetRefreshCount(PARAM_FORM_ID_VALUE_6); + EXPECT_EQ(count, Constants::LIMIT_COUNT); + + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0024 end"; +} + +/** + * @tc.number: Fms_FormTimerMgr_0025 + * @tc.name: FormRefreshLimiter::IsEnableRefresh. + * @tc.desc: report refresh to 50 count. + */ +HWTEST_F(FmsFormTimerMgrTest, Fms_FormTimerMgr_0025, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0025 start"; + + FormRefreshLimiter refreshLimiter; + bool isAddOk = refreshLimiter.AddItem(PARAM_FORM_ID_VALUE_6); + EXPECT_EQ(isAddOk, true); + for(int iIndex = 0; iIndex < Constants::LIMIT_COUNT + 1; iIndex++) { + refreshLimiter.Increase(PARAM_FORM_ID_VALUE_6); + } + + bool isEnableRefresh = refreshLimiter.IsEnableRefresh(PARAM_FORM_ID_VALUE_6); + EXPECT_EQ(isEnableRefresh, false); + + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0025 end"; +} + +/** + * @tc.number: Fms_FormTimerMgr_0026 + * @tc.name: FormRefreshLimiter::MarkRemind. + * @tc.desc: Mark remind when refresh count >= 50. + */ +HWTEST_F(FmsFormTimerMgrTest, Fms_FormTimerMgr_0026, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0026 start"; + + FormRefreshLimiter refreshLimiter; + bool isAddOk = refreshLimiter.AddItem(PARAM_FORM_ID_VALUE_6); + EXPECT_EQ(isAddOk, true); + for(int iIndex = 0; iIndex < Constants::LIMIT_COUNT + 1; iIndex++) { + refreshLimiter.Increase(PARAM_FORM_ID_VALUE_6); + } + + refreshLimiter.MarkRemind(PARAM_FORM_ID_VALUE_6); + + std::vector vIdlist = refreshLimiter.GetRemindList(); + EXPECT_EQ(vIdlist.size() > 0, true); + + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0026 end"; +} + +/** + * @tc.number: Fms_FormTimerMgr_0027 + * @tc.name: OnIntervalTimeOut. + * @tc.desc: Interval timer timeout. + */ +HWTEST_F(FmsFormTimerMgrTest, Fms_FormTimerMgr_0027, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0027 start"; + bool isAddOk4 = FormTimerMgr::GetInstance().AddFormTimer(PARAM_FORM_ID_VALUE_6, 10, 30); + EXPECT_EQ(isAddOk4, true); + + std::this_thread::sleep_for(std::chrono::milliseconds(Constants::MIN_PERIOD)); + + GTEST_LOG_(INFO) << "Fms_FormTimerMgr_0027 end"; +} +} diff --git a/services/test/mock/include/mock_ability_mgr_host.h b/services/test/mock/include/mock_ability_mgr_host.h index 31d9f78693..1a0080a53e 100644 --- a/services/test/mock/include/mock_ability_mgr_host.h +++ b/services/test/mock/include/mock_ability_mgr_host.h @@ -184,6 +184,11 @@ public: return 0; } + int UpdateConfiguration(const DummyConfiguration &config) override + { + return 0; + } + virtual sptr GetWantSender( const WantSenderInfo &wantSenderInfo, const sptr &callerToken) override { @@ -235,6 +240,43 @@ public: { return 0; } + int MoveMissionToFloatingStack(const MissionOption &missionOption) override + { + return 0; + } + int MoveMissionToSplitScreenStack(const MissionOption &missionOption) override + { + return 0; + } + int MinimizeMultiWindow(int missionId) override + { + return 0; + } + int MaximizeMultiWindow(int missionId) override + { + return 0; + } + int GetFloatingMissions(std::vector &list) override + { + return 0; + } + int CloseMultiWindow(int missionId) override + { + return 0; + } + int SetMissionStackSetting(const StackSetting &stackSetting) override + { + return 0; + } + int StartAbility(const Want &want, const AbilityStartSetting &abilityStartSetting, + const sptr &callerToken, int requestCode) override + { + return 0; + } + int ChangeFocusAbility(const sptr &lostFocusToken, const sptr &getFocusToken) override + { + return 0; + } }; } // namespace AppExecFwk diff --git a/services/test/moduletest/common/ams/app_life_cycle_test/ams_app_life_cycle_module_test.cpp b/services/test/moduletest/common/ams/app_life_cycle_test/ams_app_life_cycle_module_test.cpp index 508b2f449e..20e10a2cb4 100755 --- a/services/test/moduletest/common/ams/app_life_cycle_test/ams_app_life_cycle_module_test.cpp +++ b/services/test/moduletest/common/ams/app_life_cycle_test/ams_app_life_cycle_module_test.cpp @@ -377,7 +377,7 @@ HWTEST_F(AmsAppLifeCycleModuleTest, StateChange_001, TestSize.Level2) auto abilityInfo = GetAbilityInfo("0", "MainAbility", "p1", "com.ohos.test.helloworld"); auto appInfo = GetApplicationInfo("com.ohos.test.helloworld"); sptr mockAppScheduler = new (std::nothrow) MockAppScheduler(); - ASSERT_TRUE(mockAppScheduler); + EXPECT_TRUE(mockAppScheduler); TestProcessInfo testProcessInfo; testProcessInfo.pid = pid; @@ -473,7 +473,7 @@ HWTEST_F(AmsAppLifeCycleModuleTest, StateChange_002, TestSize.Level3) HWTEST_F(AmsAppLifeCycleModuleTest, StateChange_003, TestSize.Level3) { pid_t pid = 1025; - ASSERT_TRUE(serviceInner_); + EXPECT_TRUE(serviceInner_); std::shared_ptr appRunningRecord = nullptr; std::vector> tokens; auto abilityInfo = std::make_shared(); @@ -643,7 +643,7 @@ HWTEST_F(AmsAppLifeCycleModuleTest, StateChange_006, TestSize.Level2) exit(0); } - ASSERT_TRUE(pid > 0); + EXPECT_TRUE(pid > 0); usleep(50000); sptr token = GetAbilityToken(); @@ -868,10 +868,10 @@ HWTEST_F(AmsAppLifeCycleModuleTest, StateChange_010, TestSize.Level3) char index[32]; int ref = snprintf_s(index, sizeof(index), sizeof(index) - 1, "%d", i); - ASSERT_TRUE(ref > 0); + EXPECT_TRUE(ref > 0); char name[128]; ref = snprintf_s(name, sizeof(name), sizeof(name) - 1, "com.ohos.test.helloworld%d", i); - ASSERT_TRUE(ref > 0); + EXPECT_TRUE(ref > 0); auto abilityInfo = GetAbilityInfo(index, "MainAbility", index, name); auto appInfo = GetApplicationInfo(name); auto token = new (std::nothrow) MockAbilityToken(); @@ -882,7 +882,7 @@ HWTEST_F(AmsAppLifeCycleModuleTest, StateChange_010, TestSize.Level3) appRunningRecord = StartProcessAndLoadAbility(mockAppScheduler[i], token, abilityInfo, appInfo, testProcessInfo); - ASSERT_TRUE(appRunningRecord); + EXPECT_TRUE(appRunningRecord); ChangeAbilityStateAfterAppStart(mockAppScheduler[i], testProcessInfo.pid); @@ -966,12 +966,12 @@ HWTEST_F(AmsAppLifeCycleModuleTest, StateChange_012, TestSize.Level0) */ HWTEST_F(AmsAppLifeCycleModuleTest, StateChange_013, TestSize.Level3) { - ASSERT_TRUE(serviceInner_); - ASSERT_TRUE(serviceInner_->remoteClientManager_); - ASSERT_TRUE(serviceInner_->remoteClientManager_->GetSpawnClient()); + EXPECT_TRUE(serviceInner_); + EXPECT_TRUE(serviceInner_->remoteClientManager_); + EXPECT_TRUE(serviceInner_->remoteClientManager_->GetSpawnClient()); auto mockAppSpawnSocket = std::make_shared(); - ASSERT_TRUE(mockAppSpawnSocket); + EXPECT_TRUE(mockAppSpawnSocket); serviceInner_->remoteClientManager_->GetSpawnClient()->SetSocket(mockAppSpawnSocket); EXPECT_EQ(serviceInner_->QueryAppSpawnConnectionState(), SpawnConnectionState::STATE_NOT_CONNECT); diff --git a/services/test/moduletest/common/ams/app_mgr_service_test/ams_app_mgr_service_module_test.cpp b/services/test/moduletest/common/ams/app_mgr_service_test/ams_app_mgr_service_module_test.cpp index 63cf32cbfc..12eadc519b 100644 --- a/services/test/moduletest/common/ams/app_mgr_service_test/ams_app_mgr_service_module_test.cpp +++ b/services/test/moduletest/common/ams/app_mgr_service_test/ams_app_mgr_service_module_test.cpp @@ -139,9 +139,9 @@ void AppMgrServiceModuleTest::TearDown() */ HWTEST_F(AppMgrServiceModuleTest, AttachApplication_001, TestSize.Level1) { - ASSERT_TRUE(appMgrService_); - ASSERT_TRUE(mockAppMgrServiceInner_); - ASSERT_TRUE(testRemoteObject_); + EXPECT_TRUE(appMgrService_); + EXPECT_TRUE(mockAppMgrServiceInner_); + EXPECT_TRUE(testRemoteObject_); for (int i = 0; i < COUNT; ++i) { EXPECT_CALL(*mockAppMgrServiceInner_, AddAppDeathRecipient(_, _)) @@ -164,8 +164,8 @@ HWTEST_F(AppMgrServiceModuleTest, AttachApplication_001, TestSize.Level1) */ HWTEST_F(AppMgrServiceModuleTest, ApplicationForegrounded_001, TestSize.Level1) { - ASSERT_TRUE(appMgrService_); - ASSERT_TRUE(mockAppMgrServiceInner_); + EXPECT_TRUE(appMgrService_); + EXPECT_TRUE(mockAppMgrServiceInner_); int32_t testRecordId = 123; bool testResult = false; @@ -198,8 +198,8 @@ HWTEST_F(AppMgrServiceModuleTest, ApplicationForegrounded_001, TestSize.Level1) */ HWTEST_F(AppMgrServiceModuleTest, ApplicationBackgrounded_001, TestSize.Level1) { - ASSERT_TRUE(appMgrService_); - ASSERT_TRUE(mockAppMgrServiceInner_); + EXPECT_TRUE(appMgrService_); + EXPECT_TRUE(mockAppMgrServiceInner_); int32_t testRecordId = 123; bool testResult = false; @@ -232,8 +232,8 @@ HWTEST_F(AppMgrServiceModuleTest, ApplicationBackgrounded_001, TestSize.Level1) */ HWTEST_F(AppMgrServiceModuleTest, ApplicationTerminated_001, TestSize.Level1) { - ASSERT_TRUE(appMgrService_); - ASSERT_TRUE(mockAppMgrServiceInner_); + EXPECT_TRUE(appMgrService_); + EXPECT_TRUE(mockAppMgrServiceInner_); int32_t testRecordId = 123; bool testResult = false; @@ -266,9 +266,9 @@ HWTEST_F(AppMgrServiceModuleTest, ApplicationTerminated_001, TestSize.Level1) */ HWTEST_F(AppMgrServiceModuleTest, AbilityCleaned_001, TestSize.Level1) { - ASSERT_TRUE(appMgrService_); - ASSERT_TRUE(mockAppMgrServiceInner_); - ASSERT_TRUE(testRemoteObject_); + EXPECT_TRUE(appMgrService_); + EXPECT_TRUE(mockAppMgrServiceInner_); + EXPECT_TRUE(testRemoteObject_); bool testResult = false; Semaphore sem(0); @@ -300,8 +300,8 @@ HWTEST_F(AppMgrServiceModuleTest, AbilityCleaned_001, TestSize.Level1) */ HWTEST_F(AppMgrServiceModuleTest, ClearUpApplicationData_001, TestSize.Level1) { - ASSERT_TRUE(appMgrService_); - ASSERT_TRUE(mockAppMgrServiceInner_); + EXPECT_TRUE(appMgrService_); + EXPECT_TRUE(mockAppMgrServiceInner_); std::string testAppName("testApp"); bool testResult = false; @@ -334,8 +334,8 @@ HWTEST_F(AppMgrServiceModuleTest, ClearUpApplicationData_001, TestSize.Level1) */ HWTEST_F(AppMgrServiceModuleTest, IsBackgroundRunningRestricted_001, TestSize.Level1) { - ASSERT_TRUE(appMgrService_); - ASSERT_TRUE(mockAppMgrServiceInner_); + EXPECT_TRUE(appMgrService_); + EXPECT_TRUE(mockAppMgrServiceInner_); std::string testAppName("testApp"); bool testResult = false; @@ -370,8 +370,8 @@ HWTEST_F(AppMgrServiceModuleTest, IsBackgroundRunningRestricted_001, TestSize.Le */ HWTEST_F(AppMgrServiceModuleTest, GetAllRunningProcesses_001, TestSize.Level1) { - ASSERT_TRUE(appMgrService_); - ASSERT_TRUE(mockAppMgrServiceInner_); + EXPECT_TRUE(appMgrService_); + EXPECT_TRUE(mockAppMgrServiceInner_); std::vector testRunningProcessInfo; @@ -410,8 +410,8 @@ HWTEST_F(AppMgrServiceModuleTest, GetAllRunningProcesses_001, TestSize.Level1) */ HWTEST_F(AppMgrServiceModuleTest, KillApplication_001, TestSize.Level1) { - ASSERT_TRUE(appMgrService_); - ASSERT_TRUE(mockAppMgrServiceInner_); + EXPECT_TRUE(appMgrService_); + EXPECT_TRUE(mockAppMgrServiceInner_); std::string testBundleName("testApp"); bool testResult = false; @@ -446,8 +446,8 @@ HWTEST_F(AppMgrServiceModuleTest, KillApplication_001, TestSize.Level1) */ HWTEST_F(AppMgrServiceModuleTest, QueryServiceState_001, TestSize.Level1) { - ASSERT_TRUE(appMgrService_); - ASSERT_TRUE(mockAppMgrServiceInner_); + EXPECT_TRUE(appMgrService_); + EXPECT_TRUE(mockAppMgrServiceInner_); SpawnConnectionState testSpawnConnectionState = SpawnConnectionState::STATE_CONNECTED; Semaphore sem(0); @@ -477,7 +477,7 @@ HWTEST_F(AppMgrServiceModuleTest, QueryServiceState_001, TestSize.Level1) */ HWTEST_F(AppMgrServiceModuleTest, GetAmsMgr_001, TestSize.Level1) { - ASSERT_TRUE(appMgrService_); + EXPECT_TRUE(appMgrService_); auto amsMgr = appMgrService_->GetAmsMgr(); diff --git a/services/test/moduletest/common/ams/app_running_record_test/ams_app_running_record_module_test.cpp b/services/test/moduletest/common/ams/app_running_record_test/ams_app_running_record_module_test.cpp index 163a900110..f565d0ef49 100644 --- a/services/test/moduletest/common/ams/app_running_record_test/ams_app_running_record_module_test.cpp +++ b/services/test/moduletest/common/ams/app_running_record_test/ams_app_running_record_module_test.cpp @@ -63,7 +63,7 @@ protected: void CheckLaunchApplication(const sptr &mockApplication, const unsigned long index, std::shared_ptr record, const std::string &testPoint) const { - ASSERT_TRUE(record != nullptr) << "record is nullptr!"; + EXPECT_TRUE(record != nullptr) << "record is nullptr!"; sptr client = iface_cast(mockApplication); record->SetApplicationClient(client); @@ -92,10 +92,10 @@ protected: const std::shared_ptr abilityInfo, const std::shared_ptr record, const int index, RecordQueryResult &result) const { - ASSERT_TRUE(service_ != nullptr) << "init service fail!"; - ASSERT_TRUE(appInfo != nullptr) << "appInfo is nullptr!"; - ASSERT_TRUE(abilityInfo != nullptr) << "abilityInfo is nullptr!"; - ASSERT_TRUE(record != nullptr) << "record is nullptr!"; + EXPECT_TRUE(service_ != nullptr) << "init service fail!"; + EXPECT_TRUE(appInfo != nullptr) << "appInfo is nullptr!"; + EXPECT_TRUE(abilityInfo != nullptr) << "abilityInfo is nullptr!"; + EXPECT_TRUE(record != nullptr) << "record is nullptr!"; auto abilityRecord = record->GetAbilityRunningRecord(GetTestAbilityName(index)); int32_t id = record->GetRecordId(); auto name = record->GetName(); @@ -111,7 +111,7 @@ protected: sptr tokenFromServ = abilityRecordFromServ->GetToken(); auto nameFromServ = appRecordFromServ->GetName(); auto abilityNameFromServ = abilityRecordFromServ->GetName(); - ASSERT_TRUE(result.appExists) << "result is wrong!"; + EXPECT_TRUE(result.appExists) << "result is wrong!"; EXPECT_TRUE(id == idFromServ) << "fail, RecordId is not equal!"; EXPECT_TRUE(tokenFromServ.GetRefPtr() == token.GetRefPtr()) << "fail, token is not equal!"; EXPECT_EQ(name, nameFromServ) << "fail, app record name is not equal!"; @@ -170,7 +170,7 @@ HWTEST_F(AmsAppRunningRecordModuleTest, ApplicationStart_001, TestSize.Level0) std::string processName = GetTestAppName(index); RecordQueryResult result; auto record = service_->GetOrCreateAppRunningRecord(GetMockToken(), appInfo, abilityInfo, processName, 0, result); - ASSERT_TRUE(record != nullptr) << ",create apprunningrecord fail!"; + EXPECT_TRUE(record != nullptr) << ",create apprunningrecord fail!"; ASSERT_FALSE(result.appExists) << ",result is wrong!"; // check apprunningrecord @@ -196,7 +196,7 @@ HWTEST_F(AmsAppRunningRecordModuleTest, ApplicationStart_001, TestSize.Level0) service_->GetOrCreateAppRunningRecord(GetMockToken(), appInfo, abilityInfo, processName, 0, newResult); EXPECT_TRUE(newRecord); auto stateFromRec = newRecord->GetState(); - ASSERT_TRUE(newResult.appExists) << "fail, app is not exist!"; + EXPECT_TRUE(newResult.appExists) << "fail, app is not exist!"; EXPECT_EQ(stateFromRec, ApplicationState::APP_STATE_FOREGROUND); // clear apprunningrecord @@ -230,7 +230,7 @@ HWTEST_F(AmsAppRunningRecordModuleTest, MultiApplicationStart_002, TestSize.Leve RecordQueryResult result; auto record = service_->GetOrCreateAppRunningRecord(GetMockToken(), appInfo, abilityInfo, processName, 0, result); - ASSERT_TRUE(record != nullptr) << "create apprunningrecord fail!"; + EXPECT_TRUE(record != nullptr) << "create apprunningrecord fail!"; ASSERT_FALSE(result.appExists) << "result is wrong!"; // check abilityrunningrecord & apprunningrecord @@ -262,7 +262,7 @@ HWTEST_F(AmsAppRunningRecordModuleTest, MultiApplicationStart_002, TestSize.Leve */ HWTEST_F(AmsAppRunningRecordModuleTest, ScheduleTrimMemory_003, TestSize.Level1) { - ASSERT_TRUE(service_ != nullptr) << "init service fail!"; + EXPECT_TRUE(service_ != nullptr) << "init service fail!"; // init AppRunningRecord unsigned long index = 0; @@ -273,7 +273,7 @@ HWTEST_F(AmsAppRunningRecordModuleTest, ScheduleTrimMemory_003, TestSize.Level1) appInfo->name = GetTestAppName(index); RecordQueryResult result; auto record = service_->GetOrCreateAppRunningRecord(GetMockToken(), appInfo, abilityInfo, processName, 0, result); - ASSERT_TRUE(record != nullptr) << "create apprunningrecord fail!"; + EXPECT_TRUE(record != nullptr) << "create apprunningrecord fail!"; ASSERT_FALSE(result.appExists) << "result is wrong!"; // LaunchApplication @@ -310,7 +310,7 @@ HWTEST_F(AmsAppRunningRecordModuleTest, ScheduleTrimMemory_003, TestSize.Level1) */ HWTEST_F(AmsAppRunningRecordModuleTest, LowMemoryWarning_004, TestSize.Level1) { - ASSERT_TRUE(service_ != nullptr) << "init service fail!"; + EXPECT_TRUE(service_ != nullptr) << "init service fail!"; // init AppRunningRecord unsigned long index = 0; @@ -321,7 +321,7 @@ HWTEST_F(AmsAppRunningRecordModuleTest, LowMemoryWarning_004, TestSize.Level1) appInfo->name = GetTestAppName(index); RecordQueryResult result; auto record = service_->GetOrCreateAppRunningRecord(GetMockToken(), appInfo, abilityInfo, processName, 0, result); - ASSERT_TRUE(record != nullptr) << "create apprunningrecord fail!"; + EXPECT_TRUE(record != nullptr) << "create apprunningrecord fail!"; ASSERT_FALSE(result.appExists) << "result is wrong!"; // LaunchApplication @@ -358,7 +358,7 @@ HWTEST_F(AmsAppRunningRecordModuleTest, LowMemoryWarning_004, TestSize.Level1) */ HWTEST_F(AmsAppRunningRecordModuleTest, ApplicationStartAndQuit_005, TestSize.Level2) { - ASSERT_TRUE(service_ != nullptr) << "init service fail!"; + EXPECT_TRUE(service_ != nullptr) << "init service fail!"; unsigned long index = 0; int startCount = 10000; @@ -372,7 +372,7 @@ HWTEST_F(AmsAppRunningRecordModuleTest, ApplicationStartAndQuit_005, TestSize.Le RecordQueryResult result; auto record = service_->GetOrCreateAppRunningRecord(GetMockToken(), appInfo, abilityInfo, processName, 0, result); - ASSERT_TRUE(record != nullptr) << "create apprunningrecord fail!"; + EXPECT_TRUE(record != nullptr) << "create apprunningrecord fail!"; // LaunchApplication sptr mockApplication(new MockApplication()); @@ -428,7 +428,7 @@ HWTEST_F(AmsAppRunningRecordModuleTest, ApplicationStartAndQuit_005, TestSize.Le */ HWTEST_F(AmsAppRunningRecordModuleTest, ApplicationStatusChange_006, TestSize.Level2) { - ASSERT_TRUE(service_ != nullptr) << "init service fail!"; + EXPECT_TRUE(service_ != nullptr) << "init service fail!"; // init AppRunningRecord unsigned long index = 0; @@ -439,7 +439,7 @@ HWTEST_F(AmsAppRunningRecordModuleTest, ApplicationStatusChange_006, TestSize.Le appInfo->name = GetTestAppName(index); RecordQueryResult result; auto record = service_->GetOrCreateAppRunningRecord(GetMockToken(), appInfo, abilityInfo, processName, 0, result); - ASSERT_TRUE(record != nullptr) << "create apprunningrecord fail!"; + EXPECT_TRUE(record != nullptr) << "create apprunningrecord fail!"; // LaunchApplication sptr mockApplication(new MockApplication()); diff --git a/services/test/moduletest/common/ams/service_start_process_test/ams_service_start_process_module_test.cpp b/services/test/moduletest/common/ams/service_start_process_test/ams_service_start_process_module_test.cpp index eee1fba582..27ebd33e6f 100644 --- a/services/test/moduletest/common/ams/service_start_process_test/ams_service_start_process_module_test.cpp +++ b/services/test/moduletest/common/ams/service_start_process_test/ams_service_start_process_module_test.cpp @@ -71,7 +71,7 @@ HWTEST_F(AmsServiceStartModuleTest, AmsStartupMoretimes_001, TestSize.Level1) { APP_LOGI("AmsStartupMoretimes_001 start"); std::shared_ptr appMgrService = std::make_shared(); - ASSERT_TRUE(appMgrService.get() != nullptr); + EXPECT_TRUE(appMgrService.get() != nullptr); std::shared_ptr innerService = std::make_shared(); appMgrService->SetInnerService(innerService); EXPECT_EQ(ServiceRunningState::STATE_NOT_START, appMgrService->QueryServiceState().serviceRunningState); @@ -98,7 +98,7 @@ HWTEST_F(AmsServiceStartModuleTest, AmsStartupMoretimes_002, TestSize.Level1) { APP_LOGI("AmsStartupMoretimes_002 start"); std::shared_ptr appMgrService = std::make_shared(); - ASSERT_TRUE(appMgrService.get() != nullptr); + EXPECT_TRUE(appMgrService.get() != nullptr); std::shared_ptr innerService = std::make_shared(); appMgrService->SetInnerService(innerService); EXPECT_EQ(ServiceRunningState::STATE_NOT_START, appMgrService->QueryServiceState().serviceRunningState); diff --git a/services/test/moduletest/common/bms/bundle_installer_test/BUILD.gn b/services/test/moduletest/common/bms/bundle_installer_test/BUILD.gn index 1dc596fe57..e73c540971 100755 --- a/services/test/moduletest/common/bms/bundle_installer_test/BUILD.gn +++ b/services/test/moduletest/common/bms/bundle_installer_test/BUILD.gn @@ -32,6 +32,7 @@ ohos_moduletest("BmsBundleInstallerModuleTest") { "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core/include/bundlemgr", "//foundation/aafwk/standard/interfaces/innerkits/want/include", "//third_party/json/include", + "//third_party/jsoncpp/include", "${services_path}/test/mock/include", ] @@ -46,6 +47,9 @@ ohos_moduletest("BmsBundleInstallerModuleTest") { "${services_path}/bundlemgr/src/installd/installd_host_impl.cpp", "${services_path}/bundlemgr/src/installd/installd_operator.cpp", "${services_path}/bundlemgr/src/installd/installd_service.cpp", + "${services_path}/bundlemgr/src/kvstore_death_recipient_callback.cpp", + "${services_path}/bundlemgr/src/module_usage_data_storage.cpp", + "${services_path}/bundlemgr/src/permission_changed_death_recipient.cpp", ] sources += bundle_install_sources @@ -73,6 +77,7 @@ ohos_moduletest("BmsBundleInstallerModuleTest") { "//foundation/distributeddatamgr/distributeddatamgr/interfaces/innerkits/distributeddata:distributeddata_inner", "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", "//utils/native/base:utils", ] diff --git a/services/test/moduletest/common/bms/bundle_installer_test/bms_bundle_installer_module_test.cpp b/services/test/moduletest/common/bms/bundle_installer_test/bms_bundle_installer_module_test.cpp index e2b949af39..db27d0673b 100644 --- a/services/test/moduletest/common/bms/bundle_installer_test/bms_bundle_installer_module_test.cpp +++ b/services/test/moduletest/common/bms/bundle_installer_test/bms_bundle_installer_module_test.cpp @@ -154,7 +154,10 @@ protected: "defaultHeight": 100, "minWidth": 0, "defaultWidth": 200 - } + }, + "labelId": 1, + "descriptionId": 1, + "iconId": 1 }, "com.ohos.launchercom.ohos.launchercom.ohos.launcher.MainAbility": { "applicationName": "com.ohos.launcher", @@ -517,7 +520,7 @@ void BmsBundleInstallerModuleTest::SaveBundleDataToStorage(std::unique_ptrPut(key, value); if (status != Status::SUCCESS) { std::cout << static_cast(status) << std::endl; - ASSERT_TRUE(false) << "save fail"; + EXPECT_TRUE(false) << "save fail"; } } @@ -530,7 +533,7 @@ void BmsBundleInstallerModuleTest::DeleteBundleDataToStorage( Key key(keyString); status = kvStorePtr->Delete(key); if (status != Status::SUCCESS) { - ASSERT_TRUE(false) << "delete fail"; + EXPECT_TRUE(false) << "delete fail"; } } @@ -626,13 +629,13 @@ void BmsBundleInstallerModuleTest::SetUpTestCase() { if (access(ROOT_DIR.c_str(), F_OK) != 0) { bool result = OHOS::ForceCreateDirectory(ROOT_DIR); - ASSERT_TRUE(result); + EXPECT_TRUE(result); } if (chown(ROOT_DIR.c_str(), ROOT_UID, ROOT_UID) != 0) { - ASSERT_TRUE(false); + EXPECT_TRUE(false); } if (chmod(ROOT_DIR.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) { - ASSERT_TRUE(false); + EXPECT_TRUE(false); } } @@ -665,7 +668,7 @@ HWTEST_F(BmsBundleInstallerModuleTest, SystemAppInstall_0100, Function | MediumT { std::string bundleName = SYSTEM_BUNDLE_NAME + "s1"; std::shared_ptr dataMgr = GetBundleDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); BundleInfo bundleInfo; bool ret = false; int checkCount = 0; @@ -689,7 +692,7 @@ HWTEST_F(BmsBundleInstallerModuleTest, SystemAppInstall_0200, Function | MediumT { int bundleNum = 2; std::shared_ptr dataMgr = GetBundleDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); BundleInfo bundleInfo; for (int i = 1; i <= bundleNum; i++) { @@ -718,7 +721,7 @@ HWTEST_F(BmsBundleInstallerModuleTest, SystemAppInstall_0300, Function | MediumT { std::string norBundleName = SYSTEM_BUNDLE_NAME + "s2"; std::shared_ptr dataMgr = GetBundleDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); BundleInfo bundleInfo; bool ret = false; int checkCount = 0; @@ -752,7 +755,7 @@ HWTEST_F(BmsBundleInstallerModuleTest, SystemAppInstall_0400, Function | MediumT std::string bundleName = SYSTEM_BUNDLE_NAME + "s3"; CheckFileNonExist(bundleName); std::shared_ptr dataMgr = GetBundleDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); BundleInfo bundleInfo; bool ret = false; int checkCount = 0; @@ -776,7 +779,7 @@ HWTEST_F(BmsBundleInstallerModuleTest, SystemAppInstall_0500, Function | MediumT std::string bundleName = SYSTEM_BUNDLE_NAME + "s4"; CheckFileNonExist(bundleName); std::shared_ptr dataMgr = GetBundleDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); BundleInfo bundleInfo; bool ret = false; int checkCount = 0; @@ -798,19 +801,19 @@ HWTEST_F(BmsBundleInstallerModuleTest, SystemAppInstall_0500, Function | MediumT HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0100, Function | MediumTest | Level1) { auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); - ASSERT_NE(installer, nullptr); + EXPECT_NE(installer, nullptr); OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver, nullptr); + EXPECT_NE(receiver, nullptr); InstallParam installParam; installParam.installFlag = InstallFlag::NORMAL; std::string bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle1" + Constants::INSTALL_FILE_SUFFIX; installer->Install(bundleFilePath, installParam, receiver); - ASSERT_EQ(receiver->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; + EXPECT_EQ(receiver->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; std::string bundleName = THIRD_BUNDLE_NAME + "1"; CheckFileExist(bundleName); OHOS::sptr recUninstall = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(recUninstall, nullptr); + EXPECT_NE(recUninstall, nullptr); installParam.userId = Constants::DEFAULT_USERID; installer->Uninstall(bundleName, installParam, recUninstall); EXPECT_EQ(recUninstall->GetResultCode(), ERR_OK) << "uninstall fail!" << bundleName; @@ -826,14 +829,14 @@ HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0100, Function | MediumTe HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0200, Function | MediumTest | Level1) { auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); - ASSERT_NE(installer, nullptr); + EXPECT_NE(installer, nullptr); OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver, nullptr); + EXPECT_NE(receiver, nullptr); InstallParam installParam; installParam.installFlag = InstallFlag::NORMAL; std::string bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle1" + Constants::INSTALL_FILE_SUFFIX; installer->Install(bundleFilePath, installParam, receiver); - ASSERT_EQ(receiver->GetResultCode(), ERR_OK); + EXPECT_EQ(receiver->GetResultCode(), ERR_OK); std::string bundleName = THIRD_BUNDLE_NAME + "1"; CheckFileExist(bundleName); @@ -841,7 +844,7 @@ HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0200, Function | MediumTe StartBundleMgrService(); CheckFileExist(bundleName); std::shared_ptr dataMgr = GetBundleDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); BundleInfo bundleInfo; bool ret = false; ret = dataMgr->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); @@ -850,7 +853,7 @@ HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0200, Function | MediumTe installParam.userId = Constants::DEFAULT_USERID; OHOS::sptr recUninstall = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(recUninstall, nullptr); + EXPECT_NE(recUninstall, nullptr); installer->Uninstall(bundleName, installParam, recUninstall); EXPECT_EQ(recUninstall->GetResultCode(), ERR_OK); } @@ -865,21 +868,21 @@ HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0200, Function | MediumTe HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0300, Function | MediumTest | Level2) { auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); - ASSERT_NE(installer, nullptr); + EXPECT_NE(installer, nullptr); OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver, nullptr); + EXPECT_NE(receiver, nullptr); InstallParam installParam; installParam.installFlag = InstallFlag::NORMAL; std::string bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle12" + ERROR_SUFFIX; installer->Install(bundleFilePath, installParam, receiver); - ASSERT_EQ(receiver->GetResultCode(), ERR_APPEXECFWK_INSTALL_INVALID_HAP_NAME); + EXPECT_EQ(receiver->GetResultCode(), ERR_APPEXECFWK_INSTALL_INVALID_HAP_NAME); std::string bundleName = THIRD_BUNDLE_NAME + "12"; CheckFileNonExist(bundleName); BundleInfo info; std::shared_ptr bms = DelayedSingleton::GetInstance(); auto dataMgr = bms->GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool isBundleExist = dataMgr->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, info); EXPECT_FALSE(isBundleExist); } @@ -893,11 +896,11 @@ HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0300, Function | MediumTe HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0400, Function | MediumTest | Level1) { auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); - ASSERT_NE(installer, nullptr); + EXPECT_NE(installer, nullptr); OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver, nullptr); + EXPECT_NE(receiver, nullptr); OHOS::sptr receiver2 = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver2, nullptr); + EXPECT_NE(receiver2, nullptr); InstallParam installParam; installParam.installFlag = InstallFlag::NORMAL; std::string bundleName = THIRD_BUNDLE_NAME + "5"; @@ -914,10 +917,10 @@ HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0400, Function | MediumTe StartInstalld(); std::this_thread::sleep_for(1ms); installer->Install(bundleFilePath, installParam, receiver2); - ASSERT_EQ(receiver2->GetResultCode(), ERR_OK); + EXPECT_EQ(receiver2->GetResultCode(), ERR_OK); CheckFileExist(bundleName); OHOS::sptr recUninstall = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(recUninstall, nullptr); + EXPECT_NE(recUninstall, nullptr); installer->Uninstall(bundleName, installParam, recUninstall); EXPECT_EQ(recUninstall->GetResultCode(), ERR_OK); } @@ -932,27 +935,27 @@ HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0400, Function | MediumTe HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0500, Function | MediumTest | Level1) { auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); - ASSERT_NE(installer, nullptr); + EXPECT_NE(installer, nullptr); OHOS::sptr normalInstall = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(normalInstall, nullptr); + EXPECT_NE(normalInstall, nullptr); InstallParam installParam; installParam.installFlag = InstallFlag::NORMAL; std::string bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle9" + Constants::INSTALL_FILE_SUFFIX; installer->Install(bundleFilePath, installParam, normalInstall); - ASSERT_EQ(normalInstall->GetResultCode(), ERR_OK); + EXPECT_EQ(normalInstall->GetResultCode(), ERR_OK); std::string bundleName = THIRD_BUNDLE_NAME + "2"; CheckFileExist(bundleName); std::string upgradeFilePath = BUNDLE_TMPPATH + "bmsThirdBundle7" + Constants::INSTALL_FILE_SUFFIX; OHOS::sptr replaceInstall = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(replaceInstall, nullptr); + EXPECT_NE(replaceInstall, nullptr); installParam.installFlag = InstallFlag::REPLACE_EXISTING; installer->Install(upgradeFilePath, installParam, replaceInstall); - ASSERT_EQ(replaceInstall->GetResultCode(), ERR_APPEXECFWK_INSTALL_VERSION_DOWNGRADE); + EXPECT_EQ(replaceInstall->GetResultCode(), ERR_APPEXECFWK_INSTALL_VERSION_DOWNGRADE); CheckFileExist(bundleName); OHOS::sptr uninstall = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(uninstall, nullptr); + EXPECT_NE(uninstall, nullptr); installParam.userId = Constants::DEFAULT_USERID; installer->Uninstall(bundleName, installParam, uninstall); EXPECT_EQ(uninstall->GetResultCode(), ERR_OK) << "uninstall fail!" << bundleName; @@ -968,23 +971,23 @@ HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0500, Function | MediumTe HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0600, Function | MediumTest | Level1) { auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); - ASSERT_NE(installer, nullptr); + EXPECT_NE(installer, nullptr); OHOS::sptr normalInstall = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(normalInstall, nullptr); + EXPECT_NE(normalInstall, nullptr); InstallParam installParam; installParam.installFlag = InstallFlag::NORMAL; std::string bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle7" + Constants::INSTALL_FILE_SUFFIX; installer->Install(bundleFilePath, installParam, normalInstall); - ASSERT_EQ(normalInstall->GetResultCode(), ERR_OK); + EXPECT_EQ(normalInstall->GetResultCode(), ERR_OK); std::string bundleName = THIRD_BUNDLE_NAME + "2"; CheckFileExist(bundleName); std::string upgradeFilePath = BUNDLE_TMPPATH + "bmsThirdBundle9" + Constants::INSTALL_FILE_SUFFIX; OHOS::sptr replaceInstall = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(replaceInstall, nullptr); + EXPECT_NE(replaceInstall, nullptr); installParam.installFlag = InstallFlag::REPLACE_EXISTING; installer->Install(upgradeFilePath, installParam, replaceInstall); - ASSERT_EQ(replaceInstall->GetResultCode(), ERR_OK); + EXPECT_EQ(replaceInstall->GetResultCode(), ERR_OK); CheckFileExist(bundleName); StopBundleMgrService(); @@ -994,14 +997,14 @@ HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0600, Function | MediumTe BundleInfo info; std::shared_ptr bms = DelayedSingleton::GetInstance(); auto dataMgr = bms->GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool isBundleExist = dataMgr->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, info); EXPECT_TRUE(isBundleExist); std::cout << "info-name:" << info.name << std::endl; OHOS::sptr uninstall = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(uninstall, nullptr); + EXPECT_NE(uninstall, nullptr); installParam.userId = Constants::DEFAULT_USERID; installer->Uninstall(bundleName, installParam, uninstall); EXPECT_EQ(uninstall->GetResultCode(), ERR_OK) << "uninstall fail!" << bundleName; @@ -1017,27 +1020,27 @@ HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0600, Function | MediumTe HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0700, Function | MediumTest | Level1) { auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); - ASSERT_NE(installer, nullptr); + EXPECT_NE(installer, nullptr); OHOS::sptr normalInstall = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(normalInstall, nullptr); + EXPECT_NE(normalInstall, nullptr); InstallParam installParam; installParam.installFlag = InstallFlag::NORMAL; std::string bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle7" + Constants::INSTALL_FILE_SUFFIX; installer->Install(bundleFilePath, installParam, normalInstall); - ASSERT_EQ(normalInstall->GetResultCode(), ERR_OK); + EXPECT_EQ(normalInstall->GetResultCode(), ERR_OK); std::string bundleName = THIRD_BUNDLE_NAME + "2"; CheckFileExist(bundleName); std::string upgradeFilePath = BUNDLE_TMPPATH + "bmsThirdBundle10" + Constants::INSTALL_FILE_SUFFIX; OHOS::sptr replaceInstall = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(replaceInstall, nullptr); + EXPECT_NE(replaceInstall, nullptr); installParam.installFlag = InstallFlag::REPLACE_EXISTING; installer->Install(upgradeFilePath, installParam, replaceInstall); - ASSERT_EQ(replaceInstall->GetResultCode(), ERR_OK); + EXPECT_EQ(replaceInstall->GetResultCode(), ERR_OK); CheckFileExist(bundleName); OHOS::sptr uninstall = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(uninstall, nullptr); + EXPECT_NE(uninstall, nullptr); installParam.userId = Constants::DEFAULT_USERID; installer->Uninstall(bundleName, installParam, uninstall); EXPECT_EQ(uninstall->GetResultCode(), ERR_OK) << "uninstall fail!" << bundleName; @@ -1052,29 +1055,29 @@ HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0700, Function | MediumTe HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0800, Function | MediumTest | Level1) { auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); - ASSERT_NE(installer, nullptr); + EXPECT_NE(installer, nullptr); OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver, nullptr); + EXPECT_NE(receiver, nullptr); OHOS::sptr receiver2 = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver2, nullptr); + EXPECT_NE(receiver2, nullptr); InstallParam installParam; installParam.installFlag = InstallFlag::NORMAL; std::string bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle1" + Constants::INSTALL_FILE_SUFFIX; installer->Install(bundleFilePath, installParam, receiver); - ASSERT_EQ(receiver->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; + EXPECT_EQ(receiver->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; std::string bundleName = THIRD_BUNDLE_NAME + "1"; std::string modulePackage = "com.third.hiworld.example.h1"; CheckFileExist(bundleName, modulePackage); bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle4" + Constants::INSTALL_FILE_SUFFIX; installer->Install(bundleFilePath, installParam, receiver2); - ASSERT_EQ(receiver2->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; + EXPECT_EQ(receiver2->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; std::string modulePackage2 = "com.third.hiworld.example.h2"; CheckFileExist(bundleName, modulePackage2); OHOS::sptr recUninstall = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(recUninstall, nullptr); + EXPECT_NE(recUninstall, nullptr); installParam.userId = Constants::DEFAULT_USERID; installer->Uninstall(bundleName, installParam, recUninstall); EXPECT_EQ(recUninstall->GetResultCode(), ERR_OK) << "uninstall fail!" << bundleName; @@ -1089,17 +1092,17 @@ HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0800, Function | MediumTe HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0900, Function | MediumTest | Level1) { auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); - ASSERT_NE(installer, nullptr); + EXPECT_NE(installer, nullptr); OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver, nullptr); + EXPECT_NE(receiver, nullptr); OHOS::sptr receiver2 = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver2, nullptr); + EXPECT_NE(receiver2, nullptr); InstallParam installParam; installParam.installFlag = InstallFlag::NORMAL; std::string bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle3" + Constants::INSTALL_FILE_SUFFIX; installer->Install(bundleFilePath, installParam, receiver); - ASSERT_EQ(receiver->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; + EXPECT_EQ(receiver->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; std::string bundleName = THIRD_BUNDLE_NAME + "1"; std::string modulePackage = "com.third.hiworld.example.h1"; std::vector hap1AbilityNames = {}; @@ -1107,13 +1110,13 @@ HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0900, Function | MediumTe bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle6" + Constants::INSTALL_FILE_SUFFIX; installer->Install(bundleFilePath, installParam, receiver2); - ASSERT_EQ(receiver2->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; + EXPECT_EQ(receiver2->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; std::string modulePackage2 = "com.third.hiworld.example.h2"; std::vector hap2AbilityNames = {}; CheckFileExist(bundleName, modulePackage2, hap2AbilityNames); OHOS::sptr recUninstall = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(recUninstall, nullptr); + EXPECT_NE(recUninstall, nullptr); installParam.userId = Constants::DEFAULT_USERID; installer->Uninstall(bundleName, installParam, recUninstall); EXPECT_EQ(recUninstall->GetResultCode(), ERR_OK) << "uninstall fail!" << bundleName; @@ -1128,17 +1131,17 @@ HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0900, Function | MediumTe HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1000, Function | MediumTest | Level1) { auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); - ASSERT_NE(installer, nullptr); + EXPECT_NE(installer, nullptr); OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver, nullptr); + EXPECT_NE(receiver, nullptr); OHOS::sptr receiver2 = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver2, nullptr); + EXPECT_NE(receiver2, nullptr); InstallParam installParam; installParam.installFlag = InstallFlag::NORMAL; std::string bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle3" + Constants::INSTALL_FILE_SUFFIX; installer->Install(bundleFilePath, installParam, receiver); - ASSERT_EQ(receiver->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; + EXPECT_EQ(receiver->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; std::string bundleName = THIRD_BUNDLE_NAME + "1"; std::string modulePackage = "com.third.hiworld.example.h1"; std::vector hap1AbilityNames = {}; @@ -1146,13 +1149,13 @@ HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1000, Function | MediumTe bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle4" + Constants::INSTALL_FILE_SUFFIX; installer->Install(bundleFilePath, installParam, receiver2); - ASSERT_EQ(receiver2->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; + EXPECT_EQ(receiver2->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; std::string modulePackage2 = "com.third.hiworld.example.h2"; std::vector hap2AbilityNames = {"bmsThirdBundle_A1"}; CheckFileExist(bundleName, modulePackage2, hap2AbilityNames); OHOS::sptr recUninstall = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(recUninstall, nullptr); + EXPECT_NE(recUninstall, nullptr); installParam.userId = Constants::DEFAULT_USERID; installer->Uninstall(bundleName, installParam, recUninstall); EXPECT_EQ(recUninstall->GetResultCode(), ERR_OK) << "uninstall fail!" << bundleName; @@ -1168,17 +1171,17 @@ HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1000, Function | MediumTe HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1100, Function | MediumTest | Level1) { auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); - ASSERT_NE(installer, nullptr); + EXPECT_NE(installer, nullptr); OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver, nullptr); + EXPECT_NE(receiver, nullptr); OHOS::sptr receiver2 = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver2, nullptr); + EXPECT_NE(receiver2, nullptr); InstallParam installParam; installParam.installFlag = InstallFlag::NORMAL; std::string bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle3" + Constants::INSTALL_FILE_SUFFIX; installer->Install(bundleFilePath, installParam, receiver); - ASSERT_EQ(receiver->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; + EXPECT_EQ(receiver->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; std::string bundleName = THIRD_BUNDLE_NAME + "1"; std::string modulePackage = "com.third.hiworld.example.h1"; std::vector hap1AbilityNames = {}; @@ -1186,13 +1189,13 @@ HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1100, Function | MediumTe bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle5" + Constants::INSTALL_FILE_SUFFIX; installer->Install(bundleFilePath, installParam, receiver2); - ASSERT_EQ(receiver2->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; + EXPECT_EQ(receiver2->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; std::string modulePackage2 = "com.third.hiworld.example.h2"; std::vector hap2AbilityNames = {"bmsThirdBundle_A1", "bmsThirdBundle_A2"}; CheckFileExist(bundleName, modulePackage2, hap2AbilityNames); OHOS::sptr recUninstall = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(recUninstall, nullptr); + EXPECT_NE(recUninstall, nullptr); installParam.userId = Constants::DEFAULT_USERID; installer->Uninstall(bundleName, installParam, recUninstall); EXPECT_EQ(recUninstall->GetResultCode(), ERR_OK) << "uninstall fail!" << bundleName; @@ -1207,17 +1210,17 @@ HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1100, Function | MediumTe HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1200, Function | MediumTest | Level1) { auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); - ASSERT_NE(installer, nullptr); + EXPECT_NE(installer, nullptr); OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver, nullptr); + EXPECT_NE(receiver, nullptr); OHOS::sptr receiver2 = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver2, nullptr); + EXPECT_NE(receiver2, nullptr); InstallParam installParam; installParam.installFlag = InstallFlag::NORMAL; std::string bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle1" + Constants::INSTALL_FILE_SUFFIX; installer->Install(bundleFilePath, installParam, receiver); - ASSERT_EQ(receiver->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; + EXPECT_EQ(receiver->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; std::string bundleName = THIRD_BUNDLE_NAME + "1"; std::string modulePackage = "com.third.hiworld.example.h1"; std::vector hap1AbilityNames = {"bmsThirdBundle_A1"}; @@ -1225,13 +1228,13 @@ HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1200, Function | MediumTe bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle6" + Constants::INSTALL_FILE_SUFFIX; installer->Install(bundleFilePath, installParam, receiver2); - ASSERT_EQ(receiver2->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; + EXPECT_EQ(receiver2->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; std::string modulePackage2 = "com.third.hiworld.example.h2"; std::vector hap2AbilityNames = {}; CheckFileExist(bundleName, modulePackage2, hap2AbilityNames); OHOS::sptr recUninstall = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(recUninstall, nullptr); + EXPECT_NE(recUninstall, nullptr); installParam.userId = Constants::DEFAULT_USERID; installer->Uninstall(bundleName, installParam, recUninstall); EXPECT_EQ(recUninstall->GetResultCode(), ERR_OK) << "uninstall fail!" << bundleName; @@ -1246,17 +1249,17 @@ HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1200, Function | MediumTe HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1300, Function | MediumTest | Level1) { auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); - ASSERT_NE(installer, nullptr); + EXPECT_NE(installer, nullptr); OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver, nullptr); + EXPECT_NE(receiver, nullptr); OHOS::sptr receiver2 = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver2, nullptr); + EXPECT_NE(receiver2, nullptr); InstallParam installParam; installParam.installFlag = InstallFlag::NORMAL; std::string bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle1" + Constants::INSTALL_FILE_SUFFIX; installer->Install(bundleFilePath, installParam, receiver); - ASSERT_EQ(receiver->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; + EXPECT_EQ(receiver->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; std::string bundleName = THIRD_BUNDLE_NAME + "1"; std::string modulePackage = "com.third.hiworld.example.h1"; std::vector hap1AbilityNames = {"bmsThirdBundle_A1"}; @@ -1264,13 +1267,13 @@ HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1300, Function | MediumTe bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle4" + Constants::INSTALL_FILE_SUFFIX; installer->Install(bundleFilePath, installParam, receiver2); - ASSERT_EQ(receiver2->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; + EXPECT_EQ(receiver2->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; std::string modulePackage2 = "com.third.hiworld.example.h2"; std::vector hap2AbilityNames = {"bmsThirdBundle_A1"}; CheckFileExist(bundleName, modulePackage2, hap2AbilityNames); OHOS::sptr recUninstall = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(recUninstall, nullptr); + EXPECT_NE(recUninstall, nullptr); installParam.userId = Constants::DEFAULT_USERID; installer->Uninstall(bundleName, installParam, recUninstall); EXPECT_EQ(recUninstall->GetResultCode(), ERR_OK) << "uninstall fail!" << bundleName; @@ -1285,17 +1288,17 @@ HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1300, Function | MediumTe HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1400, Function | MediumTest | Level1) { auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); - ASSERT_NE(installer, nullptr); + EXPECT_NE(installer, nullptr); OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver, nullptr); + EXPECT_NE(receiver, nullptr); OHOS::sptr receiver2 = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver2, nullptr); + EXPECT_NE(receiver2, nullptr); InstallParam installParam; installParam.installFlag = InstallFlag::NORMAL; std::string bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle1" + Constants::INSTALL_FILE_SUFFIX; installer->Install(bundleFilePath, installParam, receiver); - ASSERT_EQ(receiver->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; + EXPECT_EQ(receiver->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; std::string bundleName = THIRD_BUNDLE_NAME + "1"; std::string modulePackage = "com.third.hiworld.example.h1"; std::vector hap1AbilityNames = {"bmsThirdBundle_A1"}; @@ -1303,13 +1306,13 @@ HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1400, Function | MediumTe bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle5" + Constants::INSTALL_FILE_SUFFIX; installer->Install(bundleFilePath, installParam, receiver2); - ASSERT_EQ(receiver2->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; + EXPECT_EQ(receiver2->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; std::string modulePackage2 = "com.third.hiworld.example.h2"; std::vector hap2AbilityNames = {"bmsThirdBundle_A1", "bmsThirdBundle_A2"}; CheckFileExist(bundleName, modulePackage2, hap2AbilityNames); OHOS::sptr recUninstall = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(recUninstall, nullptr); + EXPECT_NE(recUninstall, nullptr); installParam.userId = Constants::DEFAULT_USERID; installer->Uninstall(bundleName, installParam, recUninstall); EXPECT_EQ(recUninstall->GetResultCode(), ERR_OK) << "uninstall fail!" << bundleName; @@ -1325,17 +1328,17 @@ HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1400, Function | MediumTe HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1500, Function | MediumTest | Level1) { auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); - ASSERT_NE(installer, nullptr); + EXPECT_NE(installer, nullptr); OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver, nullptr); + EXPECT_NE(receiver, nullptr); OHOS::sptr receiver2 = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver2, nullptr); + EXPECT_NE(receiver2, nullptr); InstallParam installParam; installParam.installFlag = InstallFlag::NORMAL; std::string bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle2" + Constants::INSTALL_FILE_SUFFIX; installer->Install(bundleFilePath, installParam, receiver); - ASSERT_EQ(receiver->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; + EXPECT_EQ(receiver->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; std::string bundleName = THIRD_BUNDLE_NAME + "1"; std::string modulePackage = "com.third.hiworld.example.h1"; std::vector hap1AbilityNames = {"bmsThirdBundle_A1", "bmsThirdBundle_A2"}; @@ -1343,13 +1346,13 @@ HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1500, Function | MediumTe bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle6" + Constants::INSTALL_FILE_SUFFIX; installer->Install(bundleFilePath, installParam, receiver2); - ASSERT_EQ(receiver2->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; + EXPECT_EQ(receiver2->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; std::string modulePackage2 = "com.third.hiworld.example.h2"; std::vector hap2AbilityNames = {}; CheckFileExist(bundleName, modulePackage2, hap2AbilityNames); OHOS::sptr recUninstall = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(recUninstall, nullptr); + EXPECT_NE(recUninstall, nullptr); installParam.userId = Constants::DEFAULT_USERID; installer->Uninstall(bundleName, installParam, recUninstall); EXPECT_EQ(recUninstall->GetResultCode(), ERR_OK) << "uninstall fail!" << bundleName; @@ -1364,17 +1367,17 @@ HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1500, Function | MediumTe HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1600, Function | MediumTest | Level1) { auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); - ASSERT_NE(installer, nullptr); + EXPECT_NE(installer, nullptr); OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver, nullptr); + EXPECT_NE(receiver, nullptr); OHOS::sptr receiver2 = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver2, nullptr); + EXPECT_NE(receiver2, nullptr); InstallParam installParam; installParam.installFlag = InstallFlag::NORMAL; std::string bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle2" + Constants::INSTALL_FILE_SUFFIX; installer->Install(bundleFilePath, installParam, receiver); - ASSERT_EQ(receiver->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; + EXPECT_EQ(receiver->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; std::string bundleName = THIRD_BUNDLE_NAME + "1"; std::string modulePackage = "com.third.hiworld.example.h1"; std::vector hap1AbilityNames = {"bmsThirdBundle_A1", "bmsThirdBundle_A2"}; @@ -1382,13 +1385,13 @@ HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1600, Function | MediumTe bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle4" + Constants::INSTALL_FILE_SUFFIX; installer->Install(bundleFilePath, installParam, receiver2); - ASSERT_EQ(receiver2->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; + EXPECT_EQ(receiver2->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; std::string modulePackage2 = "com.third.hiworld.example.h2"; std::vector hap2AbilityNames = {"bmsThirdBundle_A1"}; CheckFileExist(bundleName, modulePackage2, hap2AbilityNames); OHOS::sptr recUninstall = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(recUninstall, nullptr); + EXPECT_NE(recUninstall, nullptr); installParam.userId = Constants::DEFAULT_USERID; installer->Uninstall(bundleName, installParam, recUninstall); EXPECT_EQ(recUninstall->GetResultCode(), ERR_OK) << "uninstall fail!" << bundleName; @@ -1403,17 +1406,17 @@ HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1600, Function | MediumTe HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1700, Function | MediumTest | Level1) { auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); - ASSERT_NE(installer, nullptr); + EXPECT_NE(installer, nullptr); OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver, nullptr); + EXPECT_NE(receiver, nullptr); OHOS::sptr receiver2 = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver2, nullptr); + EXPECT_NE(receiver2, nullptr); InstallParam installParam; installParam.installFlag = InstallFlag::NORMAL; std::string bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle2" + Constants::INSTALL_FILE_SUFFIX; installer->Install(bundleFilePath, installParam, receiver); - ASSERT_EQ(receiver->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; + EXPECT_EQ(receiver->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; std::string bundleName = THIRD_BUNDLE_NAME + "1"; std::string modulePackage = "com.third.hiworld.example.h1"; std::vector hap1AbilityNames = {"bmsThirdBundle_A1", "bmsThirdBundle_A2"}; @@ -1421,13 +1424,13 @@ HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1700, Function | MediumTe bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle5" + Constants::INSTALL_FILE_SUFFIX; installer->Install(bundleFilePath, installParam, receiver2); - ASSERT_EQ(receiver2->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; + EXPECT_EQ(receiver2->GetResultCode(), ERR_OK) << "install fail!" << bundleFilePath; std::string modulePackage2 = "com.third.hiworld.example.h2"; std::vector hap2AbilityNames = {"bmsThirdBundle_A1", "bmsThirdBundle_A2"}; CheckFileExist(bundleName, modulePackage2, hap2AbilityNames); OHOS::sptr recUninstall = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(recUninstall, nullptr); + EXPECT_NE(recUninstall, nullptr); installParam.userId = Constants::DEFAULT_USERID; installer->Uninstall(bundleName, installParam, recUninstall); EXPECT_EQ(recUninstall->GetResultCode(), ERR_OK) << "uninstall fail!" << bundleName; @@ -1456,7 +1459,7 @@ HWTEST_F(BmsBundleInstallerModuleTest, BundleDataStorage_0100, Function | Medium std::string bundleName = baseBundleName + std::to_string(i * saveTimes + j); InnerBundleInfo innerBundleInfo = CreateInnerBundleInfo(bundleName); bool res = bundleDataStorage.SaveStorageBundleInfo(deviceId_, innerBundleInfo); - ASSERT_TRUE(res) << "save bundle data fail"; + EXPECT_TRUE(res) << "save bundle data fail"; bundleNames.emplace_back(bundleName); innerBundleInfoStrs.emplace_back(innerBundleInfo.ToString()); innerBundleInfos.emplace_back(innerBundleInfo); @@ -1467,7 +1470,7 @@ HWTEST_F(BmsBundleInstallerModuleTest, BundleDataStorage_0100, Function | Medium */ std::map> dataMap; bool loadRes = bundleDataStorage.LoadAllData(dataMap); - ASSERT_TRUE(loadRes) << "load data fail!!!"; + EXPECT_TRUE(loadRes) << "load data fail!!!"; for (std::string item : bundleNames) { std::map innerBundleInfoMap = dataMap[item]; for (auto iter = innerBundleInfoMap.begin(); iter != innerBundleInfoMap.end(); ++iter) { @@ -1485,7 +1488,7 @@ HWTEST_F(BmsBundleInstallerModuleTest, BundleDataStorage_0100, Function | Medium } for (InnerBundleInfo inner : innerBundleInfos) { bool delRes = bundleDataStorage.DeleteStorageBundleInfo(deviceId_, inner); - ASSERT_TRUE(delRes) << "delete data fail!!!"; + EXPECT_TRUE(delRes) << "delete data fail!!!"; } } @@ -1508,7 +1511,7 @@ HWTEST_F(BmsBundleInstallerModuleTest, BundleDataStorage_0200, Function | Medium std::string bundleName = baseBundleName + std::to_string(i); InnerBundleInfo innerBundleInfo = CreateInnerBundleInfo(bundleName); bool res = bundleDataStorage.SaveStorageBundleInfo(deviceId_, innerBundleInfo); - ASSERT_TRUE(res) << "save bundle data fail"; + EXPECT_TRUE(res) << "save bundle data fail"; bundleNames.emplace_back(bundleName); innerBundleInfos.emplace_back(innerBundleInfo); } @@ -1522,7 +1525,7 @@ HWTEST_F(BmsBundleInstallerModuleTest, BundleDataStorage_0200, Function | Medium std::shared_ptr dataMgr = GetBundleDataMgr(); if (dataMgr == nullptr) { - ASSERT_TRUE(false); + EXPECT_TRUE(false); } for (std::string item : bundleNames) { @@ -1535,7 +1538,7 @@ HWTEST_F(BmsBundleInstallerModuleTest, BundleDataStorage_0200, Function | Medium for (InnerBundleInfo inner : innerBundleInfos) { bool delRes = bundleDataStorage.DeleteStorageBundleInfo(deviceId_, inner); - ASSERT_TRUE(delRes) << "delete data fail!!!"; + EXPECT_TRUE(delRes) << "delete data fail!!!"; } } @@ -1553,7 +1556,7 @@ HWTEST_F(BmsBundleInstallerModuleTest, BundleDataStorage003, TestSize.Level3) DistributedKvDataManager dataManager; std::unique_ptr kvStorePtr = GetKvStorePtr(dataManager); if (!kvStorePtr) { - ASSERT_TRUE(false) << "kvStorePtr is nullptr"; + EXPECT_TRUE(false) << "kvStorePtr is nullptr"; } int saveTimes = 100; @@ -1579,14 +1582,14 @@ HWTEST_F(BmsBundleInstallerModuleTest, BundleDataStorage003, TestSize.Level3) BundleDataStorageDatabase bundleDataStorage; std::map> bundleDatas; bool getBundleData = bundleDataStorage.LoadAllData(bundleDatas); - ASSERT_TRUE(getBundleData) << "get bundle data from database fail!"; + EXPECT_TRUE(getBundleData) << "get bundle data from database fail!"; StopBundleMgrService(); StartBundleMgrService(); std::shared_ptr dataMgr = GetBundleDataMgr(); if (dataMgr == nullptr) { - ASSERT_TRUE(false); + EXPECT_TRUE(false); } ApplicationInfo appInfo; for (int i = 0; i < saveTimes; i++) { diff --git a/services/test/moduletest/common/bms/bundle_uninstall_test/BUILD.gn b/services/test/moduletest/common/bms/bundle_uninstall_test/BUILD.gn index 1d5d96d811..4b33f57d20 100755 --- a/services/test/moduletest/common/bms/bundle_uninstall_test/BUILD.gn +++ b/services/test/moduletest/common/bms/bundle_uninstall_test/BUILD.gn @@ -32,6 +32,7 @@ ohos_moduletest("BmsBundleUninstallerModuleTest") { "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core/include/bundlemgr", "//third_party/json/include", "${services_path}/test/mock/include", + "//third_party/jsoncpp/include", ] sources = [ @@ -45,6 +46,9 @@ ohos_moduletest("BmsBundleUninstallerModuleTest") { "${services_path}/bundlemgr/src/installd/installd_host_impl.cpp", "${services_path}/bundlemgr/src/installd/installd_operator.cpp", "${services_path}/bundlemgr/src/installd/installd_service.cpp", + "${services_path}/bundlemgr/src/kvstore_death_recipient_callback.cpp", + "${services_path}/bundlemgr/src/module_usage_data_storage.cpp", + "${services_path}/bundlemgr/src/permission_changed_death_recipient.cpp", ] sources += bundle_install_sources @@ -72,6 +76,7 @@ ohos_moduletest("BmsBundleUninstallerModuleTest") { "//foundation/distributeddatamgr/distributeddatamgr/interfaces/innerkits/distributeddata:distributeddata_inner", "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", ] external_deps = [ diff --git a/services/test/moduletest/common/bms/bundle_uninstall_test/bms_bundle_uninstaller_module_test.cpp b/services/test/moduletest/common/bms/bundle_uninstall_test/bms_bundle_uninstaller_module_test.cpp index 5a65a0ab72..73ceee1bf7 100755 --- a/services/test/moduletest/common/bms/bundle_uninstall_test/bms_bundle_uninstaller_module_test.cpp +++ b/services/test/moduletest/common/bms/bundle_uninstall_test/bms_bundle_uninstaller_module_test.cpp @@ -157,7 +157,7 @@ void BmsBundleUninstallerModuleTest::CheckBundleInfoExist(const std::string bund BundleInfo info; std::shared_ptr bms = DelayedSingleton::GetInstance(); auto dataMgr = bms->GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool isBundleExist = dataMgr->GetBundleInfo(bundlename, BundleFlag::GET_BUNDLE_DEFAULT, info); EXPECT_TRUE(isBundleExist); } @@ -167,7 +167,7 @@ void BmsBundleUninstallerModuleTest::CheckBundleInfoNonExist(const std::string b BundleInfo info; std::shared_ptr bms = DelayedSingleton::GetInstance(); auto dataMgr = bms->GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); bool isBundleExist = dataMgr->GetBundleInfo(bundlename, BundleFlag::GET_BUNDLE_DEFAULT, info); EXPECT_FALSE(isBundleExist); } @@ -214,13 +214,13 @@ HWTEST_F(BmsBundleUninstallerModuleTest, Uninstall_0100, Function | MediumTest | { std::string bundlePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1" + Constants::INSTALL_FILE_SUFFIX; ErrCode installResult = InstallBundle(bundlePath); - ASSERT_EQ(installResult, ERR_OK); + EXPECT_EQ(installResult, ERR_OK); CheckFileExist(BUNDLE_NAME); CheckBundleInfoExist(BUNDLE_NAME); ErrCode uninstallResult = UninstallBundle(BUNDLE_NAME); - ASSERT_EQ(uninstallResult, ERR_OK); + EXPECT_EQ(uninstallResult, ERR_OK); CheckFileNonExist(BUNDLE_NAME); CheckBundleInfoNonExist(BUNDLE_NAME); } @@ -234,14 +234,14 @@ HWTEST_F(BmsBundleUninstallerModuleTest, Uninstall_0200, Function | MediumTest | { std::string bundlePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1" + Constants::INSTALL_FILE_SUFFIX; ErrCode installResult = InstallBundle(bundlePath); - ASSERT_EQ(installResult, ERR_OK); + EXPECT_EQ(installResult, ERR_OK); CheckFileExist(BUNDLE_NAME); CheckBundleInfoExist(BUNDLE_NAME); std::string errorBundleName = "com.third.test0"; ErrCode uninstallResult = UninstallBundle(errorBundleName); - ASSERT_EQ(uninstallResult, ERR_APPEXECFWK_UNINSTALL_MISSING_INSTALLED_BUNDLE); + EXPECT_EQ(uninstallResult, ERR_APPEXECFWK_UNINSTALL_MISSING_INSTALLED_BUNDLE); CheckFileNonExist(errorBundleName); CheckBundleInfoNonExist(errorBundleName); @@ -256,18 +256,18 @@ HWTEST_F(BmsBundleUninstallerModuleTest, Uninstall_0300, Function | MediumTest | { std::string bundlePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1" + Constants::INSTALL_FILE_SUFFIX; ErrCode installResult = InstallBundle(bundlePath); - ASSERT_EQ(installResult, ERR_OK); + EXPECT_EQ(installResult, ERR_OK); CheckFileExist(BUNDLE_NAME); CheckBundleInfoExist(BUNDLE_NAME); ErrCode uninstallResult = UninstallBundle(BUNDLE_NAME); - ASSERT_EQ(uninstallResult, ERR_OK); + EXPECT_EQ(uninstallResult, ERR_OK); CheckFileNonExist(BUNDLE_NAME); CheckBundleInfoNonExist(BUNDLE_NAME); uninstallResult = UninstallBundle(BUNDLE_NAME); - ASSERT_EQ(uninstallResult, ERR_APPEXECFWK_UNINSTALL_MISSING_INSTALLED_BUNDLE); + EXPECT_EQ(uninstallResult, ERR_APPEXECFWK_UNINSTALL_MISSING_INSTALLED_BUNDLE); } /** @@ -279,13 +279,13 @@ HWTEST_F(BmsBundleUninstallerModuleTest, Uninstall_0400, Function | MediumTest | { std::string bundlePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1" + Constants::INSTALL_FILE_SUFFIX; ErrCode installResult = InstallBundle(bundlePath); - ASSERT_EQ(installResult, ERR_OK); + EXPECT_EQ(installResult, ERR_OK); CheckFileExist(BUNDLE_NAME); CheckBundleInfoExist(BUNDLE_NAME); ErrCode uninstallResult = UninstallHap(BUNDLE_NAME, MODULE_PACKAGE); - ASSERT_EQ(uninstallResult, ERR_OK); + EXPECT_EQ(uninstallResult, ERR_OK); CheckFileNonExist(BUNDLE_NAME); CheckBundleInfoNonExist(BUNDLE_NAME); } @@ -299,17 +299,17 @@ HWTEST_F(BmsBundleUninstallerModuleTest, Uninstall_0500, Function | MediumTest | { std::string bundlePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1" + Constants::INSTALL_FILE_SUFFIX; ErrCode installResult = InstallBundle(bundlePath); - ASSERT_EQ(installResult, ERR_OK); + EXPECT_EQ(installResult, ERR_OK); bundlePath = THIRD_BUNDLE_PATH + "bmsThirdBundle4" + Constants::INSTALL_FILE_SUFFIX; installResult = InstallBundle(bundlePath); - ASSERT_EQ(installResult, ERR_OK); + EXPECT_EQ(installResult, ERR_OK); CheckFileExist(BUNDLE_NAME); CheckBundleInfoExist(BUNDLE_NAME); ErrCode uninstallResult = UninstallHap(BUNDLE_NAME, MODULE_PACKAGE); - ASSERT_EQ(uninstallResult, ERR_OK); + EXPECT_EQ(uninstallResult, ERR_OK); CheckHapDirNonExist(BUNDLE_NAME, MODULE_PACKAGE); CheckFileExist(BUNDLE_NAME); CheckBundleInfoExist(BUNDLE_NAME); @@ -325,24 +325,24 @@ HWTEST_F(BmsBundleUninstallerModuleTest, Uninstall_0600, Function | MediumTest | BundleInfo info; std::shared_ptr bms = DelayedSingleton::GetInstance(); auto dataMgr = bms->GetDataMgr(); - ASSERT_NE(dataMgr, nullptr); + EXPECT_NE(dataMgr, nullptr); std::string bundlePath = THIRD_BUNDLE_PATH + "bmsThirdBundle13" + Constants::INSTALL_FILE_SUFFIX; std::string bundleName = "com.third.hiworld.example5"; ErrCode installResult = InstallBundle(bundlePath); - ASSERT_EQ(installResult, ERR_OK); + EXPECT_EQ(installResult, ERR_OK); bool isBundleExist = dataMgr->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, info); EXPECT_TRUE(isBundleExist); CheckFileExist(bundleName); CheckBundleInfoExist(bundleName); auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); - ASSERT_NE(installer, nullptr); + EXPECT_NE(installer, nullptr); OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); - ASSERT_NE(receiver, nullptr); + EXPECT_NE(receiver, nullptr); InstallParam installParam; installParam.userId = Constants::DEFAULT_USERID; installer->Uninstall(bundleName, installParam, receiver); - ASSERT_EQ(receiver->GetResultCode(), ERR_OK); + EXPECT_EQ(receiver->GetResultCode(), ERR_OK); isBundleExist = dataMgr->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, info); EXPECT_FALSE(isBundleExist); CheckFileNonExist(bundleName); diff --git a/services/test/moduletest/common/bms/service_start_process_test/BUILD.gn b/services/test/moduletest/common/bms/service_start_process_test/BUILD.gn index 8a8e4a39e6..adf376a677 100755 --- a/services/test/moduletest/common/bms/service_start_process_test/BUILD.gn +++ b/services/test/moduletest/common/bms/service_start_process_test/BUILD.gn @@ -21,7 +21,10 @@ module_output_path = "appexecfwk_standard/mstbundlemgrservice" ohos_moduletest("BmsServiceStartModuleTest") { module_out_path = module_output_path - include_dirs = [ "${appexecfwk_path}/interfaces" ] + include_dirs = [ + "${appexecfwk_path}/interfaces", + "//third_party/jsoncpp/include", + ] sources = [ "${services_path}/bundlemgr/src/bundle_data_mgr.cpp", @@ -31,6 +34,9 @@ ohos_moduletest("BmsServiceStartModuleTest") { "${services_path}/bundlemgr/src/bundle_mgr_service_event_handler.cpp", "${services_path}/bundlemgr/src/bundle_scanner.cpp", "${services_path}/bundlemgr/src/bundle_status_callback_death_recipient.cpp", + "${services_path}/bundlemgr/src/kvstore_death_recipient_callback.cpp", + "${services_path}/bundlemgr/src/module_usage_data_storage.cpp", + "${services_path}/bundlemgr/src/permission_changed_death_recipient.cpp", ] sources += @@ -60,6 +66,7 @@ ohos_moduletest("BmsServiceStartModuleTest") { "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", ] deps += bundle_install_deps diff --git a/test/resource/ams/ams_page_ability_bundle/amsAbilityVisibleTestPageA.hap b/test/resource/ams/ams_page_ability_bundle/amsAbilityVisibleTestPageA.hap new file mode 100644 index 0000000000000000000000000000000000000000..796c49737d0c7fc6b44ce4fed732505d580b5d7b GIT binary patch literal 125783 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 I$l{~_0T&@vr~m)} literal 0 HcmV?d00001 diff --git a/test/resource/ams/ams_page_ability_bundle/amsAbilityVisibleTestServiceB.hap b/test/resource/ams/ams_page_ability_bundle/amsAbilityVisibleTestServiceB.hap new file mode 100644 index 0000000000000000000000000000000000000000..65fc1997d908bc8e73cf3de619fc3c2c8733e25b GIT binary patch literal 131123 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%0DjZKJHRlWp1-TVu|Dh4 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

Ayx1>muI6I5t(YgOo<%RL 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 delta 99373 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

wXDYGHcHA&_~{BJcJA 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

_65gq7IyZPeip4^+mqrNwBHr@lwQOVNO{rR zaJzDfU7Prf-;da2e+}2--Z)dXTOn()&1`p})55>%{Z8Bb1k}50JMMe)+udi#@lC_X$a59&wrFX|8lka(PbkMm9C0HH-3y z+`v0LT?F%|4Ua-?>D06Nm3glMsl5~OIUJ$A0D4u`r!j5sozB>q*S-hNbxmNnXCu&Y z-F%&tUUYcfZ|Z12TV`*pCq#JpIR!>Q>#82oe297n?(k`!p#3WbGjOvyr9f58h1L@8 zZo-c{|21(NJJV;Gp)_HsMNwOv&XhILQD<0Ex>Tb+5gSP~h^}Ui`?28`>A$>-8zW<= z2JN{gNDpbVgxR46+^L)4dD;C#3VfaIw1G+c`T5*71g*ilNL(aS-BR2Bl+=U2HIy$? zIr$0Fy0au-Unje_JAgyG`UuHlF>`O#`x( zItPPxrh`D`j)58j#Fv2@L4N0jP7sqnVb37b*^WicPsd|kP+}a`6`7kx0e=OReOb@? zw@k(@NlOAnJf9LP?CI15!egTY*L-!&-U0zfse3~AZ*gg*=ML5UoL zGVFrC$98oN6%2SY@V{{PCX8IW1bg75H~%EumcTZ$xpxUQS;wgiIi2)Wv?ptfz21MS zY4LMNVs#{xHFsSR7ec}ivobVG!5i*L7j{HCZHj|b^NX1KPFbLjMZr1s5sPVJqJeh$ zPFpNsq_)(K1K9S;VmFeY#mn)$OE*j62zPy4otSxzQJLd%se)Fvo#<&4%A@6g)B3Vr zLl)BBLENOT|AB{It)BT^?XC=d`H!^Kj*9<4+dG=&&R_qu=dUnX<=;?j`S6z?TkLGx z8E|eY94~{uho>lZ(4Q76_7%p?x0B#qdAWJ7Wx;2J-U3i{X_kJ}>gnY^(?l#3G!Oq# z%Xsa$2vWOywSvjq+1IL(MP0IeRo2Mcm&3$K+UIeZQ}{1EMXQuZ7Gkz{M{mAZn_N{I z=3k$otZH^5_^l+^kI3z@e@aXbb@oA%l!$JxIRUk87d{UX+iO%m{yoO{vhht1&tn8v z&)Qq)zbN2wV2|2OwfjCfRyqEOWmp%_!bV-@o~&F4KlP&q!Hp^-W3VqDgW+nS8KX=@ z=w7{QaB5o-1EY!c*z_eVlg8vMTFry{2C2|%EDOq?Q)?SF(9DjSc657u^{7%fzb6;Sct*U{;#3T z^`o5wL!C{5M@D32<#aqkhQN(@lB+AH%RdmB%jLf-$R+9RJ+m|7lKoWuaOG4p8Kc{8 z2cVhh=qSN?Oq1l2XX2`<233e-NACBO6<*Kp_@>@W_Eb2=gp8 zVH2vT!tFl)P8vHOE9r@gnc5*~@1W~R2z->XuPsPF&dDh90OR72Oa5x<*PB8gO~2pW zq=p{7iWA?XWv35HEpxM>Qz%=QP+Ah?>NHkqV?@Sb4Cr5YV;px+Lyo84zjqfCTgB}E z>YXcfHA;W_NIN!KcP8d)_Ez0j@@%7N`2?%EZHkC@P2TLtJN{o{0VdLyssHM@J^+)o z83(FVHI(7?1b2xuoPJ8pO0=8B1<+5G6LV%y72T^e7QWqc59V(D>fS{eCnv=Jdvlh_t?Osx4a z{8{G7L-#1b0cbA%4vo74ZL}tv*^$qVsS!MwMY}X09qbTg5|OSnUA_OdUUaLNZ)K~& zZ}=jvrK$QmzzrsxK#?gtqcX5wqK#T5YT;w{Em89IiPh zRbMkxV#DXCrnh#wtoyG(2a#QCpTfLSy*WzUxiZ(4>G4*ay8eTjjXi1Wq{+n^$LzN+iF+xBG&PO>e6_PV}HNdifOT&&VWr~wDge8 z@7#!*sCji-E`I=1@oW5ZI%JE2*k~U(hB|UXF(gZc#gD+y8l6qAwaH=02{Wg$CV8KD zsbFd-nMwEKBt+awXo7s9k6EQe0F90$Lz^B1&bC&r+r#YoAw?`A229`aJ2OJlM#IO> zQ4c={;%iexQo*Cty%II4uGbsE_^Fk@t7w)sFQ(L)1nXNc7zs8VZ2EUwSVkL=E!`x= z7akMm1ULUl{_)8rNV#NdgS*^@y=;o4Fr}`mrljaK*0yGaY~rTUX)S}yDKpBE9r^mg ztWi%I$lF*kpU=L5v+^ z@1?!+8RsfZ>UZY74t_m6>ZAvCoQ~KKOso%`L&aSq^UM-8RUVz}$)VY=R%54L4?`M!j7d=(yFZRWBO3kuU# zX)nQO2GJTTG{p%4g8SRmmDf@Wb4S*3&{e{_bk~6A!KhlHj9N&A&uTy0+@k6^$0bhD zlk{x|kT*I*#Bm~6 z_hqc5(}68ERXRGx*`!N)-eacgJu*L;wW^chiUPAs-G9)Wr673zItBNoPV!OlT*Qyi)xdNH!a1UGC-Ul)g@4?y7V}v*sgj+cx9OhH!zwV z6%&N$avVB0lJqRk^-j}pB<9ia>?B9$`d@=dSU}z1MiByp5x8GC3$pvEdOBw^6T_o_ z&W&+l@fN4lWi4S}2aJ{< zxPgX~ydLhX+-O@@J+bT&bIxeCK~D9w&$!SWvB~0;%W4b{CkJ&`*QlJA-!$u*B8m-i zrY@5(;JaU^TS8oALnGzbQ-dbx&-x{rQ{yPD^{?KRb6eHR+@T{+69+t43We$U*#oBI zBxmAF?Kv-pDb_ac->0_jG_(g9*vL%dNepy zjPE5aHHc@`3&dxv{2Izo=;*^2Eso`8zSJDVo~uc^vGx<|pVPiIqZb%B={-+MJ}+co z;2|EJki5Zq$^st#w+H$uzNQp!o{|86!3%P~SGNJxnTc4!JS$@!cq!5&W!b16A7Bw% zU+wW;dPSQJ<{kfryWloq@o7ic7NZZ&dDKj2KNa`XOBnt+vs+Od+tktyT|!uQI8pim zH(LaYo9LXzl)alt&xUZsY{!<=-Iflu6|u6z*6iXZ_Et&!(`qO$~bjLBaY`x@V5do0oy3wMzf2Qc6wn`+TZ zFpkHz=N_4ux{vNlol*xZ4!N=VqY*N$z$|dByq}$lUlNZX#%qH=?%rjp16IadM1*Ba zoT-GAdmL1|7ES4U^-$(89wRLqnX@3dIk39n)Tf(}tj={<>eSVmVu#;Os}BeC_{9Fo zS%~>mj+`AM+a&y5Jy}sPuqFmIxyLw<{)vfL=&80dRcKt4Kae&JG(|(0*=*k{h9)5$8pHLnkUtM;4`DLJXNLhaH z<^2Ls?f&*P+#PtxS*T|v_9nMUWI%($vgA&Tkk1^UJF#JaIzlp4fSE02>589`4qI#i z<-XTn#s6391a#s6Z|#3L_m|vVNh;56b|-y3Me{`u7^w7Q6hR0}Pe~SoA~Z$NN?L>G zR{~}2PVI0+q9k>O@83*aAM!Yg+6CQO)9UBN82>bhxGjhqzAg~F4=i{#dNw42uaKvs(MwT zDVypp)fue$4i#;RAqyo_ieYTS!&ux!jft@<*m>9(5BTJyt3PsLpPHy4lhUqT(2ne~ zU$_CLjI`H>lcSf^r;-X8)S1nd8@*a$;^rwN&~Vv*Jn$KAM7;LI>wUz$?!YSgA+nf9 zy}&Y%T(;9+$K?Nvz1zmN^r-SjoRItLUhn}ObbJaUO*UBP8#q#>PHvBx@zcw<^ZvY> zt@m{|8(>G5`T)fkp+<>+!AHQxa&bevFn|z8;IB^}cNAwJV;3qX4>qUSSza@=%P3-& z(`kr@Xpt9y&-kW%w8Iy3ZK+V4o!0qN!k4E7Ax-!^Fuwkk=(jnNs+W29>G!R>pSN9Y z*SwB;gWUf9Oni+BQ#1r0D_OGT`XZlS_$m!oErAK34y^ILAADs5ISWJIbhx%{ahvJM@?IGXMX=Xl@clxeFefxevkEgkx ztUML!S!72e5~{XXoOG`o8EdNJzIa6Qu|Smd$7<;Z589X}#Vy7ro$i<{MaA*Fyp7ML zX|}>;T=)PMjcaW4P$HYcZ^1of8tJJSSuIaoL2yh4-NM5n`+j!!xOrw}f1wqA(Qv&; z=fLZ$w_LVDNWBiUIPBS`U%fK#Vy7hIAqKE}NQ~qWndo|Ayq>vJMy_Cg2CP}W0AWc< z_hyGia$J`K`tg(s-n%5}>C&z=%l+Ns4emIjs-k`?)W>d)8;y=(neCQzh+k zGEC4Kb9;{STf}^a?zaebFM;QG_F8XuVJs}YU0=E*J@ape69i}$nU0~)=*!pTiDg|~ zNx29rK9!EY6Pp{PKgUHw&n0%^(u? z>8*x*z94>l%kdIUsl9C6P*qX1ec)qa19bfB~W?V=024JQpWlj5djoM_~ zkS~ZYKd@mm7x8C?B_R@#bbUq0dzZ+?O0bVGb_}CRv?37SS0$(Q@$TchszHzjYwzZW z(ci_j-QORg-)_H}(Bn6CmZvwh+qk+bT5gFhvS&|JXWZUXN2U-7iQw@hcZG`Y*7$-7 zBZl*;shVI~fS*j$#@v*f_f*Z~mh;iyS5cE)(f6KYS=1d{nyAa!b zKmE~?N=K39ph#n>ULQD&JFw1tM*Jrf=DbVNljN+#$oQrqV;|`CDW9OLVJX0@Zpz=< zvuk9bRi5<9+f(I|+-ql6moME{=1(7I7Uq6QNDCnEU^K@~Ot}5+*|St(6j8`K@>cMs zoILI|s~grJAyud>ZZ>K1nmE=1HpfWwsTCJosm;5XeVjg!@KX_*k>9-cnf1dv=7Nx}KQ$Z<{KnfGXdcHES9)0BOK zI<@Px(WCmcRRS&qc@3`-b^o({9Ky7^Pi5mES$Rnm3E)iYK&JHlUOI?UvQaeZK5;m0 zYOewtc#12&z~z)FH?dy>UHQN>^C(Du!WsBQohCxgg$ppIS8E@xz;T_FLs4lhHOi0( zxKMt-Ba>p+lT)TBEtLR#zhKTSaoFAMnvc#J($`&m$Xfk7kB;B)u_f7`DO&FkwONoB z^z}Nuv?q$mipEErXQ$;tUx>DWMM)@0=*UI!`3USJ=4}SknWE$wF=o|0xv=s_JxXK< zti}17b_`f!s+T1H25+kvX(z?2VH811c1lWfjo4f!$JLeQnX0V4$T$%n{T9EGk%Far z{Utr$Q&T6H21p zhpQrM*-`i&*Bs*>vA6jGGvi(e)h1yN*{+?VvH-R}xPRgM2^FYAT&mKn(pfC+Yhhlf zTv$V*QTu3l>6GX_%(X?%DneZO{b%^nNw-jXQdiyBbNcQQ(X8bX{)F-28H#b)t`+`( z+!3er?39Z-X+}q(0>nNtQ=B1Q*Ek|qg960A?y91^5!T`9>Ek6O-!e*z#dCWW_zD?X z5&)J=YTpeSeLD~?rpRLCND1*Hq>B5IK!W=I7N$?ms}C8aKu>9VX4${)!6|Aa68xDlh;p`6l}(U8i@TteAnz2zTo#??aG1DFv| z5GxWPO|#A)R({_~-;-L9Co9bMsx~;rx2hpriP$7mqDAj#5QTG=sm3}Xy!c$|QB7-K z{s^wiUm6OtJ5O<8kA2%JDAr8!QvKa&5P$hzo^_*}4QAR%dWVsU!u?=O4lF*AR*bZz z5PnJvSTFg8tInhLQHI>F5RYVlH~~Y*o?@V(d35pS5=^@C*Ri#9_AThrYmPn67Qdu~#)*97Wl0Gp{TxSDxcdCeG z^@B$3;}KHF@zO$(tj3>+C4j+uJo_F?4+Mu72pwXGQ28 zR2sURgBhz#DXXH`%Tcq1*O20)n{4QvO7Wr5^1Yy;Im;}@OJ0AxH{>wt(b7H>LUOKDq>3xLTu&`CDEmb!yCyb;1Be-7tP_}$K{4qIg`0F@05Vva7 zvP8KKK?`A49IF#UG`S2`N~`l%`$fXJd(S$`UfZ~qd-%pjbN=mWzbl*RV!~~5!NREp zfKuR-M}V~wbjO;KI3O**{v#vG{7Lm9-b+wx2LBkRBTrw8dgCO$S2bM&r<8PjsdfT{ zTUyKVfb;c-#iB?GX?60O{<_%*(%Z6W&S{18;ogpaJ9)CdM&e(XA9xg*G~`NS1B zJd!*;K;dXyW*G>lj$_WYSyt%MUHf)1oMMXe2<*^|RVMeNg#sNtObGknQOR{W+6%1Q zM=B5dxmIQm$vwYxOx~2ic~t%X`I>?6_^Icol-y?0LS#_%7$5$k{iFjjg^F zehUk~F=LbKTfjC^8$o?!TUG2@QKpFoK?BZb8OMx82YwHiUXw6?F?&%VUhNYe%qe}Y zN&TfZ;C-eU=!7kkMdI|9BzIzHcCu9h=9IYxZ5|ZLanc8Jtdaf>DbDagYpD6$5KCB8 z6orFzzw3v!U!T1@k=@WC=UD_>zo%gnd4Re|mxPa*3%F>xS7ncf*I$}u^^3Yvj-evE zN9&Ioqp`2)+UA|hbMt;u-oVu8%O`P3)3aP*D8cNqB?s9_K7*DLiDm{BF5`=T_!0Tz zm7SW+WQS|3RMH*F1!&5d1EVBwVWi8N1J;_?4faVFUrPcBY43_@Kirv^IPgj0aKSG} z%f%k(16rFXr2;8~?YPxkw2RN-20|YgH7s=mRA~9Lq zR%3%6q`mT-pws6iu~iz=#4jHjRBP+F^5f{#X9WcFi?*>%Z%?AxT+a0L&*obgdLd;z z+ra5T<~O^v?XS1|2!k(+I@0wlW9Tn6bbtIQftHM)MGdB`4^o_+Xx9UFcj9#&1Wg_f z;yBHT^9(Uo`Aw_{%n0#75o}mf#v_XS58zrmDgE@2QnCy50@Yp?h4<~k;i$bf?#5O6 zfPc2^*Ui)#vrtPJA3|P}w8}?w-$7cVelt2kGdV^}W6|dH*U_3XAy1}J)}VfK#dqx^ zfUTA*IB{3ZH|b3>idR-gHQEvOkz@rqV2uj&!ZzQ9Uo|zR@K#ro9)NK>Ta6M-uPE-5 zdGm*=`nd4YXO1~YhVBmE#D`!zbpNn9uXSatkW=6jwJ#}9{wGpgS$J2wK2dlh;|O&HG<m&TvX`aG2VP(&MkGrTRN48=2$; z_WUuwFy$kz7Ub%6=SF6b#!DQ3U+WNIcGE@(gSLHcevf=r30s1*8T9bl%M8Yucx*2l zx^q0<^awPuV<~{Qhh}mAfNAj^xDETA%hjiZ@TLGJsn5bodO8ll^W@)|Ntm8icJLGMzai~ z=o;&^h?)Mj_=iX(ye@ZWJlRv0%A&O&miCZy%GfObbdreugRrH`K1@ppVxW_FzN7jZ zRSO+q^lzW2v7~ueCh!n4AgPqCRlF*CJVG}2P)~Bl%)}h_N=_U?B-;t{ev;tbmnMS6 z%W-!KONs3<0iv@@?I{V8$Vc@uQ?l~q4gW?Zs(Gnj75TsE-$=03eW|nRkF7Z%&+p|; zR%;L2eDLyku|=}o_5E1;*i~oAH!v|iC=hiWsyt5HZo-TXV0@$nZhe{x7bdudq^<9C z($ri+IJJm4a=K+EB`+9mXu6!K#l+fFUF2nRC7$}`cu-U%xHFX77?P9~WzM<}^I%XJ zNAO1bnS(>COc~9$)ksCCp=fVlQ{Ckx5elu~NK@=sgOb55A{p?xmMD9Qb@DGU6SYLQ zslO`BAg8%JIA>pg{+CDP*cXw%LfhFmMs`*8*vm;Lin%}5q@qW2n#{Ifw)i45yKL8u zWuTZJ^|`)A50CU4i@@4ao|>Ylg>?TdFqr5cAT2bpr_nI(%xEnObJz+~QAx6kG4 z0^9!WNcgNJz8^!hRCf4Mtuw4_tLEH=MBUQMhOf1=t}ZnOI9O6JMfWF5R-|kn=Y7_Q zv7+u)-%{U>%Q%3~_636NOn}a>DBZjwn6cEUUd2-_3?WRu**%lNA|w>-w5?& ze@MV^cpJ&mmbTxE7lka0lnzqG63Nlu3Wz5{d=t4V5Ktx@&%VpbX|FoVw zz6)pq=X9uX2O_{sZYCw7XsP=6YY5ekDZ?aG*=_2vm6-CWeZWU7bBaed}%4__K zp6kzHVSDM)w-1^uT5T!ZwqFs7O3Za}L)8=cY&|*ON~}9Dmd6+6!iP7;qg5JG-aTrPG|~Bjecm4&e$Zc*3lVy-5beO}AM; z7#DzwXGv=ui$Zj9;zgVWe6EkE(}dZVP)R>~N&bEmQMhD}HMx7bZ*$Qd?x!pz;px`Pr}-oW z4u7BVjr;n(YVRF&A4j5x$(T2KiEOHLD)Ku_X z#p4bW_lpnT$LH9Ceo4W30d_X(qP({a1wcy}JFeXILl6-VC|r4t?10>lNzE(zsrKg| zk?}xHK(upc?qE8^A}|EP4v`KUBLjc}uVnQNy(+b|B@ zbem1^nk+(`rdSYK;p)MaqM`sioSP=t`$sa1x7wBU;hJUd zIuE@xXgS+IOWQI()7kEHW0iF|0r4tkSi;ERgB&;`Cq5W5m?x_gU2+S1=7@#v`MMfZ z`UGSkzhV5Ezhs4yF|*b9`*R361oIw{;|=BeR0F#-mdeejJ;iuFu*c-0J6)s|$Y~!s zJ4DH4`9!fvYO@fSDwZn_&>CCD_BoP<)|}Vs6tEpr0Xd23NVfQ%ITaNEQl{y?dP@TE zbV~v@;S1WV-;@Q|X*Vq3Hk3GcwnpDwNG`C7T)*o{pLO%tp5?U8YFlSkx&GA4){al% zmcREunW;u8a<8YWBe#SNP+B_jws1)s`jpfg|KQ}8rwzI0)jM*ig`TdCGK1-61@qh{ z_w5EJ$jbM7?iw{uzY!`32>RotC*lPc_qrq#D&V*Ws;?sjhXm-IwEpMpT|zfnRUpwR znp2{;{;Dz$Piun`w~lpS)vt9(^f3!m8tFG$*AhGLdc~W;Rm%0! zXkzea+{yCsh3$)zN8pW{;Yvw{rRjac^&f-5L}L9;QnDnF$7cJ zFQ`&GDE>oYK9~k;4Jl1{7q@UQq1mBA)&G@h`=Q~oAAS-cm15~2SQg*b%(!woXITBI+AlwGsTBwY=0wa35`<742MZ5 zRsd@y+iNti!sDb55$+$#UYlrsb%eZho+B<7TES0tF%Jp`tew~9!xI|CcJcr7p*ZiH zo{S{WRa^1ymq(Hplv!sIQfG)u?9}*=HcGs&m&gk4EcZ0wjB`)D>1cDv(0*izF_t=` zn*0EiFqyqCLO#8@_$2GWQGKg38c{Jg(vQ+avfw?O@B?KfEJdoMn)CiHVhXj+r@gFo zwMEjdwt!C>$W+C0YGAMk{W5ygz`kJVx7rrc{?~T@_aGd*Q@&c?tYN+kaH;y6+nZ_p zd*6KaLeHF@v_WKr5vZj`SpmstRpB(h!^CU9)5(b6(Q3AMvS%Ds3qd#WEhva{59{Sq z+xQ7f>;WAwUa~I{ z!_i%_3ci~h!~LxW^o>2~U(1>lccj`@GBC(3c>8hp+|$S&$KTB@Zz$G&P1Z>f(zI7~ z#kk{&@BXkVIX|u9I>@KB!zsR4wrJb+80ORCq5rf_1?lORi#6FjdC`&6a-yQlc31p! zA8NY37a($sezH-=j6-~vlCYgCyd(~SY4)OtcsJyr=D1}(*yHOwAK!^TV8)(SyrZ=u z4YC~Nh#POcg$2dAd=B^vl2}=jojI=ytqMgELXvVou@nEfjy>a{!C#=N(Rvv1>UE4k z4oX|bN%OYfGi9Xn#~t*JHN|2_dsd@55+wFp1Nd#Kne3NEI<1UjH@dABX4w!bC+Kag zz81hTCTU8WR?f7=s#WEmRo*W7X}Sz(}IegOX?cI-q=hRBm(CSJ}&a}|d*CLL_ zO*`2_*S@P+QTu%1XuG`JkWq5+xOeGr>=iZ<3W$;E;J&`_sRiz4;yzE|?HZr`M7$t1 z@S)gHB5N|RH9uu(W}dICSH;v}yWGj`0TPs^N1qBHmC48((|@F#q}(=_(ODv4Y35Zm z)nAyDh3bPa_*KL!HM+b6z84ljt|5&sq{dlfdJ=w=)7Bb*IV-1zN}EkYf&=fR-NP8{ zD9!T&Ypi;^lL0|zP~_S$SwzbpcVf|;!Ib@ss65t0r^O5_U1EbadS}M2R@ii9Kv+Zk zxuwPuy5_vsbSUH>wzrN{7H2kKHMOtj9~MpqG79uN-Nrn*@%UI%goj8uzAGw-iJ6QW zpZhsRrCDWba?V8u`N;4*Be(MEOU&Jum09t&{Ds<) z!_;!21gtG`^`7nI@dGNS^haz8aYpa94;&(RP$Ru(EsW&`TqpfdJM%ps*DhOnuo%y?A-?v2>hVGCyma*Y`SWyf?1= zF*ed!+YE$hf4<{yaqm|HbPxxJ&{QaDQhFc10nEpqz#k9bXCZxHE78%uIoE|mWpKxF zoBDqyF`nj!(sYlCXilakGIJ zoC;765(x@#!cyj@K?LhrxT#&3q0zbv?EW;ZVc4sezp0oLnDyxaqM`fY&~BpLjW+gw zyEa`Wh|!S4(Uu4+yY7Tl^!Tn`Mc;Q;$;WF8I~PYyGj1~W9}CAj*Af*YO_bSg#;wX) z1KI`Fzh}Iv;Jw`OA9HNJJfp(_v0W&hPQ&C&i+D*31vGG%NAeZr$O^_Ku~Ba%JHDU@ zBSC~3UMyv0rY#G=pHYxLmPjp@i}&{U7ANqb!9@>>{^|mC=A^YVl-kf(js>d?3gvUO zq(f4Se)PG&emb*lAX!|lg$^nMY$kthn%QOk3qB`=p=6&fOe=ugC2V*88 zE^`gTC}*1evKjEIUZBy3Z?BUbvuVCV9kK4ky1c7>B!7Se5T==><;(dA0B0J&x%^;()i&mX1}F=L(!bT{S%bL<}t@bVUDX9P<6*+s!!g=}$>8-GzA(n$jXbu%^GD!%!( z#Un-o$3jPA*7-YxtcacIqPvCh%o@2S$z?##jOZk83i8O|18J6(_GqARd6vR@aAn&> z8dDZ0YT*B~@`I53mL0-?zXPQip{&IDe}v?fu}6M3U&A@LvhtsT=`VUQRk}4ytM>Oi?b<7HlI7+J&Tf?pFMZ}Blte^ z+`024P=7tM1wLdYZ~(s71U3m{fq%7CG^Ll_Fx~`L+5n>wkpPS%x#8jf&UN(33w6D; z3|b}R0*!((M@9w2&`N12GXgF}JvDHDJktg637(HM`<VaeE`>cwh5-=8UBpan}4`JDY##^azdyjpqG9nSR$O4PW`6U znA$m+r9{;dc%Ib=uu6V=?)>L|NJDkvk?T_Qd{c$4P1_xs$#B0!mXh5~ijdQyG>UyDRRtWrjepLm zDZI{h5zi;B_E}A`fdFokY0)xiwQrPf9AGm)>2l~0&&hz%w4sPmE|eKSeGa_q(CVH0 z2CkQ8FwV`Pz0p+}5~WY2ib|xE8_#)>&UAZVIjWZXbGqCjl_TTncgpG1a{JQd7GOEu zc-;l%s(175VQdJ)lFxUEYDref`+q7#EX|MSQ>DSaaaHf{!?Lcc8p@Jx$I?$F-WTj5 zmP=vVANoD&8x@`2Tks9sIdZ8Qux+jjag1k~@Xpmvzh;kRw3a%`_larcW-5|H%+va@%m^J*g-#x+y?rEb7v_QX#XVN6#NfS<-hVs)CcW4EFX?6fAicas@4N?^*RVVM>Ph0d<4Hoex=%y% z&M4K7;eO`oH9}DN_n@7cbl`0M# zaA{@a1e8KNP9$v(S|n7SNa1oAzHf+H(YjJh9PWB9`%7a`Bo3vy`+tL&t{Hdp(t3n@ z(kGke?p@CEIDBGvA2*YR>YZE`5fx*dwty%WY$ z#~(D^j@HpcKPlGcerTOP!mkGV#p8<{g|W0&F4rz~Iif|L?mEW{pope{bV6=9DxV9Ka zedv(_j6AMJ$?-XqXM2vu@MKt48*x*SY%5E0qg=~L{bhI-F||UZQ#})h@!z+R+9OQcN6WEKVO+JZMyUrWe=tiq6!-3`lBnx5X#>jr0B!;Y z{(*kLnNaC2m)aIBak7i1v?t1GbDT2bdM{KZrQYeMyR|*0c)GkSl;#7jp*m*5^9MB@ zte&Tp{2^hrpg45G9p==myhAB{L#yEzaX*d_dEe=aE`NvW!Rw*^H&j`xp1BrmS?an@ zd^^VFRnLqh`4(N^RoSLTzo;}kko`(D zJ?H;QEq}2|z!KFnvwZkpm$FUZ9arBKSQ1%yO@S{Yu-1tyZlz&8<3^PNC4On(uwRM6 zCFymQS_$8K8og#WUsgR+kmlsB6)SI`Zmk5~!!iqq5z_0KrEe%`Mr{#dbT5;nNHNNgeIP#;wl7Dko&zvLaKnHCQw`MminI(N+9g*+F zpzc+)%klXF)d%59riY*IGFcqm4hzzXr7E-Qz&go3h zHGg&egK&bEu2GjNse_UezPIEhV2YP6$)~91Qze)A7D#W#h>qs{{qi~)AtO&Qf*h9D z^hcTWf<)X!0a8e06Ms6V4D@jc=$WIP&7nq_r?Ydp@sXi!MNcnxZkKhsM$r=<#vX@0 zQWd~+Zrh<39U9swRxnjF)M`*SNY((!8-D?pGjgNz6_fToXbYM7aB>gTMj2Zyj@qGbN@{ph_pN?mbhY?SFPChq~}g3BIT8Wq*61 z*~Wac$Vhc3AVx`XaP{czEd^?(GOnZ$cxoTEUR<1_=IInQH?#df&F#5BgB>-`iI7e< zT1tlHDS91hqi1B33H8hCK#ibMvj(Vf)%-5WRg>RXq7!^;L?=)a57mn5-IfoMq(zJR z;!yq+2W^|=9Auj-crdAReHsKBwtt>X?Hf*yz=z}3F{U=$%}$8K2w0o9?#)VbfG-1T zgK^w{ODpjt0IBn{`6>?>@W70jC~DI6ZH{X(I2u9YVFZpt?N5|x`;lv#ACWj_4-nUB z(78I`i1$cqk_%o5+HOhG)ciVdW#lPcp5oNWb9BHPJ7`0;w4(U<8e!xyy??B;pj`p& z-RO#dy6L{-S^VWj$ zXO?xQoie3;W1Kb$>Y_T?LTkmz$!y2=(0Z{?1|E$OmrE4IOG(=1SenzpitF3<0H^sj ziDAp4MGW%S;%J>7o(uJRM=E;Ly}s4X zY#;AikaW8$!9Q`9fptF`aMJO-XZ=U+atSe9 z?b`_b3<>xB)s8;{xmGxe{}Nqx4|m;|51jL{~8&3_xb+#^ZT;_|GsPEe%l4t+4|((R`FQ`;@_oECE>qgOXgOX;R< z@jbg{pLx;U>^OX8r~5O>KcniR8G{d1J!OgDes+fvk0(R6Nq-Q&ZpHgiXy%ll~@7mH$JWn*M1xJ@afTHcjEDA%EOCgR6Xk6TK&{Wbl#Yl4aO4A{qIkC1lKX zM}tm`v$S6@A0O>6VWVeV$#6Bup{(g3BWFjw>d9>~(xEJiS4&Mo`H>&(LVIDJLhU3k zBRW~qDI@fiW|JH=+0W|#QYtmfpc6{P$A!xxFG%@;lVGPT2RkKxymVNjD5|B$OMh6h z<+^LlRDRGzJfBBOrR*91)!rz%0~V(tp{MB6q1QbtXOmz6Z;p=C{5f5e_kjg6vNRRn zZ9NL(kCp9wZf_c)PNskC4+M1;ga(2sQBc2GqBbN<)TF5?5@8;GvXdGdbq67~$(DKHwwtnxbRW$<=pWNEU1 z97?!!XhGvCl>D>0(~h$G8T^d*0bi8L06_ld{;F5OZ8W_CDJ$$#x6+sK&3 z5nEgB%X(7_5vS zS46H)7CBlHE_Kc~?<`UH8O2eAIPmX6#Ff}Sn8cl_#Cs5?^*b=#YRMv!o`X$W<(bN1 z*$bA`^v*Sx_t!;l?OQb=t$&Le7|AEaw@2)34M^-`3}x069thHN+3^#gH7vspCwbSx zB&{R)=u0eBWmnI(R?Ij))<2tRI|MV8f}Tu}OSGu2NphJjITM+`VqMrIn~7H}kfJ$$ zod3@}sJ$WhgaSK!%)dRe;0I$?NIvzQqn|uIxbsQ)> zuJURg@QKQER9+#^w!`mDg0by*ieG@W1N$?4gY;1Ak`!0?QGb+tw!S|<-q>5|)#4YD zLQ-5A$-IacsMWIi@q!d0C#D^J8=j3~yX8lJIj(h^Fy`1`_8&2FcG2P^Z{X7*eE~1-7hwRzG%$MIrhBZNYiWrn#ZMS9Pl!wN4*2 z_zfvef6;|&IDcA-w(H{m<>Y&&YkW3;|k{V1HUBg$IrL*R@M$*FU#iruCy`b^#>?7tr$2fvZdYb?vgH z>z~^$AI1A<`9(e@OMa=^uQT!VUb!DB=!+Vzue&v}iEWo$z1Dlqk!6x~*l$IRh99dM z!@$z#Uw_vK4dI;vf86UI#k{Hdo`U*jM+dVL+PT?c@I{IR=c5kYx8~E23&!I+oRvUj zNf&78>LJlVZ3ekQN98r92LJh z7!bKtjYkRnsSEvwOl5S(lWNWwjE!wqe&3B=PJdS`E!6i$4^KsGd(e*YdBO)kuiAk( z|MrVM-pu?CZ&rUVZ&v;d-b@1COiJ;_0lc~9@ABrQ&VPhAv;Qt{+`yaRz#A=Ic$yny zRc;K3XdL@R=Wd}Vg3onZ={7YoPk2YJz~e~dihtIAX`bZ*&z=F@d)iIOxSwnDcX$ex zNPksQrjxp<{DSedL~!1Mw(aWKXx@3dB9^}fV?;xkIf9_mJ>lDxGBzoMrG&O-VpsNc z;kl>R9VHTx*XrK^uH#u~BCoe)Gu$EY2=IUu%}8>$UYq2`>=m5ibn)v8&pdl^)yomF zF|ja_`|{1(PUvn#8*3{7_Bvn~>DDu2}U z%%*1locnx7G)eTDADbb8=YLOIj4XO8r^xr5Y%&?;KbmHW`Jo>V|M~FS%3NbDM}9us zD7nYs8R2>H#e-pFEo8~UYJzY6<~lRHy9|6wP7fGAC=|9n4;D{r4wYMsbnMk9uif>> zgo|DW9@xX^p(y&T`+}9yjy3 z(p4pZsW?(H#d*_6tnF?iU|4k4e&z>KMVvGIKpY`G0~7-s!!YsZQhy#Z#Lb4E!`&Z9 zEN(DP?^nlvd`w5{Ph1rp#OUa0C*AD%iap^w7{I*dWtp0w-syJ06*)5&Ff5TKm+hNT zA_7(hC^Hh{y4vCf+YreHa&oitiW!3upF%n=!)H)N7*PUs@&g9oz%>~sLAJOOpp+)Y zp5@NG3UHj#5NZ63EPwGQ_|^bCD~8q`NhsTuT%-&&#!S0%1%F0Ncn~#)qw_)xUjr+7 z*zq)uMmeD3IHMQGCIQEXGDjN6$3ysh(kTga$W*}87M&EjlOV2k<<1_1%nW_F&Wi`g zofrudFh+cr^;qNzgGpw_3vvFU>ryzM+?&SvH5v4kd@zOGgz5~WB+yuM}JFd^xr8I zw&h7d(1?vZS`hrV=4;W4cu*jx*912@({V*e(MAXT)||L7YJKLe2ZcLQQS0r>ptv*o zTnKFkj8acV5_t`Ml;{&Sqirhmt)D$8X0yxLnbs<8ZFQ|ErZW{mt*0@%J-n-j(ZQyZ z1s%LiV1GnLScZQiCT2+3sO`!>#>h;^%kA@v`atUzqTuj>|@Ite$Zb2$H z5|uDZ60Iw$&s4^C%)6TV-8{b`QEIv0H+C3~%zyA~JduP1(H&IJp2LlZ=?H>`=*06ehC~6K>bK|NIbR2q&Z?h0 zi%6?|m~+tsr3cm7l`ne?0QGDSW>>c>&v$x%Nb`Q~D~8`4J#){zzu@XKJq!Q+%*V^# zKY#NH(AV8l%xIonInhI_5TCXGFy_#%6H8lJ`M2uPWVKIQ4&~x?))P7JUdJ~H-Ch&ND6!Nq4ecmad|6}rKzkd`66aU$qh$W zf=Awgm`v#G%k5%U9_m5Pl&aYWX9L_wE+x)k+Idxz-^R2IBOcK+4DjtCF3&yh#JDo; zT2iZED0jGnLOJ3}m;6(%cHYb8cmE=N{?#Rx?{zT;;D*tdsW%GV+%-L})qlt} z{N320ofmsH7h{A`mX+kjwLwXLZVNmu>q*B5L%11#2X09}xOaDG`#>|4A>pf2_;YM9 z&iz1nDHqEO=<(E)x#xX(^3L?V{D57t_lQ;6e!gb4*8X*%&N|nfe(q48mj%i~pmDl! zA1h`$607hDMkomGE(>_z*_rM%6@PdlC4KkwCGRR1+{Lp-xQlo|$~LBTVxS=eJ!evY zku7#S&$AVA8P8mSTETci1pGfqK_Keh-jdYb-s=4s&_77{At&-;O|xwlM$B35%aDpC zT3;3@4FSZ>sF4vOAGR^7TF7{w8_!K;fb>sN-$hStUx5+MnNxnB)`>cak46L+QRc^_o{ zFu<>b&$glId`_4BKhSfo8*7_(L2aAW+JxTPHt)X?>WF7kGJ2?Hvp=ZD)!wA$fgQ}! z8QF{&8%oV@ZX+$bT#`jLm=~+rUPorvNdJ+{4icrAoLl7r3Hc$b&VL=)YIqsvW5GX- z4^>ZO;_u;cDjg2E+;uaJ4E?I%@pCsSug=FDTh(Q(gw0_@8I~;Do6gEg1LcZ=+7)LU zYk#@Rn99A@n{n)s4CM*%eH?mM%P z0sj91A+vRdYz0rx1ejn1`7|z=WA_l|T#J$duD8b-QdGOT?|-~3z1N<<C^2Op zO~+kEKYByp&nwpp)53?A8QHwRS2=?dj?BB;EMo>9)ApeLK^WHh(hrd~xW5LdKCoB~#a!y*GOxyZM_8i{nZk z{QstPr=V+{6n~up^k*gMC<32{g>PENTmX69MUV#phcE_E#P4#D&4XcbQKZ%#Hl`o@zt zLtMgPz<$FziECZ58MK-Q^v-Rac<<`Yqp`eeb_<3GUVp9Xu7RA+Ne-x^ks?=Fl#c$vN$PSltfh>RN9~HOGv7~N&Yy+r6F3tG z8m4h0s2d&P(rq1}j&%A|&so=Ln6=smBcx2i#zB-c z!e^d=kj?j{&zONdAO$6o69SJ#JZ@(p@UMQ-)=X{(UXJc0@_K%H4v~$zt0Ut_3}n{g z(SOI?ieCR0r{2e1`MO|igBI1BCy|K>qU**6cCeBJuzikq1!LR?_O51Rp>H-u6#iMvC}-ieV3 zjRHm}Ojs(G;}L7 zq@s@Cbz=x;Bf-9xIrWUsMm4I-1E7yO+d*1{SOnvjW2}-d+D&R?7mRg;R>Vj0k^$*F zzc^>Rk@d~k>gu4EKs)&&Xcuqlx>a4eP%X*9PmmsGcmW15dg^t581h-B>u#u9Qxp-sZ1%{_-IF&OCw;2=vB>9AxycP{x_@y^tbd!_9lL1GvNi)F@`fLBq{ma_M}7b~QYLMee*3Ly zS*>tIq>;6mmm~+>KHT^Gx2B)&9I5;Evdg>7hHo#s3GlB59_cHSg_S1xZ4*WeHOOxp z4+yyt@YoHu6dfKZdvd9>`Kw>v&W9H#xnCXty)J>y!;}D-bs3PWaD?%5bpUqYY5ZTHH4c$ zS7s;;F^c*6-1{8IlYgX=%4_uRY3m3k3L11Po0a6Qe^8hdneODK+r}0ixjnwcP~wAf zbgzJG*$>dIg7XO0y~Q?K(c4jPf~M5HAU|yQt^6=`T!kJjKSkyui+qk|V&~`8%iPRYfJJ^Tk?Wg;=IsQClSK7RpY)7;MU+ zc{;g~kUSzss-KZXzRWQ@=Q%lOoELw_%tdgWEJJDOULhIe4a6vKq@uW89P}yj>S#gf6$LO6MSbzVzzYb#EZygKf%!`XAK1@gc z0oo;~oDJ?F+hqekFa8^IhVpI)kvH0j{Gd%eAE88o^Wsfo1XdUAH zLDCldAn9oS063qaZ0ML<;cSgm_>MQp79F&;%J6a z-AnDXj)$VL zgGnyB9sb)|hKIZW+t#sNdJ}A@Mv3z_ipJjT)PHIJ$kvgelys1=Gb6QrrN&X#!8p4B z`@}s5gq-8bB_woH&hv86q)8~|WdZxE>n6zr(rE-KJqVg;LbN5PKd&YLueQrZXo1Jg zHl?9QYk>!B+RnxPE$}q70NBIVb5{++7BCD1-|tN8NQnT2z!N+0BzHupl-ZOgdbUd^ zpns?FqDCLi4qZC=5yjzVwIHwZ)8hB|5fnjF2n9VP0HdGRWc z!wm*QI)B_{=@zmnQ+rlOxGS|H$=O7SD^1Vw+LRyn zXnJLDvxzPD+u8D2HNK2QfqAvhoZv0se-!HL%o34G>oDtZ0sObYC~r=zBJ`)|IA z{eZ-^XHh6$tKKK0Pqoql^DBK^nA@G6gDquvr2`-QjaX@KmU{8-b$#j@W%*cl;bG6K9pdaE| zUNpyXkKdDOw>2^7g&S~$ynpTWanbawLJ4@ChNKR3_t_ZcEAW0#o;2wHU441dxE+`$ zEklh6FD_1Js2>v20j@7~X))pl^~;;4#zKRB{&JTKAidSK$4JQ+x1T%z3rdOUrx=T7 z9p;5#m-WszN&x*AT?m?e(6<-E zrbu1--dPr$fwY0Xd)Pq98+V^OzX3iCBt1VsJXxo7s{Fb@e(g}lf-VDV2HDR%Rp>8a zT0AQ*>hk9?SBj&@I<(#SxXPG&>YY$}Z+(Wsfjq#keDa$NWo#Gq4vKhdN?1sZSaL@$ z%1udEli+C8_W0vz0e@9{l-ZOU->~{^Dfmqte{R^Mq`>>)iQ$@abHENg5wRyO#KMFB=n_IW6Tj zuddFRkVtO*EEw5sFuGN$+Gm`)W;0e>v%##)yq}T!+Fnn7U+ z`*mpJ-Wk{)%F51xbxS}RyzZgVss1ZfnrzCMPFnDj=oGk*+QFOFTG7esJC&WpGq6sH zfJD28Ld{wk;Ah9c2G_3AnxE(XM~rIut-{3&chO`hTRPLQ$o&q*kU2c^j8s%Jt>$&9 z(Eqima26k43V&Q^H?0OeI0_{1T#qG+c@A>?xhd_q6k{+er+aiSlL8W@1*9Rj&d)Ro zhj$K6^>(Z)8mAyt5A}E(PV~-Mj!$V9p_7CKj*{d#LMGmM?z|4<>@&FTx%S-owa_lh z;QrtrpF4j)eBb<|bLYR%UrN_Vy}E`2T@#i2>zYRJ8Gmic+#XHWpw5!?xCWyK=^cK` z#%4=qHD3fDp3R>P5zlrhoAKeQT+j!dIKw{dl#aP-mP=ZGx^2S1NVb2d+Ag_Khu_H@ zsWw{GgC0YM-=4b8?Zh<>n^M`sNr*?MtY^HRpOwe7=Znf z_{I{JvC+E`#w7cV+QjZdWFksKAUolZ0wC?Yf81{4RYCO%D0>*9)IxjlJvgANzQ?_1yi-JlZhwXx+g*T zNs$vV3U-&=3KG%0UA7ul)jBQ_h8+WmAa!M!UmL^Bl7PvpkLWTe=Y+pNu`6 z6n_AozY>yl!@2Xn1G&2wevg6QP2UpIb-UIce`u!lCU&FW^wN#9 zxWp>Z23&$StoD&2)EYcmX^u(tntsTuH$kr`X8abL@^RO7DcfXXRZ4c%^;}$`-2lEo zF7%vb@u3Z+AyY%&tUpHwM5os5k>;o^TYr;_EqhIzc!t)=5mSTBJtEcPT|k$mduT&b z$n=tCmAF)!!XL+s2N}xMaqg+tKr@d$b)|m-(=-boMT_SOzqS()^A6pcYg71cQe=9i zKUS0C6Z%;TrEx#->e;SIz5UtCCZ}XzY5X;4$04Ua36b7$Awx07(-djiW>}obLpC7e7 zj+_(f@Z8!4;fE3Z;~5EuwcKw_aDSG1)~D;aIxFb<;q~*G4s`vOom14-9AA%_-@K2f zOOZNU!Kd}Z>jB%Cw`OobNHT)V<0w|n_Nq~ICKgn(Jit6JP8rugijg-L`yyjI2^%3^fe1_UuP=DVh1>Emw z!|*!NfY^Y<#IjN?h_Hrq;5dJfCvJ7Tm3?sZ~d=@?0J)F`IIrE4?C%e8p(q_5L9&gY}(5vt2Nb@~@!&;)w<111;vU zvBq6w>{XE`lP)m%P9;4-%zwT4VT^(%HUaOnOsiM(x8;)21pHg`R-7j+=Xsf0whO`2 zn}XM}KY+jb0(e!p>Ksa(ACITSX`C1iM{oC6r+BullN7$EYQ0tdTl;A}8=j9Y+#StG z46;mNs0q3|(pgGvN=FCcWl2zr`6jdoG`#2C(>S>q8h%i4Tuvm#Oc)CUdFx@Gb5MECbNh zs7v~%P9<}j2Zak6+XjYRZ^7 zXLfG*%j#E9rrwBQZhxtjuZ#!TGxc6Cf2AgOr%dQ}q2t8$?H|O*v?c6u@TWGyoA$PH zDAyRP3}NPReCL^%C#01R30+Xh0+r$SI&nPex(>U7IpV^w^O_&>Yp_xFNS!ALI8eU1dB84-^U+K;cTIMHT`8vVwUR8?bcM81rr&*v`vijepZ zwLRN7H$BIH8GpNQcDk=G)P{^NV_z^5zRm*{txaj_sR^}*jH=Fdc5rM(bejJMshXzB zxFcbCbX3hwX^MYJN`hCa5Ax_ z`_mAvU>lx7>BY5OO%Csj8&M8_@O7)J=BSnfS1o^&T7RAp-4j^eoS@tgwfxdJmnyGs z3ZRG5!?8YJ!m0>8>N+`G8Q^MaPhZAOt1_|2+`Eh0#k5_sR;9G3`x_9IFA1pw9v*}5 ziHp=6g_3>ty*}J~|X;g zm%#^ZM}Pa@^iu)#eHAlh=dqba$(B)Hj0HoAcoaX8w2G-juOhihF@gt7l%EMvfD z%U#RX!JX#)}@j zhZ+z*4<0=}gWrUAiOUfm*Rr4O<;NZi^F?1Q|IuD7UEOV9)MbRSg@_d)h5u){hOvu1 zw;X-Z^g4lm6-G$NU{o5x>KLvU8kuKR_J6J=aTB2tI(GO;k5n7*0LKsQ<+tjKhqOKa zE$<@vc+!uIHGXTdc~+77W8v9sUi^!n9SWPi<=?g`rQOw`gE6vI7uBNuq;qW@jOnO0 zf96>Q{lELe*noV@v39y${(4$c(~=zHS3%jSEg@dYWWxZf+5pCrz%}RK-cvElmVeS! zmouEZp3QK!#Jl%xc9{J!HsAp+s-D~{#GOakgHzIC?Z@ptXWI;=(=k<8dFk za0|wJrru={F5x%87;F|-<*lr`MSm~-B(N~M7%{Ee16*~j)NRdQg)1^s0q@tk_6U<( z>DZ2lZtUd|*DAbI^ZHd$ZO!&*%sifYw##~>;Uq>}B!%;x{uxUy(ula~1u1W( zL3%G|%t}(P+tCDX@BGjv`&dPlkZ#T_&sD140MFA#oJjx!<-+<#+sg*}R= zE>A&A9E=U1AcgKvR{*E7+*Jo-W{?!F-#Ha^$I4o(a;P(L87Z8=K5UPFEuAM}CyW<3 zR^W>CO{ok4Cg5lGuFc6C2r=ayRi)Gst>W{gmsp5mgeC49KlUA5%1 z728GXqtHwAS%FYv$Q2-kwSPixgs=H^6eZ@d=%;F)fJAFXB1bnr7qE1@tB5Dw`i#UC zx&mvQI=Su6g$|63xET2IS!<&-D+m3mWDII28$x-3?b3pr{8j#;3xMx7#nweUKZb{Rr#`ALVteL3%W3IYb|F=Wn<%0Ba$M=zutU~gx~!OjDM@%3PobN36BYb z+UDdAj?^WWcuyMnqXUw3+E32b{&hLn3kbD(=EC7`i#*dMX>RpQ?aut+Z;Hgtt8wA6 zcWwmR;JSXX8o&Zj`_8`wABT3|#9EBmN2Ob^7rqnIy>9lrlYewH4?OZXNCGJy6#g*j zYW^^0Z(ibiCpoCuH~gJsc5`PHAN>%nIs>4s3f_qsUVjHHM~ACp#ft%Ff|AV0sJ$79 z5&9*$@a*!AsjX5_wD^_ZY<&5AB%j|uh&)Ioxwr<|i!Ie_yMKn9GR&BEMP zgxFcNFLB|%_F_Ohsf1PE5e-klzi#k~YzbSQt@ zhPV))nhT&!RiS;+m4-HDFA47hSlblRyWeC~Kbg{jhhDvQZB*qFxtO@ z<0hBzQGX(7zZO#7TmDU^1$zOXwS8GRbBVa_oiX`fX{7J-tGEz=vG$F z&}MMR@3rDk`D%fVKnLEjYWbSuMI=E8oTRDQ#F5U(-X#T);mMKDd{Z zta5}%5k`y8Q*>l7qot(iN)I`GZEy^5>pwe)GJkyG!iDaI3&#{JT<9ISaN%^gE`jUI z;d&BWU;H;6J|*y(0-tHa07h=q4gZHmhr|CN(LDG+Fq#Yh9nm51KO>q0|1Hr$@ZS_2 z3jew20QgU%m%)FGg=SN>fbZnG@v1Lhd}W8}xfRwAiCdRPiooKFdqOz=42c)rh!o&n z@_+Y*bLZz>d+z*QbIzSVf8DwB3Vd8k&z;YMdsE>v6h4>1#{{1#*J8|?warF0xHne} zFGWJegu`G{xxJyIS*i@VB^o7?H>3;H3ulkusdUbJrhWV{34A-E*ppatU574}Q3dnG zfIko;;WxT8Il*kw^=wg+yFG&i*_IH>%75r#`sjG+j?hGAXX67KgyfN0fp43LrAD|z zMeKBY5hKxwY^0PKBCh;sw#%xN#7yjXj5z)n;~b?S?xGAi#P!D*AqT{fqDO+h;&FyO zqFb86B+07$HQppqZ<9z}8jg_X>1+2<~J$<`}tV(Ckq9i}UH3GCv zjJSMB?rL1kN%!w*d+L%N(tp2^RcQn3`*Xnc6K(d`ZB?$=qv~$3e+``5^;tvO{H&MJ-&mFAp2q>Qw13MpthT}s2}lO8plOp$c{YZ74n0uHs=VAopTcvo z-asB$kH3ILu+b2kygkB-drUG$*9d=a10$(G%DyX56iw88Lm#28hrnm8-mle8ZQG>W z`-VtQ3A#uD;5a-M~Ycwku)gehF>!xk4Xq=tx(cBxgXp?(h9&?gIh0chffCX z*0^O0z|CNz#bp5ZI)H1r0PcK%YXi9TyV6kYk)iihg|?%hfzpq)lYEg$ z?RxNSvhS+ikJz~G!)yuEMcjYccR8f2yUL|3krZc#H$mOC@UgOmsrs!fTNK1PadLEE zDEq!Wp+yqD<+`g9-lEd{?|DlHZ;_~j)k>E8ba&A_3zWCq6_ltnThfV`$+S*fBW;4u zK=r-#@ZLZ+RP>9rV)g$1@0F|X!GB5kp7(h5JuN?0Gf2BxGJp(z)Kh;YX+3;J;K`8Z zZ%QxtYZCfv9%fN)NO{#3}4XtjMDJj`%(TbkrDN#1*4S*;P@OY*M6 zV2`vWx#ri^`MzJND-;7GCzCvB2vO;}iUASgE*Igtx>V{2nNt0|M#8LUSy4YD?w6uu zq$7$^>9JG|X#WdKy{>=mS$ZgV17j6L*%krpxEEBP_}LV=8|h{hiz1-CIZ{ZY ztYU5?+htJ>bW!FF@Kx0Te^qK+8%HOkx#g0?kOlZML%Kec&GazxeAA|v@QDui;=(aF zsvGuZj4a+DW?g^8lPr}d7UljPzXbi(^|lOyG|mjB$(C!7mpxsurg0Cl)2zeVLz(tMR=X zBi!&XjAsP-a(A~?Io)9p=}RzL=1VFE-|7U<8@_Mrp0s}#cLCu((nGk@pwQB9{?@9F zITmG67YRT5e+aprXg0@2z;~>lj7`Tdm=Q6&gjfLl1{eE-WKkw`dGEv7!RmlTDd_To z6y|kdH2$fK6u}7HjkCzc)UJm2Lb$F)@-p+uW{YwUo}Y4&d~Pe*qODA1x=0?_C*6Ik zmKNn~XBmGxG!thi2dVc=a8KzpMYTLwt9`()4xB~hdsjuwDO$QaN%-^633)9_$k4gx z&Zo1AX3ioBpB~n)pAnz3`s>QyUT#%?vtZjkZcMi#uS_if$OMq8T{1+iBKSz6BJF|vy zd|Q7^nUVKY{cRm9n++2kbF%Do|DqOc$F&?*T?Pn zivmlhFVMvD#uD>?Kx&A!k8K84LN)5=oMheP3WSkWjCpd7Iy5#GkL#G za+L(={W!iE;M9bG_lDaT&c$1m6Y4$U`C5O?uTpp`zgHhEyp=S-_z_QMWAv!m7=e58 z-JcPn)j9lvI+LARoqz45g`U^@*ZE9*9kdSCQFlSTPhC(iaTneSKr8gCWyo4 z@8GaaCZ7@QoM6g=y)#Z-Sl*Kwx!&8?|LL;0hiy(S0_*oSbw7RoXN%Nli_v3E?X`c$ z{nS>!CZ#TM-j@XI|81ST8+Sl*2^+yH;&QX{q$e}F%*CpfIrirPKI!+UBubczusj#6 zb>*Q>Y(G)lzLHB65WLo4)OF%%*Z8N}du392F4$<`z1*ED??|08L=e0QQS6-X+-2RJQ(-_$NfgJ*6d&1m!v(yykFdHBEC~tuM=n6a_ zj5uLQcue}JSE}4KnHgb}c|b^>Y!V7iOlH@j?XYV)cv|VbKNh8|+p6MV_2PeQ)O6;E z;`p&=ml*I@Tp5|*zdTiLbhott%5eqJ$*fd5wiosO(l});G449zg0YA^EKU(mBnwhw z(P8*CMLGfghXv?AksJ+U(P8*s3FF3W94%!|r7tSG)HqF5(v%RN@)9y(?AN>HcGXwN z)b;ljGWDvj0QES~TfkZnwi|!Ec!Z8#0A_r&C==tAOy_>DorKGPx9`k4cRm}wH~ugc zce~ldhWR%zJk36YY5B-?P0(ZHJ0*=yu7qpL1}Uga<~fW}JpZlnp{dKwY9!r@6C_=I zIpel~M9GyQyZ>J4a;e6bF^fDlgJHSN7}=-5)T`;$*}htfl8n9f3CMrQNkaZ>=DG8Y zpzFI&z;Bj56E#$AePgQi1$jJB?a6FF589Q<3~Y2@6x%H9Q9abA@Hp^Lhe7K<0=Bosw9FqxPD3De!iEEF{fl%E}GG8{sm(S@Z&@t;&~i18V_( z-vIP{Iummw>KNzY+RPdkNpQcRSMrTrn$!jH4DNA4o&@@r{xBV5b}gIkx3m7U|HK8h zX_>z6gBT?rhkl<3{zPgUNfDRqm>Qvg>FS8gIlyD4B}`vOAE$o_hu(3O@XfzlENm$I zx>Z+4qok0y%5yMk{N>D&Rg4~EoMY5m5P4`99ql;@p0i0ftvAn8be1A!h;l$xbKEhR zPIpGoUi>C?8n=NLC&B|XfXS!;=;?-B-{$+HjGVy+Q^Lp?8XZnB5JmS&re57K8kw5$nh z530GigD`Gwh!M~KW$)eNo2s&g;k}cSAcxltL^rRvLRQj%U zPFg^4X5RPxe!uUJ?`wZa_Bm%?)?Rzv_da`{45`aFnd+2Uh6SJef{^{iIIpdNQJEbu zN{@d=zy<*PB_*h{Sho9m&m}cTlcN1)j%?UXhFRIjg$=uJfI6O@a<=Do_-%x`(AF}^ z@3R`ElWlJ=7kJ{Wx;t~=P; z=Ctaij4lszmZh%cV-~Ke80Rxe@C{dC76Xho@D3bjD=Ud}LEwl;VTB{G!lmnbw@xSS zk7qP+=f79Cg^$@mw!}|8e@5$HanW0HO8<4>0S_yi#fByDx2}DlNNNs&<kR!QhNJ%29iFXQjpxpBccyhIq z>80zsu)ovVct1_7pf6N>hyT`the?7w$j}b>qyrB3IhB3MlR^92$|f>f!uNQk4Y0@| z^!?lZya1tl!!;sQ4|Km1`uGRo4Um8M*`iUZ#9fMMksH1()GaNbh0?s^!haTn(@Syi z4E5kICEk&RvHco&@V+KOCd1fTWM3q~f%1%oWw24YHL+8OUP^+z?2uwZ@fYQr)`pth z8By{^cah)_%s27@o17#j=?TyjmhmiKpMoJ6@Z+H=>@uH$s0@Tr895 zrGn!QkP(KP0Nzfcl-q_ngo`=pck^+!0&UE~d-q0g&Sh^T{m#nW?f*bu1NQ+LSk`-% zAP1xTWv2!py0sHWys1;oQp?h&;o9s+0P?>@NV&lN7Ez@W8+xl%JBa`20&$+e$ZCU> z*+~;CT=7)o%H4XYqZ8kkHb{SE;MXn%p1TLyJo@*Zp4+cRykXmxc;--C!H#>O6lKm` z0KTg)8D!vh$E|l6q))ptcD%R%Q=fHN@4~YL5lfEU@|?$ANsK-`A<(K0IkJ`BCrqTE{9AqqkOQ_ptbdWFjZO5Tj!%I~1v`h+)&y~i8|>Fs|mM}qS|f-%{A zfRK0c&h`lKd*g2uo&Mhqn$^{8YndVD@ykmcSWZnLVK6L`)eY$$$ z!_|)s;N_Vv!M!&HJ}H08VxLUCoGE=tKUJ)dy_n$!Or9SX{@*P1LsbGMD}e}UPSh}NR2T@|-llNj3NH^%vmJLEUg zD0+P&Mvp23*D`-E!}q%DTqh6l2d>44bFww?2KXdzFd|;d3WVc3tiVkpJG4w2O9x&4 zVT3EvuKN&b{}8;4597SA!0k@V_qg48!WdR3=q2vBDB#;n$cg3-Vgt$hI(1_WznA6j z^n}DJaxbi)?lO0*qH-?C-?=ziuLiU=NMAIT&a1^d;fa4hJ=iUIi8(6cfqFJO&JCRq zC;=!-m|6s%0_1ExgR;(!9huPL7g1#e5h1U-wd--+^4-$b z`@O7Hrk{T|(%gE-jzTDlD|A4ANLd}oe|7EVJ})IXp;KOql3*&xAPan62@~>_9sH*b zLXLwRZ~BZ7(x{5-4MZN3lLp)g6 z_&(WiRtDCH74F3kaR-Jgo~iwZ@YRC$T^#*_=y`vmKeKo2-*I2Qqmw7SX{Bu*-v@uvna+gx^C?^!`ZCS~K8KNd*AL;taR(s}mw{E2L2x$X1&?C;V;+Cp z3irMawL~-)uj|V&xA8FhbTGcB{EG2i`HkahPvc;G5B^>GJ@^^zZe!n@@YCgaj}U+6 zTXK7?0%q@*BdQ%%H}nm$dDAfBCkSh)z2u;Wvzt{RX{H zC0e15laX6X28G74hlFnhGU|tr{a=504d-+7&Fx>c8u~m#V}cw18EHGUQUXI^1ZdrK_)u9sJCv|)mq!!t;mpuW|JbgNrR#s_GZnj4^20q5Abnn`Xxp>cTkgg%b> zxcwZ*V4GYlgWwx#`y-mQxaJZhu?OSlIG2$g()uScr@$enSiFH^wh|=GjF_Fyc63P!-w8?Hb&0HYg7jPCR8_^c&v@%Z9a3(1=t(yS|zEy-i; zudq4s!sLc+ki&W>$oN?cOch4op5+QP^2^~f)+Cij2p3*FZ?oAG~=)P=j0Yqzz4tZ9Lf zYl)}(kjhM8M?C&9A(!Qx?fK>-LiQG%?HMD~TtKr)37VbSN3(JbKwsx*mzSRJ`roJB zyCdglSFBL4qZ^ULWz1LV5d43EF-!$=M%5>0D99NLlnj7$MVnw<5N(k6B4j-oHTlG+Z~eNYTzq2p zTjyjYFYWDm=i9n{gydauwrACcgp9ac@im@npwCpZJIlzhJEvC_qs_cX-Y@ksz=G!4 zbRSob>wowP?m5+(abuMB^p>4k#~_aK@8{Yi>h45oFp zZB`9(w*zeQG9ND;I<95c;G7w)D)z!NCA#ErPYU2zz3$>e#QM%Wlg}i67`OZIo>tVx zGH76)Rd`>(^~fgwko7BEsn7q?qHYGQnG`G3(;64}j8oYNz?360THsjYj=#owCiiQ( z1?=a-d%u4O7-NMRl*iixSI9B{6+k`PT`32yknL+BPyp034E&y9iId0lQgQn*u>kny z3N})LJ5Y{oayaLZ5!# z+y4EOQ-`ESj+5Xa7_;L*@2lXmc`qTKja2+w19*SdoL~jdny(;hWhOdLJIJrH-f#%e*)hwBzHb2|3mGRGmmbneI46k|i zu>gPn8?|T$d#nIjwO4Eh?WaE=ugXcb!w7uedZR3p3Q#7=D>JNN6 zECggc&-t{mLb5-i1&{4sVVCPFMx-5{df|U?gxK)C(N(U@V484!NnUsWc%_}8q6K@H z<1Rf&r-r-m?8r9+708xM&(sBJ6@NO9(|rj}*VXz;3PPZlC?CdkB1ZWQ{y-7Ppjjms%b=nXltI-c zD7`>qc41q@zW9WD3*FcfQE^ua&jcp0K@~5#2KAL42xZft><$+PlJ6y#KM3%5Ie<4@ z6?iI=#xKX^X7JLKT}sTlU*DW27ju6C_c%IUyo-yCgVd}p>s`cVn}04UjPVroU#*LA zCfvP%mqHzLD{v1t;MlGg1?y#CQFSSC?VCTq*m2LP{XH1<<)!)WUN{c`_LRH|NiPja ztSsWCnHS~BNaRWHdi6hCsl-d#&ffa+67?x(*(x>0kK?|CSZ6n+GKsM5P(**j@nAFl zGRB@M$Jlx4){g&^7(4J&$5*X#9KDE_zS$}76bxKu>CjGX>ZHbpi;oHKyY)gNr1>$_ zjX3N08zGu$c%ltI*5D4olSW~mdk_3pmL7m-p$N@x6i9SFX~vyHh1%JA!BXn^GcR#n z3YHt7oxK7XiL=Ia75J8r_Y!{*VvN1_Au=8T-e~U(;s5QrO|UOIUaR;| z`SqXRT>$?_aowiEGkSUcy>0={zk^kMNgU&NUj4ojD>nQG`IRvV?J$48PvpI*9Y8B* z+Eb@$V!VlC^$Q*@Ue{)_z=)dl!qbq#J%w%V!hlAuPj_BatZp98onSjJ&Ql^|c>U=f zgvG>CrhFYzuV#Yv$_J>H3KZ~tNZq)n-w=T z8ia)mY1&wR~va%iZPPL~_7|s45(84V~&zu?)gFW}j>_U6`ygg*$ZWO!(^>*LTD5tZeFwS?oz=y-ql4R@E&<|d;f|AK~_ zFQDOF?FU;+0qR%6r6prSCVEHn~5SwFeV4g$XLsnTuqL=LW z-tCyW1#^Fmt}8%;%*_Z8so!ak01@O1T$}Vv1IK13<|Zb4O-@<*CJ4>y*-3+W>tL!!x%HJI0t`v1bBtx)Zq@*3B@N5&fL>I zkIp#p$bH4#&XL!gBn5Rp(gBU#$)>-Zti5`Np8lAsYKf3?P4tBUsvk|H5~D_yrsm?4 zORkt=Xzb=RFaM~yBC1#aID{<9glCTIDw5+C$Oy2n)qD`je6M~cBbdijn^dc*jbwv& z7Nw5dkiCCQy9M`9%Bp~VJVyl6TY6!CL|@7~bgNY{3vKDt8MQu>&(18*?e9!7CO>=f z)Rvzt{$;MzP@RlFOW&FfHKfuK7}?pOVC11z1-phz&Hq)%@losTtzgUUCM4rsLcX+v z4ZD+&zl=cRpZBzVm(Lay0C$XmH* zdme}1*8wh4fpf{cG*QIx5P!*KDq9u!EN9xC0rON1L;vNcc8=KtD0lg(WEk!Og%-z|b{$AxoMGgp zrl_(fPiXMjo|obCarW7sDEtcBmG>dvZ}6~(d-u-8-Iy$YEGt@#C6^z6@Y=_U^Mp47 zxKL`ruwW`DL%FG) z*h@l`+1-a*$>@GfoS&SibT<4zZZm{iB0S}%XhY*!n)v&&Ir2FEM!fx6JpbvjVk)`; zhPh>V3?aHFit&W3$gOhEZaR+M-+&g3E4f2=Gh(yi9%J|M(t)U)TIhn@OWPZ^-H3l@ z4E*NCvWJVSitiM!X1Q{7^3L`tWyJ|fa{?vX-B$tZD4h`g%62XEZSjdETX-o;?p+to z$^E9VY(k<;Zgjj1N9yq_%O)l6Wk#G8;~+f@=%N^| z_rSFUe&4a3?OFaMAupxFbNFOso$Xl%_svlDr@s*L4dgTRKihK?+)IPEda<_kWhhjISJM_{@S!YlI-xK7E(;Yf#+S~lWBwi?{cSi`IqUBcE*oe5^M289V`1Q>nTWuHSi)>3cK0>J9CLu1gVPS zQ6eZ5cs~8DYU`!HaS?_7;!_%vdnwQjCA16m(nD>%^p};$WtUg)77OQS^!C0ymdH68 z#dd$UEgh)9+N1->+5+2!BsOs15ax9aIMU$i*Gvl1n(ACB%~gMiww%yYoexX7b3G+D|lQ&Xm4-ybQKbI3dM?GW-=VMR83Vz2|{S9@6icRtfk)%WH6qAk*@ z?Bcg>DF)!5{cY5#LiR-BUa%_Nm8B#9oLDy_9q)WmUN=Vavcmin^i+SX4_mh33OThH{C@O*qxGzk zR~gLAJQK>Uz!VwrLm2Gh$qLl4Euk7(eSp}w7 z`e3poV8WVuZF@SwdEPv=TI6y4ti2Q3lTVe9mdm9z49ly-Gut&p8wT9K6Hh1Bir$#z zTy1@}J??*@43c21Qfn{NV8>4;BTmU}Dc1b=a{AKHyy|X9^ug8F2Nm?e5>^46&Q5ng zl(9e^89~{flh;{@Zl(84P1Ow;-85dqt$DO~n2;rCo}p{FO=Jzov*WZT3+!$hR95S# z8Y)Y5Qd^V+rva`0dbuwyS?*Juv)`(`??J3Tf$x7#^D>()vIRi|m4H6>`^W3RX3|NY zbyWuHU8V!H(9lF|S#y%|GlGVEE^NDj7NXSt;fQQISy5hTw_%*=Np`usr|%D=oA%h^4fLs$Jj((4|3j@iS0|l51YqUu-<{?Cx*v zJ+tXQg{%1A!bPNE@r&WI|3`53{{>t{`SzerdVc2=9Ur`{z36@-6?^H#$@we6hySWA zRa!y|={V}3BdMJZ15uSpGiW-sP!r`TM+txZiNwhXB9RW#M!q2;IYJJRCK4i_l6_<^ zX(YSIcJdBsAe%`&d4<%Gb;M7e1@-YHSxJ@>4|$YSkq1a6xf=|C+liaZA+yO1q?}ws z%1AMBlHPM%{{P?qZ~c~tm8D3BKORCVbdo8Ak?G_*ay`(;Z9pk^k^9IZQca!!T3UY# zboDxUn`|RHf!^K&$_tZ&5a+oxe7VZC4O zOmCw1(v|d2^cDI#-9+D_`{*b1Ga9B%^dIy~+CueJwDK>l`jymES!!7MM3uKv1u3u# zL7N!_{lj#jN=`ko((6%D;keq;2p@mtYN}A=#?;)?$vXWb^gbv2Ca#{K-g8&sxDHC` zEa&b#A$Z;At~6sXt#Oz{ywb{7T8Boy(#cmk2d4W<7$9Z9RFXko<%DlqnYdahUqLUD zv*w;w8T7)PqI_SF?*pt!St`+-MMUK})HU1*zfj+Br3U3rQsRz2%OD!Ec+r2Dr4>zC zoOn^`{6C0^Qu&Ee`IV*CEPVR`bIgZp0%?R&Wtak22s9E+<@6&W+_pnRHODz=XS6onMDlWx1#h=-Yo4CHk4D1^Su%Usz9`DGkcz zn=J4>!juHxBTWYJ*XutI#s%lqkGNZKK9o@ZG<<{LNj5m}uk~a@^xuE!$(~cbpDxyu z&qn_fJy{+7rT(UQMu6c-wCwWvaD70@caIDOwm@w2OSr>$@AgCskaL7O+*^xcQGC%s zUk4t{R?@Q{Ed79()tkjC;65{NjEu72-Sgwkq(wdCdlhyV0nKyD6tJXinaZZT$`2P z^MUj-kmkebD0n^&B>Gh#&5LOny_S~K8|Z9$3w6`msX+fgE9nEYiatg?bScRBr)ZCD zmWVx{e6oJaS8Xck+UZkEOQsY}zUs;emqwY3SIIW#X=+f5=RI*NPlzogt1+HrNfniy5*y=YOKO&} z?<(1n2J%$7qI1);dZjd8>uvqz8V$Bo`PXPO%fBX@LH>VDvT5aCvrQ$QgW^JXm8%&i zdlphzPWFuPR`#Z-JMp`)H|6#8rchV+rf(PJT=%(^U+)}I$)U6SR!&{7+`oT@{Ok2j zPdqnTn4EGc&mXv2`K_Lqc%E#zLQaiQ?msw6DPNtJc%Eh%Ca0{*^M^8(-z6D|=L0Nh zaw=K5|3`nLQhtdp@qDmFC8zex_0BDtOXuzZ8o=>Yw-k_^>QoKu*@b1*Icc%vLPAeVh821YLVYpun%}Z$}*(!lf zRJo1Kp*Sbf%WGWb7*)C4Psd4PEDUl?T*o#?Dd~URIT_=FOB*z-pL~)T&I+l0w0?ht z_EV(f-Y!~0?Aj(efv#3Jt7@iYs@CYm0QiEc7L287MEAg=A@@p@kSs%`Ix%0wHB|1_ zN>6vZ|1!cx^R@>)yJ?J?QUp37#cgRm0I+R_Ys3k_M`t2@WS{_f=s4U!;(lboR|336b(2IBHgLyiv zvlVyh(S==-g3>S*AWJZRr>x>Z$cVdZgdDD};X^G3R+DnRp+nn{+ba>kjb zyJ^0znadj%M9x=<;KbQOA+`TVVm&a|U;%6&0zdzomz4b)ybYr|xj&t4;MmeKSx$fC zfUloNgft%!2CjL`mlS)RWcX&B*izZwms#&Tz27k4Ih@Vw_Z*enUcL(VmZ8!eUR*2g z=_>bFRufw?eD0NaJ)QQOfS_D|@4ynkj#Onn=%(RHi3d zSGCTN)Fzs9D_hn|ZAq&=tvjkn&gBzIpf?|QlDkc+TiF5V&v!2pG8Jr&Mslb8{eSmg z_HXZ({ma~Cq@eX`z;yq(dgy=HyvZl*TL#OLp(oqgIv}nZiha8~4@QWl294}pMy+_( znc9@nO0$!pB+Y@6$>Z#kPZ+n5oN^KA>!Z_nIs@?8;Qw|NNoEhy-2|vc z3+X=0_h-mgS+xT44D$RrQzzZpskY}GH2aAp645>^JV5dgTgb|grm26l;k1Vl>r?T& zNP7LCH=c@DRGK$xv!04C@H`b4D#4!Yr1r+{S>A>!Pf3xq(WCxN3-Uq^kzNiKFp^{5 zNTdxx4NLM{0{E_kUL5G}=cAVmTulY-YTT`XN*>SJIB{oaHDM-M$o2O0U{5y9W|CF4 zKR!~tCx3rLKUN<$`>B6Jk>9C4oa@UAjTB#tO(FZ^nT>n4e#95GJ1vb{b#~I7?WHz) zhDa8vCYeZ?UhMV6)0CNg)B&7HQhh|KSzvZNE0X-ycbViM z_k;Xels_cg&wnAzS9s3#gHPNW?U}t5u`#lmuOZfk=*-1L%CCQ>()jJf%KKi5%_kWE z-4^dxZ5FA33?vie|F`Hs_$dE>gYEH}b!e2`5vEqP4^Q~W zlA#_NqOyF-5$ESSrN4Rb9)~C7@yO}BMHq=(tYO4xBKf?dM&B!q);OgXyczycHkwN- zR~)r6#0QmLi5q`v5j$od8BVf=0?m=B1sTEF1)7j%O}578WVGFCs=YzLfH2{&r zepwi?ydv%djquUdDzMBaR%3l&c}b7P%|4^w9@rjJCvOkZ;q@^UUu7lP8lOA{wL~P@ zcLd02+)s;Gk$&_(VueuxtP$ypUGftznD)7;K74B4sP=#3doyt_YC@+pr#jVN0lMXO z==ZBj7P|ftBQsV)&q)!n!#B=NuvGuLuQOtxucax~qEMtGF>Z+kON--GQ6`b@U#>{>?`4TDg|J7x6lM0k^4MpQYW(-wQ^V%k!hBEnw@Z+^9TSnh zmHJZG>V5l&v;F#ohsY=~wZ;HrXl=w<^81Ir_#>fr#)!%keNs!KjC$KuT2H%LHFk=A zt!ja_^NxZnA?A%MTu#ZiJjG9P@ChwU@g?~Y>(?*q=O5^! z)?}cpYj-EfbR<2C*M(QtULmO3D>S7M<6~BL= zihk8d6&8@o`VED4PxpgMi7gPlX>n=|iGE1%T#D4ySZ<(b_QS6^)&E{hlS~stm2zjDT zO$)W_dEa~TIgtt#c6ntw63rWSGEJP`HJ#V3?t=j`&lPTwdXuY3nNAS+WGmH zg%;%}hfrQU<#|1(Cj;#1hZH?J)YjPTp}fl!S}gwk`@JOd4StTU=A*4;PMxHq`<#us z`$I{7^9w+CI%2;rEK{k}vxI+)LQJDh+|fMQn(jk8qJo(HU^x(?H8-I}q07=qxe;PN z62u$`%T9*<%@xV;)aM=p`@|g4j7mSW%$54(ptr4Td@+%3_?g(MD%0zCRE}X-UJK<% zv$hsPR72Dv)?;-;m&7@vdE>*aLgr4U^_e#!HWr__bIX52t+om$;QBzD zDBy@+jAyiCuKXHTB3*G*p`#IAg^osgFQy~gQS=0Q3R8Wnpw@kDL?BfKK#`l56pShl z;|QT_xi*C3(Djp!W%vthik$Gua-#nmiliw28L_x}2}&CnPYv>%-vhFSAYQ+QF;;01 zUevLvzH`!M#d*@EK(2q|<|WwH4rmKnCgo6{!OkC`SD~B`GLNF1xk8aMslIoQmaxAb z#XIld_ZVDhyU?XjsWyyri%Cb^c-~ZQizsVX;B?G~y2;GkN70AEI|Qu8T`?6%b2Hlq zwg+-m73fQkSJv+v<{j&${B54|c(`_ROhp4{yfJ(y0p-zDJ@0=+F3QA{$(&%zg3aMz zCM@Y}Stc=wW!8VpQ=n*?yJU{`42=z(;=LiC>DR6Uj}!bzX;<~v?3TQ|kP-NpUtNsUMoG_h1{-cLdxaEIst#rr$?>7-bJLP)k*$5 zmaw*gzP|G!jJ757^NI9NuVRTF0?PwW(c#@+98LA(c;SC;@_cI~k!pwfHbamI|2@P^7nWXmf+mw-=6ix+;ldl0g*YUL^_ph-Y$9+*V%3uODSoJkX zCrBTB@IHSg??)fhL0JpS6jLET@1Nz;*W4KeYatIQ6nElHU4sz_lc@KDEm_lx53mkb z^ELR(!&s0JpgX-uHTnQ>{ZVZVV)c&dtMCk{oYY#x<{t3P3xKAOiU1mo?#o@W-2K9% z=%*%+)}47&xi?0(QPYDSpfsem)T0TlGG4!-=hT1Noycj`@+hYIlVWpBy(HS$1P(=KeToG=b&f`VlGl9OpU4CD-wy4u?_a zH*ZwgRm~rC5~EuD>v7SztdkfJ&m?D&2v(Wjv;plTvk&YfNpFAaP}M+_uLZEO6GrP& zQg7QCZ2v0{Sn5|1>8dl(D<9T?`xAI)->s_@>__`Nkk3PY(gEeyQ_v)NJ#5TUq?Wx;HLtr{~l&JAhv+ zvF|BwvDlYelU?FiwAE zl%r3>Q++c*6X7pGYZssL_%y{=bhIinSsvkqGUP*obA^|L)vkLFE0AZo=ejFIS&NNN z^m_SwNkj%= zynM^VOJbt(;RGfsMYQ`-qI@m4`N8LCnS|w$rN;gu%5<$CC1|1!(Er79&&_`uHv>j# zC1T zuSUS|*p90h#<(=nt`0JKG~0h4pHr6+46z%wSr>V9!=XL-R)(INv$qrn(R+Xs> zrTWX;jbP*4D^cFb^rDk(m-iM&&2d}1er`t4$sVgot4)>XC?0Rv-NAqTN!c}8Bduzy z{PP}xV`aLurjVlxg>{<(S)&l9sr=p)~U{ zhI=Kib7h3kvmCH^LbwpdY*42Zz}-eJXCAof=qTKQ@5hgU@x6Z>#um@dbuy!fIklZ- z0elPSa>l{c7afj(6@K53;)++q>_>6p`~*Hac^4&(^p_~y@xUDq?px#}ALH&tiM+V3 z_{xjsL2eHjp!aj-c@PfgL2^JpnE5dy*~~aM$-vT1ES|xIZ#}c*hm^|rbrIW6v@inKPn@*Xyh1WPGn?$ zc+tqT@S+iUA$hlac}^saW#G(*JSURDRKk~mTM!nU6Im-i8BKlHwS>YM#24 zWYau#rLLLF@0$?;{t90(Bhs*&ldkJJ@`N%U@>X}pEgXMaR+h}<)$gNwcP;O~W`Dd* zlUd(So(tI@NwuI&mA-m^ywFFbQywGkzmteHA@3pQ>V5m;&bohqrr89(p~gP`fR)|K zsC3U6T=|?6vcniY(yonx9J9y5C^yWq+~CiX8{7m=mKz>j(&t)`npj3?M_HkfWyO%7 zyMilp&;5UGoZF(ba{A!Tm^JxiXdC-mE2j2_b^`ZN>1EH(SPocPt)3Qu3iTV!A-Op7 zB13GVVktAT?Q9J0RW*7CONH_57ltubUw@|hd;N%HoDZ4b*j<|DchT?1dP&ry#we*O zIz{zT%t5|t&7WAFPrCPdupV5uFq`c8Kl;C3{{DZx{Cz{;_5a@g^NF&xeRpnQZ*FO(l`wk(GoDzxn1V zH~+i8++U`1FT9;Qy>$lQ=(lmx=&|{ePn2vKB+{#ZFHBdp{w~gsR^{BC513V@2A^g7 z7`1=#L3NI!6=Q6ppd8JGazn@EO+Jygh2$p5vDK2()vQn`FL6q{R)7s;+zuAqI`ATs z(IU6$#Qrs@s|}a+UxV-BQfVyiQdOy0T`F0q?z!vH(!avs1CGqOt=%*iZRm}i1x#JR z*Wimou>z&IYjKKuDeeV|ySo(kTilDg7AWrSuROFo+#Me74=HZTfA`B~vzvU`o7~(? zCUa)yoSWQxX6F1(%m&#pc?a4)pTtZ!glLLWJMcpPEav(`9HDRCOnoQ@@QB<$?#0T< z5+KC=Vm&tSv4Qat8JSvyP6AP_x(>;9*?ldhryd`y*~GpGLs-|=g4|UnKU`>Z>i%q4 z=_trHk*k^s(`9^gv@6@DY+rgf$q-Kh68xR{XI0pbK$)n-6id}vTK{fJ?$5CB`Mo^? zWv`fL0&M5`TqE0%L?w#=5K?5yrH!QWPxNPhB&1xPyFG$UVToAbagJ0B#K?#j_KCnV z)n`8OdjkQUW?1)yNGc=gZ@mUCUg`{l0Fsm#9ICf#!aS;Z>bi8}EE@;G@Am|iDkP@| z?h13J9BWy?8mr z%wzb?P1aV#Uu?|{evF^YJc7URARZ>~LxQYK!I?O3eejs~ui`23|<_;n^P^#JtrWQ!#y;Km5>YosuZpGe#`M-m2D~CgV_EzqYrW z#qhhZH)%W_nwflEA}MsInwGvo4?PYw({MK6y#Kb)SZC@+)q9te!zok0#K&)M@q+YQ z?6}NQIe&@C*M#us8&PB<`l*dY-r@71fue|y(AS$I&Xh=VEkFk*DqRl~^?0%VQ$P06 z|BYGxWd?6Sa^LqEdoR5FD9%@K4Yd{xUIKIYjcHr9>o?Xx<>fA~fK|2_6}rvht+bE7 z=~;T!iem{CMTqut>l7qTv2w2UK18b6MEw>zE_{5tHh87_Ui+lHCRq! zC952NYyKW<*%3T})LlXH-AVl=v?BvpVPUEH;< zwL8*ctlaQ2X7+ThI^`fx-0-F9lPB|yTAIz{r<%_S1_0#SUF@n*YEbz4o3%T~%&P}j zEn5tJjXstO$DO8tW?0Fci%-9gqHfKlL6g}4ni|%%WtOz)yycdQP%qcY5KAIN?#BIB zb9cXTu%_LzzxGAyis53?ziic+`T>~OZ#lcjA{y?!T>;``eRa!q%Dh1Mrqx<|ijIEK zyS}m(Z-5a!RkNq%PpDD&_Zv6X4!W0$uT#jP14mjA&WddW-|m;>uW}`YW^8#4!@mUz zg?N4&lypCaopStb;)vD0<508Q`GS5lK6ExPCq|WnaN3P5+UlNGRgk?3=XY^?KE7b- zQKz~0cqwDnn0eVnt|ysj`}Ns$CVVN|XU*o#xB+nK_d`Fe3@2&w21y9qLm!e%M4%)a zS$teNpyR?UAxh$^nNa1Vk@c9hXl391q&>6^T6cWwlvp@F3W_kKz*uD>e%w#+!+26G z?;*UNpp>q|ba^jCI>{{>rINm>d0M%f~@CseGX@)z5N=Ig4`}PRMZE7*I=Cgz%iL_ z3I)PV!d+n5tGHNV1FN*mrg#mstYx#M%yu$5E8hGP#vS(5(Q-A#nPJE#Db`4O=v{;N z9TsDul^6HaGuZe^)3ff?vviq>=YB9e;sIJS?Wo6UMVmwZ;xLqaYcem1IYCMNce!qY z&^<*NcM`XJ6z_{ah9sC0kX#7CX5%p)MW&beb^7QXvbw2&Am}QeGs_6We;$FW*0LE( zaY%stG?ae(8U7n25$m7b!FX6^Nq9({hK~5Xd4+hQ0m0`-!wy!H@I$$u)x1}P1BpPU zaHLnbj+Vks0@KBmUx{1n{C3S7^aqb08{{x6&M)gnSz0}0lRj1Sx0sgWcHFcNgm`s2^Sa2DI&5vjI>!|g-p1dSWu!U6!D^FC+MbH4V zP|@|eol0Qyz_LNOPg6j_fNr+a(<+$ggaT)<&xCrcRkx2Xfc7?Eeuod6M<#D>Bo2os zHuYEIpx)-iCn-Oupc z8fvK`Y_!{GAb*lW0*@to zSj`=p7kyR*=MZ5td>F;sbq~u~Y_4=N=gNezHvyg;4y<(~yqX~_KbDm^QKTMIhpx$V z-*>gnO3tQY5EU*h9pT{u_{PAcE>V^oG^g(T@9%IHG<)I#U)&wCPz1@+S?-jRD4WFZ zSW}xQHJ@G6gk=PpoPJKhz*Z_8>Wv| zY&NUlpVw>SZ;fPAcya0kWesyS-gF+$(HNq4X%_}9GPD1xBD;7T!CC|?!S_CPDsPh> zV`#iUMyMxTi!`5-aFh>7#$jzmY5+qP0iJl>atF6#)C?t6vF{|ekBSFe@hYqnQoWyY_%#~OTw+MdlCyICd&+Puj^ zzGN)xj3sw}`;-YHyQl$@RWRmebw9s#KH~b^uJgzkEShSwnaOxTYTYZSx-sYL)+nb{ zfq#T(a3YW)^OWjLe zd-nN|zOg$9RwY~Xw$#9Qh;8~n@6(4;BR?YPwOC>w?-fuXWU&YYU%pe}$PT?tChG4K zkqOJDaJ59_`FzEAxd+pZqB;J`(VYEpE3^R*+c(M1`J`j9BEgDb?HUWs+V)yfmPVv} zSc}i@(KtLpEGi##5xIRn;phD<-q(>RT->f(RCTv*YOZ&ZMJ0ey9IFnJdg6TV-0|y4 zKCI!3GR}GCxTPPU$FSYt>c#r>;TW#gUz+#pVtoNs?kFCnYE>?Z(Lwg8p-aU3z_# zq2~8Oha8H|c-csf+bwUcgpV@jf)2`4z#Czl=v&T)+a$?Wz_C?ppf}4H#3EW}ewmgZ zSYxq3Gm8B0`jfb7m(=8z2=o@j53vI*(ksRCqxg@qxm&{;SUEJY3 zrIl9BWuLqi0do5CzhW}rHy%CB{JIHzI^?+jb20tP-21U_f;IHZPZ9PQA<1ygK)TyI zcuGZ?as6nEn2q4u$Ok_r7w7g|fy&R|?s+Z!N8s-(ey0`5T9%}}&7eZ^&y|HDdn(;_ zBQ6}@*eGf$+)mRK7lhN9Eq!M7JG!*tY~rt^T{ggpu1!G?XU)uExK()0$I}_AXZb`-do#;67c}K%^-!oGb@B@ z9yP#6Pj&YSgxkBv76Emgnobb(T&6RkTLN%N5b$!L2kHLSz0*&$9uVQ0X zN%Z_*Dgly)rU#OdqC@ukLq_5+_07^+ahd><1H6&FyVzXR1JVH@yS=9Y{waGO+G((1 zVq0d$0r-Zmy+g*QyyOdg4bDAk&=3*48_rUv(Y@wvHv$F)&^95TK@-%&3WlbpB z)1&?iGyW(&3Vjxf7IM z-KXw4WqUxVdka@I%r)&t^xcO}m;EVi`n)fdSe;Hql*bc2VFcDi+7V_PhYsY!ZhV17 zr^w2D(6!jTkuV8-p5HD1{V5}lQsQ*AbEt%w?nUfz-JW)d;T_J|!nF~SEawiF%hS!O2f9*Dgz z?k)uR@xl!Y%O#c8tBDjSA3`{_E(IJ?Yt}+uKcR;twp}aQ4U+fl09Zw*-)m8w&fDUw zg2z1fY=wutlUg# z3LsFZ7>et33_;g7Su@r_nGpO#{YKQs{^P0Ar!<{h9x)IF;L}0jq9odM#Y(MlO3e!q zMB+jnEJE(XxOi_Y6Ix%{c18Tx=F`GbU%_byS#jotX^kDlEiI;4eE+>=%9eP1TlJQ8 z#_6@s;<6$gR;7&mmcO!PWW^^2PQi>1yW9P}bP|V!#11av9tsw_6u*)U*xdWjbH#gn zD^>5aT1w5;0Oy@Q7S+$UB@^mSUw`J;3A%*OXzsJJz=)@iC zH|2Aq@h+t{Tk7XWtQ+`RGQ|^&HOl1BV{$bSjxD*@%rEh)Zi?sfr7cG8&B=;?&ulU% zFgmx~URn5ospmrabn${j&qJk3<_Fw--KD%!$ds;`gZHk}uSO(BvL~%dr5E^w z0pB+g`L9%&JL8nA zvRk);dKWtu(V@K&+xDs_^*!NQ$P`J9KpVhho2Q}@An2~06h~7hLY|k}hv+1$Wcrg% z^tRhpj+j~N#%bySj>7Z6zoBU?ecA3s7dAKrTu$C_AChWkX-t*X(km;P`GCd(=Xb!B z{6Jd3=&0`Mo@~-eLb$%VvezkySzdN2lBbs|NYJwKbuXfLapl;!8FA}&L^Hqfej^5N zTXc&UUwioPIH5mZ(^16lRP6F}i_y||ME+*!D6r;Pvp|@q$cm4|+6fD@{$J2_p=b&q zna4nDTlZ&>csFqFV^MaERP_EsCzEbfb^4{QTa>OCym`Ej#aA-SvR3}CnC%;@7Yw{} z56hKSf#EVk=iiMH2yLa27r};suyJHTd+eZ-U#V-6Qx!&$s;7fzl7#-rB`r;2I%5D< z0D}^yb_J=22C7|=8K#{x%OJTFBcBg|;e8X{s!L9}N--xdh`SZNq(D(WVsi45FCv^Q zOYOZ1HLh68L(UFqWs@ON{_s+399=@md<(_S4S(m^C)jfJ!P6qklgl*%DJY0OJ`Cw>4*qW|0n z!lqG_NVKrH8~QnLVVqp@;{(`IiN1M5vnykbYM;FMmH-y{F2H)I<^awv?2b6lh%OLJNu_Jp7ca^kPp{A@Q$^tkNLbO^B0#hw zogbcMs*0T?XgV^l#FWjbgaQ3awVF~5B1{F`$@8N_x16^uM{AboAgOFYTz7arvA{L&xvU6%iu&mtsSfC|)m;mcR!J^9QIvagCMa zJ;bJ~bY!XO;^JB7f{VJ#JM)upiY^R-$^XYxQ-QB(IejtCCo!mBKq#F>J*)qPm#c}w zf94;&jhL>@Ig#d8o8zNkgV=8miw!$uLNAT$-rSup7RPX5d%xy$_bMzzVhM`zntN!$Co1aAiaXl_MR(zx}N?q+;JR*)G& z9}i!tom&d0V;`WqKXW^T7bcpUYfMGwW=rn zz&7fN_1AusxLkJoHvU(_$xO^`B2L({NffpA)WJ8)|K6a@xNK5mssa-FBf5|Aqi5dR zy!G9V^+iH9%Tl=k_8RVJNl{KNIjtnsOzEi1S;EKjy61bICHSO0J`M3|BD z+NI0MCP3k`cKVtjR$<`hYR+y&6`au+(;)tz-rm+A`FpFu>U1^%nh37!_^?Dc+m1+RpCaiEyCQ-%#HLhP4in$6~|1e%SDI}^_u zN4^<>D|^3+Fo&_eCnj1Ce$)Kr-gbW#aVPd7gy3&dwjq1{XZINEeM-UiokN`U1PAAS zk$VD08&a9`jgl-XEs|;q&v{qW)8AfBpYH_NluOFGV=n6nK1QT}VOKljHsgNNIiwCb zF9OJ#{5Ie5g)u)O20Y9rTWpeJ#IEK*e&t~~`YCjFVo6&dT12Zne(?KSNN}4-4rBKP zQiTe|#1-TN_7TXCa$MLOMyG?oXWlN`WLT_f{s zysgb4iCanCx{lRBPM68yV?4ZkG}*_xEt@wT?!!+$(>hTr3kJxuoMexqU^e7XSeeJJZ)VT4 zUO&wgL$)DvAa``DcoWz9G~vDJ3PAV(CssOfd3IAoefMXKyWC^9yf&vy{X~&$Ap@&} z{kMRr74NqNe4z%VpN&7Q2AFiXcq=RFH$G@>(l>ro&zvmQM^4?9uKmvp{m>-h@|1Fe zp^;gdKbjUV6!ncmO&!Wpi?LWo@h=dlI63VtGBYt8Cf2zAOwFvZ_q)ps18zGSkQ-*F zK5>QVnGhI3=mZgg%1u9GcT-K+h$>47w@l>-a_uLJkFHiZA?q#RRjlT(o5h^(#7u2c zA;w&`lT-h421HG#o|g}5cTgSBZUibxBn)&#t_LaS2bj7`HSVpxR-8nm`@8O^Qe~-U zCbiW2&8eS{AP$1$Unt4KfahW9ts4n!2{E6;P0iX*3@2ubA4hBFH7gZ0XrkPSh`tYM zFkj;J4=dVN(`pvKf6`H(n^Gg1k-+Ua-RUW*Z<4It|)!Y4#eaShqM zMsE&VXJn|c#=XjG`17`Ukv3J>$`z@FRV-`Hn7O0YLIARx>ZKi7uXHfAcpx_FwS4Wc z#|W~$LK;QxrC)flHfiDBBPV4)(jI?tw*dRG{V^0q(?n?8zE%*t8D&@sShun>ZLf;| zX@RIjZ2dB+>-V-N24EM-RmE*4Df#jfn}oMMH_f1R&P$(See`W^$dg~xH_8J(MY~uu zZtJ&2B&3D9-jNeDZ`1q_5(6NOP{?l$da}xow`@O(n${m4Scjk&z6dO`G}`g7(hsyK z=xQ|!alI=hM>tDs5g)cO9Zv)s$z(hT4JD6o?qeBR5Z1?$c>or@iC?RT-8omChd~vZ zkC?O^w;v%UC8z;Q7rrL=g9argB1d(fg|=@omD0&s2TkKBDMlp^TL>|~8qTiNldA`N z;4Q@-+e!3_EtRvirwaaYi8<#|*gay=)6Tj+%$$(0zNrlvpJEjX!t6jAWJ<_r}Ye4D9DdoXxLh&Vpaa82QbQj;n zD>s&Fe?^!;W~Xm@q+WljN~&t#@ZH>(lPCT`BD!pv1-=>~B@1GkwH+Rx^HhZ{OX!!H z(3ew}plgymlcP_1F*kwni3)(aJ^RFGv`j$2Fa2V5yAY< zCMecyO+s*jH)9fcYxqogTL6qFc-J6^ob)fx7eLt1WFKGv^nsT)!eR$s&CG2Jv$Kwh zTS*fWgr&n~WdDGsZ~GPPZmpXfGex>!k-1+A;Y^8iegp4ZN3AeiXRI)omoeaK-j#?N z#ru01DORT%A}xCwNFAQH{>be|a?{UxCb@+m+!Izvr9R^fw7hdex>Yf@jCxoj0Ns%v z0IW8kA|McQPq4|ib%{I?!C>gU8;^Bwbu}kEiLN>1g=}%K+V0N(fZ;G~mqMps=A68f zEo-C63L;dJSt6Os?o$e_)h+4@Or_W^BKo!9uM@S(w>fP>5(X)aMQ0Ov6nS%BmfHMK z{(Gn)`fdN)m*kfcUgak6yk~foWVToh~blz93#W%uc z#qFc-5|Z|AW>siUOJ`A7M)=Z-!kFcbs|u z)$upQRd{{_xaWL8u@8^JJN^)^ZClJ3D;&QzX!YMv-f)Ah&v`6!e2!lDpFEUMf*N*}$8vNTv3FzqFc$ntufTl2%lbQd4D0iY_Xm zUo9T?^zJEDeo8fOeUM+I90aAG%GQ?%^_?GF3vsC}lS2qI$koT*Qt&&55MByrZWxWB z4lna?izD+sENsQM2vq50zxsb!FaMC{cE5QR8O7cgOcgr~B$)a{60F2|sv|gfMBm~? z7$i+(91%L~;kl4;ikK=^iwsndZf1oSmg%+CNXbK>r#O2xrsMECFy!?2({Uz0X@s`u zq9s7HAst+D^0hEYMRwF-g(~%U} zcT%!WwD;Vn-sQ171n$NUF;B^H%->`nQGMI&i7gl3+ujCOg*e?GaSPqP zH+*l#CnQ<1Xqa*STkYjnJ^5ivINgHL2~;q8Yb#3j1Z+ktck$cge!J?+w3u936>_P@ zu}<{8d71vTTx3?5Bk(bF@uk9ZB50n^-?N^h6o)&j#KOABWNO?Qshy`D{zOYFf8aGg zlCtlpdp!_-Hp5rpNu)wHdi->~?AgPc+S@ds0rM&q<)OMTfUg~y+}-O*iW;Rjnw9sZ zSvPLTJ(-hVU4?q;SXZQ`?g_pn%alH0`<1|B8>Esw$xTqY2V68AZ}ni00iNt;n1?#S zx5@c5eM@F@gPk7yMGkvMJUw}NL|${0PT$wYf@`wH++y8surp6zdDS=1XKh!R`3~`W zxWfCw<4feN1mjhEcXfx}jRmlc<=zq2hx(p22Q-Cc&=d~+@G+|-vq2LZLI3!9PQxcHuzUmlh((V#NG}owL z?WhRO+eEHMS@Z0-C)vJVA-9phYCvJphRn1LmeGGdoYeBzwZ6qjr3;@V&B$X zt>*Ew&NUh@d8gw&h;iD>PjnTi1;Lt&j&w;tkd^SohKLb)qH3YG-iJrNdF=Tni@X!k zEziC>V1s_%SA+(4G4#WH-WXwUg%+D9YgLWwoZ#-F)mXZrx`vLSrmpa$ZaUvoc0#6o zkj6cB{5t5x>0&>mJa5ob$q7S@Fb zR#umEuCD+m+W}hl{y=SG6rc9{g9x8t@AfZtWSH0Qr7}~A1XlIY#$&P_e{Mraz1jul zOsajly|o7#jPU-+UEL}iF&h3g7>Z178`i1wvUOPJ*{MoqeZXZ2vTx)NAhoJ?sTP^mmxD+JIx?9eWYjlhS?)-HU6Qdw3PCTgk zZujR#_o^|c+~6v2Z^8*2;d$Fm!>}i;JpFKougezwZp;HanE$qN^8Kf|?Pjp-Cs9qD z3o@7`Tp_e+m8^wT*eXVjkpPmh^PJHFlnjK%T-4KLbChRanG zHcMHW9Z{tPlNK_zM9m|Q_Due+-#}s&-Zf0*#V%2Gcgtt|VFCGab2F-yMp$eBK<{$B z)r{O35B!vYWcJojm`d;CDsIAi3YUJ*u(L@CArd|B?y}2B&C~~Gz2k&Tos*6`rJA13 z%#TX(c9x?Hu|5xDY3$7IEZ>f_OJ^qSH7(h*jXap07#_@9%AWU6b#!=$(Cbe}d`3T1 z6XedNqg}}-8t3v9rYzN~#2Yo)0DkERW6iP6Q@p;J%e>o3C&Or)Unr#u{j3%r>oGy@ zD-lju?C67ob*Z!&J=H&6v3?`h56;cJLcOlM-8(4jv=LX^-QWJU#qC5o(4#=Iwr6KR zEA5)I(66v{3&mve#O4J_r%#QfB(94D3=&EuwUgsP&uTkXzfCp_9e1S00r?<|hO^}U z;ZFM>-(Hz>(?}f|{irt!xE!{ksGI^#N;Dtom|qlAas?mDlB3Q78t<}(N9vDm3yQqhcxU1r;bOvN30`6zrxr#f|5=v zJ!^%OMppU-kz@WO=XrpAI9w=9D7U$P3nZWzVZgpkDq2w|XdM2{v->!^^Op8lCh?`un2QeNKfa5g3Nir6QoW#MHcY-fUyEJ$(13 zSgf>@Yv}k}w*tl%hj>szdS25V{pw@QYZgI%3W;S8%bOC;a@3Kig8|1!X z38}uEMgFK?KMB~u@&g{GSqqX?b#m}U<8+<1jP9c^pA>+uG5ltzOz#z_rz4S04r2-F znmsn10up@?kwBVgEnW^}@j$!Cg1fZ5t>3Gk!ivwHewjC;D@n=2hLgDE{i8v|*cL*+ z^2`~Z8Z^Oc89V83y6{f5)C2A$emkXx!?X_ar2L=o2EKD#F^{4y%xX1&Vg9|-RHuER z;=ZATUVzSu1)dmAkY(o}n!)NyY)Q(OxZpbfd(!Kr@s5|K3#VzBbs?DtMs)J~#HJ^N zl`M^q2yShJ^9U1ro1^#;6WH7D$r@5;Cm~%;XxFp%G~@C>pOe;!;Wy3!h(e4=!FeLP z=7-;;gRE7ZlE*mxkXDjrC+;n|<&jrTu#(`92{0Hd{Iuh$UWH74>2e10K4WIzh!vou@T)4SEF0D-lG^7Pla!zY>OH= z{s01x0_?kg#d4}&NNh|(E|SB~MhOMBp{1@uYLwF}3q8@s9o&N;C&E*cV_p5(d~%}F z8x*SD5xU{b^!=URy`8re8plMAr50|hrj*BlF?;sLtU98|4-Zd{7(FeXlmagg0MGKd zOGS;-D6ggT-0{KJ0I$(%v`DS0#e#av7ZLqmb{@23)r((W#OLjQr#-99?y$3$cfI$J z$s4!!#{%i$DQYNR8}%ES-|{+qcpP1`-!Y(`m-pNm`Qv7n;zmX$_UQPA>UJ`tVjc5O z5JjE}>)>~>-O4%N8#KeMbFQS4Bj9s^j%6`V3AY9LOZZm(4g!tK4nic)28bQtr;}L| zJ0!=dx12JXdQ=g7bn-0reYRJ=R7Bw|qMKl%~N=8QPl zuIG@`N~$$gt6?X3VCx*6^=mgeY1W*DvEukDqu4?U#wRmuH=RE!3i|sh6hPfOaLKTx z<}^1WER>eGV z56Vc1oDLt~tCmumQTm6-Mu0XBv@pBD9_ZWNPJZLw&v4)-EUP4AT-{D1#)-MJt)vZv`tTF@0~9`Z&8u7`949Ew z6a`FXw>e%$3uC7h%e3wOGM^u+_fJ^=Tu|TS@FGGGM6fW^au9dE1R_~pjwcJ6kRrRs zRcC!z9zug!YuGlK5T`Km-H?~m6H zQtY274L)~~RkI>kYF4iM8>|p{Qm<% zK5;MMkl_Ec_MqSNObPm&*th+*~GXwW&HXQFz-F~ELYD8(C67}@yI zVVwB{1c(MYM4m*P%*|Wc`d&4qEGhdt6g8_DEtj55&C}cZ{%ZKLn}Vl&?Lw zRUdY!%$MgrxK$pusI-(D(g?=xa}_`$$Y}&)_G?r;H>^JTFCwVh!UU2bY?W;Gpg$N| z!zV3i2DRhIX`cVWjmr7{K@G_jfJ=T2kB-DrdR9z6myk|N`Y%_Zxm9wfu)JebqNmi~6V;1_6m~L_|^GhmRhoF-ZTFDV+KsonjXom88GSUQ>DEbi=Ibel6W(V`c(82K#$| z0pRXit?=z zSP0FD{+PZq+gSvv3-$m{qiNx?(b>}pCpt5kAeczsZh9izVL;77x&q@E@@Le(4(A=wONa`tsQm3as0Y{ycTLWV%Y+ZQ6LN$$kK2rw ztK6FC{LzFNnh>InMuN%(CIHcG<(+YY4Z#m+Fsjbz+HhwYXi7*Lt_N%weFTWt~MGO4~Mh3^6 z^+%gO;)zNxD0qoMMM69Qoa=Xvw4I4(YG7sXCF(e(zEo?>nIzadgbOtbH9ADXDCt~9 zn|?+7mJ-?(qK68jT#@wRF(H5og0a9{X!Gx0u~3Sw@wFMwpG;Vx%mhQX41S4cs^DOY2hPrH>@ ztJoTRCJy#RYk9XO-Wqvk3uXhmhmeI>;Z{@WE4QXQQ<-o<&B05IADka=u(m1xd*uNC zmv%rH+gu@WIM=vqDqh%7gAkDr60{oH&g9ypGhr|nsum6#jc|f9ITQm-52l7rSL-ESuZ;1?~t63J)B(e)+lEpXk^GGs?|GQoDXQ>-8BE->d^&j zvAtUM7NCU|hG643zH-l?IU#&_9u<{6!1j9%CnxrM zJ8_xyQlGbFCJmcN9+c1Rr`1<&G^)lKk>I!}SL293KZB#4$KRQJ&Q3Ommb)d?_S}1d ztKfaN=Z+lQs-8~}$X2;6j9=E^N!2|JJjI#;Kn%HES7UD7vn5biJJ0^P?GM|_W4mF^ zD-fRb-NFMp^7Y?G-N344t#KF!T`wiEO%y6{SqsEf&e!(7hB7ofhvcD= zAhW-2reIz=%seXHJGnh>QB~TweeUz3H41F<@ZW%~h?TfbZEjjBnIN&G= zKI@VlzPBP8LGgUP^qGDZP`|=1?>4%6QNMaAxIftI4ahyz>){I$BYI>xYuf0Boft&S zC;o|j6tI%`vyMg(UOo>BJ_79ifZ+6J>BnkQJ%X2z#qjZ;%$BrC!{b$jZ|R*mH#$|A z#B7bH^E;iMr#fm2gE(<6f%rP^vzv8>dgz8w4g1}To#-0Id3(ocb;r@^e;xXmQ~#ZmcFt#A>oYAg-ZK9oFW1EOB+YH``F>jy*eH zSBK4x@j`S|iDWV<(PUzBy4epMay>l!Fq+pWFjedbrD|O2CT25Qq+~ zh!ca)5NS8BG#dj&pYP6=Z zBxBnE>ZQft*sw@XuMWKyG777sRe9AqiLq}2_J@aieZ{H=xXKC5vQ zxCOW$cB_89iP*oWM;VatEU`sEJtW5?JLP<^_nXbbR4xGqdb?N!SC*ys!hKgloQd~7 zoncpPN4e64!dTk_LRIgehJ<9Np-Ar7q<>*NO;}q!O`TwTPudbtfbQ&i=|Jy4h}dRS z1*znCnXT}OnQsr)`IpX#nSkY?qWighFa7`w>Lm3=jq_90tzTGrOp9K8;egu4H>hIF5O~^3JLF^zb^J^yjo^G+|A$!D>yj)M0S| zmUw3iO5}~vR|OPQJk1}@_8o9OQ2ttiagDZp+pj>NlK^vOI(*3=+;L>N@KrO-be)qi$>b;~KVy(YF z;aZDsA>0u%k|akE+~>5)UvTzm&E;?s06!-$2PY3F53eo<`~Q}WhR8{cNNI-jGZf-# z`io*cU!nAK_3(WwZ5I$}sf3;rul-{z#~2OMp@ydyQkq^YySsyyb+NA delta 104381 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 D7;7b6 diff --git a/test/resource/ams/ams_page_ability_bundle/amsSystemTestR.hap b/test/resource/ams/ams_page_ability_bundle/amsSystemTestR.hap index 1bbe0c8edac9563816b83438deed6a83c888ed08..4789fee77dbe30d4c5bd26e30234f6c7750ba15b 100644 GIT binary patch delta 114753 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%0Am$0@q_9 zZGqq6wzIt}J|`qK9iFG1?SEYh*X!ZF8Or|fCLwbm-@^mW_FfP7mO^?T-1{-}Z0}9* zy9z!zgO&OBvL4O-=#@gxw7BjPG4Wvp>4t-z-J9r{a>_QYl(Dk19&Rzo)=O_jG>Kdb z0sd@Q!S)JdC?ux+Q|E9*4DRS(X*X~06_%qLb6q$-X_ zsi08c`SiECy^sFJM-=*tPi;!>qd+&5&@R?X_qX@aUv?swU0%IgBAlbqTl(`@BIjrn z+x^Y(u$nU~n7f*T8)g^mqigg^3(-?RAxQp0ZLg=YnycVTw&v|8!C(0@?z0ePn zB>@xG)Mwk%iO%!psnsHn>u2p<(4Ks%gtS5~t$$%yULBs*p&{BZ;0B&}y0BLC#w_P* z>$mN34`q-9c|Mn{+ztdLUb#=Z*Hz>#OS8+DsJt=CBubmLGvVC%WWoWL7p9_wb@{I)1b0iN7YzW zrhk*#qa-*TX!V!NeRk1uALE?;HsyT}V*LSpcbcEoVv#KfBB%uPvEMmf4>prd`lP!m z(BLv1phbpeV#}VFRFDxg6mVhN99o1@`@18u?PNuHrQMEkra!Vv=TaRGXLw!Q;Tl)_;k_AaTwfnbVS^!$ z`8b}elr87e99GKR+xZJyhcYFMuu!s!N`PI+R=sy5F?%%(G{pweQTP z{}is0e+w6phR1&nm;FD2Yv51dDlV`Gb<#7trt0|M%^k(}5UIpVCrv3>1wQ;2?SHA# zQd&gEQwJSI?Q}SZsw|p8)2W4;C{H;`=no`LP7sN7l6LYH5y=s9h%}QB`Ix*<_K_yC zo9rNOkVdkFG>{iaJy}ou<8n$YVfD>wvCa zCa;t2WEare+dz3?a*%vV{y`3t7Sc+-1nT^On5dZ!1q#jvI{p<<^&~o(UP+zQMN8=Q z^e(!J{(-(gU#6SsYxI5k5&eXQX*2x?{hYQ^eKoCmvrWH>daB9{s~)TNR)47=1$H55 zGlQUifG$?asmE4%JxVGZS6iCkqg+iBirtu+e>z#Ge~{kogx|!~W7K=@Dje5ADV^oq zoyP>P``ndgET%OMlZaPZ`AX~1$X7b~O6S0Ie+dJm446tX=&POZO{)@DtK=)_MRNB1 z(<*~rxJ{Jr3-Wz{H7Q#qnt!v2s62KmcdpxjAH+|g$nL_;<&8nd;cDVr02 zR=VJKVxm+*qEtaunKc{Ve!v_H;hI1ip;Q^B!WBY#k>{)Wp9Ac}poNR%5vIzmsN{ZJ z0?-TvXfDhPaFjt_x-gNmSpH2et18RPHi?6wH$$K|SY3UtPbege-$VCnWzQ&nfzZ^PrfM)$`+U` z@IBI$1mB}f2Jx5cKYtI#Md#IzxLb5Slu-Y4e1qVRY)If=>&eFGztfYwr+h#BTu(j~ z{ZI5{P4uVwo8}t@ovrZz{ zi#;Uyd~;C%AWK*qg{0mUe zt5EBkqF$9)bYR0kGDI#?Q6Ag_mm<>8>jHuxyk_TO@CR)Wtn z=_Me|N6^vmd^||>D?pl;&~kb;t)O%0TzVsQ(_5%Oe@Cn6y|kJ>LOpaD$oa=PkUa9=nOiDaYwp=Es#wz#k8?BVD$$w8gPqPe{Qq{aMQI(u~COL6$T* zm8{(Vy-_K@RF`-@#G;Z@d*^%S7tg2j_W}*z_$u=BoUG_Qb@sX7~wtv7i;soHMvk*R#DL@{Y>5d-p?7_M-+<3Y$ zmbRQ%I;CZnfMqRl8pZPPgq!2`#);ThzT=1`QQjiY8!u~|ID_OrRB{k-a3oF~sbn{`Dx*Y3JOA*cs{1_ zCb*l)cm{Bfybe&yWn?%oAIy2KurZoTv9220e|lc>|uNlH1Ey z9?KeHONP%~60gV8;K>MF1(&kMYR?MR$MlrTPd%J#cS=t0{?tkGa@1w+% z9P_hDzDXkPWo>0tI(?=%D>w9;GoF|x|HQ$)+pPJq&{1K!&fJ_L>67_TbA+mVE^jbf z05vmiUxZj!>5@Lxh_*_dwCwm%VU+<7wMjO>!@tSPH#)*OT01Qr*N3K!3h@j*w|!bAL3E+vM;6yZ`ck zd%yf&<}N3NZC3)O2gcRI#^p~rVc$ALmJGc)*0w=$)iCVa9r-XqG&N{sZ!v1cv(D6} zls1}^3?*qUluRCPpK`*umE=~4NM9eE#?u*q&xZWTRV0Ub#da(&}za=vVV|k?dieZ9Gb%U~w(0DoC&x=|^bCIoA(9ac_)g?l#26s2aYOSR13WmJq3+hDsB55G(I{KDLl#0CZcu zU$k4KLXt@)%Kxv?O!z4Oe}nXXIaSzyU->R1#ELyt`^^54c6Dg9-4Ui%wGU7D$d;iV z7NW9z$`uzDIHkXN@E(UJJU3-9~nV%ghI`cX@wcVxrLgLW^I934e83l(_ss%EZ~E;STz8V!+uE^ zvAi9gJP6EB$dd8s~pYTl&w<9jo4FKR-kG_NMrUkSS97U=hj zOBcJ|jFFkEpy#BR*x?)JCRnO}{g)Xr(AUz`8c`_Lkr=ns0&1#W440|**P8oF&X~_!24bOBkucgKDsyK^C_kXNVB>K0qM3+L?qdtl<`(F6w9)Rf> zz;528^QHPXLn)+b0$RhGfWuIuz>!>oa9jw3p-z2F<9ABDyz4^(BUU|NTq7!@MWp?` zG{@|FZyV>Ywr7VOY#7)t%c7U#`qd`mCdAXzUVa_YW7-nEALnVzwR#_L7jaB9-4_&iL>L{#fQjfF}2nJV`y!{S@L^^J@-AKx5bFc6#b)?Mj7>XsI;CAwQAf{{W{fJ zbKOwpn4|&kkmj|O?SG}yPS&RFh0i@vle!3U=%4Xqr22|ugpe`3 zZ_0^Bw<7f~Iq~3DnuFtqQ0E^7SwhU4R=S*$Z$*lqW<5q!rjCU)PEt3tI^jXZKN(qP0&W_PiR9MRaxp|4((+>p^5=D zNEH^4%leH)c2CcJ%ZM!yy?#k*Es4HI@LY=2HCQfFH2dM#oa%o&rb(s@#@eResEw{r zT}!l=B5(GM^G26B>e8-~OOi3QAspRj!phj1HvunvqwxDNZy&cmU2_-k_kRkPJ*Z{S zZocoB*{6ZtI;C&DX1^j`kb8$NQ+Q3kOyRYpWf$W$BGKJunMbL^DcvJe1zOZ*pP_E; zF{CTpPvIdLzZaJ6W?7rFKvNT|>h%8AH-WBJQPt`HUX5p{s7-uOZF^vzOd}4R??#Y@ z`@QB(CeZL!>y4m2A0o|13x8SVSLfu`H1GLxiygI97Qtw(iuB16QSkiC{^R`%p)@Vh zZs2`y%jZNYRM_p6=}0th+{H9;diw;%`ys!arz?zT%D@F+CY%Pd}vS(P6fx9uMVRrqB}c@89ktS+DT(bhRIBD}Q(DBprR<*`&KC zl;k%*3v{O=_G`j2l}f!!$!Nqh>cpKbQ>^Jev?D5s*$e zfw1gi*xx*nj7WX@5wK6p5zXlIL(5&MpAUZB$|jT$Y0i(tR$Z0eu(N6`!}3}vKZdop z8loDa7O@^fR7c2px_>=&L%P2-&Kb>{9%vJ?b}_Bbya}3J z{O5Q^JLd8)aV64aM-@66=~d`xl=tU!WIKwUKyOj1Z#C5VemfCJbsSLYpEdyt14a_=+MaDt<&Pu33uG2F6o^Jb&l+fUF^i*Dqm=RT_jB zb!@8doU~bap0p{H>$qVlwzU)5f|f}I)Mv2s2j~?jCxon{C}%EHpXt)r#vuSfCD z8~8mISK2OiDO9Qr5jUPUmDeiD+7&n*^Pz4sGxt&Sq3{j?t8sTs1=8Hi-Ur(Q zxvCoUrN=Al_kWEGj`dOgcF%b{T(>2rqJcBs7`~H$@@Sf#cOn;M;mKr9uw}vKa4?hu zJ0O3ZX!I*K9CCU_03`;VsCt)`f_2e*s`)K^I`gPDp$8BfFD^B2LdcqW3cXEnQa|k& z$o*`Sn8dOgKIAD-G|gK&PkV;OGN*dy6fpg|_26-WAAc$BuKAMPn4cdq0w0rtZ$hK< zzY4=MM-sbnqzHFarmTiK7w8X7(t$9ql62a#d34;9F3lP3$+8Zuu58Y?VUnvAH^lF= zT*8XMQhFRxnasRtZ=0d6_f+>=$n{$3iEiX}RWnj9FV+kAdp2EnQeZqKK<+Ar*I;czdIC#*_Ht3FqX6oFaeu#tuOoSXjrBV2j+#*h6R5$euSGgR z`rw0iGkHJypbpAfSeBRy`Fa0rm%jG4C|C>mNTIkBZ|Yi%K$t|mA8g6mK74?6xQ4IA zUmnJSj0D~3O{&!gfa{NHYZ0rr)?9&SK;@>^AvX7dZ(ayAg;WI4Xmp?NmgVke9z{Pj zdw;aSWw z4{z9>;Ws{gYwq&vserPHMgIQa%t*W0mkOT2tzoq3O?9$N znWIRQ#;lCZSTa{GX|ExpXN6?@Tt}oWXMc>fj}M(8nxFkOj_?NRxFm#f&Lq==`6Bed z0W}~k6dk`94W!EQ|L@);|I0vMmH^;1_ZbnT)+gX?5S#b9!D|M;qLp07i#r`go!`7k zWmmPl+eM6O@vp~4QOt99-R|^-LGFRpp7EG_<^z;PrH|ItwEMi{fU4^v#ChHV$Ep*0a1gz@q% z7cYv5ss|F7s1nicM~U*K+<)e~pQ2?FmPeKv2Z|`uwSJVKi8?_4m&iRgZ`uMFrB#TD z>&3qI6ntPF^QIYzyVDZ20afH)0r(aIG?Dw}#FL`_9HT{qB3AErN$krx2vVa* zd4c z0mI`uuV5JC(nz~I$(S*0e|%njMli(YY_~q-(T#xi?Axt^6HnvGey$QUE!fW$ffwfw z5UrJ3=}bGZ$3pe;N#G`NekIM%HItd%JxBwH)p9l=&#oL?_!q(64z%C+h&T`1LG z(P0D|=PrrzPNo-~Y=4Kmw>WB!n>+OLGlEX`NNrkOsys*WXycwv?hneY(Hd!Wd(~g| z3LGofr8Te8(NC>{WqV3OQV>dutnMvAz8Y(yW9PeZCFE=w()XgpSyzXS3Xkd3&A6uW zG2Qo{J}2PmUjX&k`SYvx)CVnNJ z>gw*1TySdjTO(fxFRc!aR0Y)z^(2f-ua{4MsY>k2u4TN?=wjh?p^CJ|?TuwwmoVHb zdA%zmgr4P~C4UpcMKETAyQBc_HgYNRz*T2w(N26nek_ddr7*U5ey)=lMa-$~Di7dW zK$kKOu0HE@1g!A;P83(XB4$5`6X!?p(aF0gX{0x!aK{68Jh*R>lYEG~7bWuIy5h@! zHV<-3$N;^cFVBN;I1iEw`oYYP9mQtFxyc5Wc4Em)E`NN}nWf*QTw)k~;$X_K-dthi z@zC!_W(4mTNy9X^y=|&w(a1A(qru{|>8Z`Wis z43OtS_D51JXj7%H*&i?RQR$S&i2Ls(Vok_<$hmso{-6eW6{zeN_6hXICs2EUh+AD?o+%jpmX(oOzKU zHc_#Rnb{6D7Wb+evy-L5cn%1|7^|;6Q}eBUWHQc&ENtp2OY^(vx8uAd>QQ5qR27}7 zdVfCVAYZfA(J;{Xdf^Ti1VQj{H4K{(d=; zR^={hTi&M5rFmt{+eWjK*FM~K824$wjR8UIBbzx}xnjaej;{_l^Rw11m` zeltXUxPl=agB2*x1<&lL7(7UPIX0Ed?2w4gKK#(RnS-Grgyw9VGK(^AU?9@tGDINd znp&Z@-RI31EMF;XQ~Q$rKJblob)4^Vxi4RpeRWJ8QM4yepir#1yOmNBgXHIY)J9X>pQfCC^F% zd+Zt$e@dOQ%As)toWkXPY3NhNw55kBq#SVp=YoYMeHuGG!A=6$FLOrV zKwrofn0|B(#cEKyB|p==lp5QD+)Vz9&gY_K;%yzOfRtDjM$XMPG;l-zgfmynQSiH23AtqhOdasdk!+iIStl&4L~Hh$R6q7e9D|`fG?zo z$~WC9hfs;wB4|Ww#Y+s)=4uy69&Ht$b3AS64L?{o8+cGAv*k8uRkYl8q%&D|HsB(| zJf~^UWG{L!Tv2V!m?mXx(u3UV)xDKI0PZZ8AOOiTzwr<4IcJ18OGJfCetcf@H`QW) z|4@{rIsL7mIL=?6Cyr8gA{35r#V9cRMS85uFS4W=jF)El4H{WW{6YN>MUty4AA z38mEqtvUFQ1C)5U5JqGUf1Hak(7rik!0iul=h-3hWWaGAYf#$HkEmyGJ3~ee*s~6( z)+H4`eSRw8C1$gac4TyE9bmlq(lFbhtui%R?}Y3A5V@Iok-OCO3VYI{epQA^@;Tlv z&d9_)jj>p*Vz2;-djpflEQ%7O*U5&xvWA7XH*$>1Bg5H^!}0|GjMcocX(N)- zZtNtU@0T3DD81Da*eIK3B8Wm=RST()=EnWx$g>{JbNf6 zdsq$UK1rmigwtD-kdvn^zxg>Mw>+agY!JeR{B#qXVViyiSWQO}RYRuHz5yx~F9Fx}%APgQq47G$Ra95DYO^NW^Pd z{5jlMRdg`FG!0KHKS2xtYEedv!mXpt=Ir)3!oHYZ@_k>HMs4s)OT)`WeYRbYxPFuv zVBKa3Aj>b!(PwlOCET(yZeZpQ4 zr{A)L7kh`-KBI{0^}mM|N>+RcESevt{U$OL)sRNK0tK9YpQxlcnP~0R870LF#Xzvt z6?}Tt1n1|1LvyzPqdCgX*LA3>@a%AfU^K%Lw1z{Zx ze`$2~*dA%SdpcoAT4tVqMNBn6AE?-iH+14|t^8c3wEXdNBh8*cW>471^2*A=^-d%8 zOCd3k!&Rmk9-X1ST`|!dAoDK2xc$!d95Ywv*1QC{lkGeK=o>U4+#g#oTa$rTgtZMj zF^w{2^-Jmb05O?(!A!!`aJ>jFWfq>>Bt_Iw{iRd`sYtofcIcy}gXp|%%$tR~GNh|P_qUPQ%Hhj5~nY|x>ThO>>^WH@xgu8=D}O7o>eF6Lyw zpP$J_XwAMfc_qg@c(_Dq-J=Yn)KMxT|BDVcn)`V#(}b~>apY3)R=F=k*6@}k5_3?c z-_~<4N4Cc6nzZR>0;_^tzl}_3E%DPJnM6{AO;;yiOc1rJu+AqKOO)7_O`(xec%Y=| zd>PcIhqTzPIbf>ju4XOdxI`)il^%4sF5)5nj|A0{O~$CrD9tz{py8pLc50PjQbG14 zJO8%ra>-~6gP!syI?SIxf4*jJC!5h^Zdcivcjs?8-Exf4PTC|a2hc8V=KI{&_hKs+ z%7|0|$VqC{oDkK2kU|#780Sm$!PnvDR>8ai^-4{tHJzQy@jV43J805)1MI5La~3I7=D6iwasLfkgphjUz)_!WluFl&vr&D*@?GZAFGa=+X7Gb!ZMJ_xM&Bfx6m*bi6 zh~UQ1i|YCfN2@#Gs%I(mbNg^(3wZ5xZm1r;+AA2Awb6^bAe2Z2vqX#4w???{LUc+G zM&#Pv{5S7A$+pffA|)Nd>G_^&rn*WnFrGjFJ5yw#m;Z(X+p@Okz}2fkS{&j|ug}s| zh5cobt3Ao*BVl@xKOe8uTI1i>Nvx2d64l9oYUc@4Mm~`*Qo=s$+{X}}OI%3yB2m)^ zJI58YiI@m`W;IRoQ@bFlwp^nRC;p9+6jZKQ%3SAp^*TI-=R!!+0`uwGZa~F7pghmO zZOF4o+EEO9Ru=5Lfshp<`Vyn@@{3HHW1VtmOQl9HDMS6wp3~G{HI~y@Q*uu)ja;DG zir#k$j2)_*!{Dd?;$`0~Bx8-VHCUdJOcRnwrhKHwy90Eb6 zI8+`Hx>#gR5^~L*UI*3ATJ?j3+O0ou>|r9JJonr`$@cjel-MLZF9P?dfssANE{Vrl ziBgX~e%ij=q96LW6H$eA0TgmO3xA5k&0$_x1hE%HzMi-r2#wMDq*Utjpjf5G;uK#w zhJyDQywQogEH-`6MO^?ZW9UXJ!*xhAvozjjO;3Ofz_97{ zST9_s{>nb;lz+;+5axs5e>6}b9H(dR>=)esp@*c*vcqf#{?JfoEk0%Bj7*g7N|i*$ z3uX2T{{lB1rZJV}$ZSegoQp5pcaae81QJ%!_IwKD?DmjsP?Jx!C6SG==a8Y zyHJ-arj}aO74iLPG)=4CRb>;2+w zt_*N{e<2W%D_42rq}(}8yR0ND8VG=Gn~SgOX3z)Gc?FV`lwZzfG;nh#VRayshE=fY ziDl>lQS+mJF`c1m3kQ^km1M^^Bq?rIfG8c&n!&)Sd#`qZvt|+1X}u@n8^$c8KsiWn zf>*bMG^$YxwLI@SVlCG!lH^IwwA1D+5*B5{I^rs`OD4?d$s&SRr!h&o>pzYlYM8#_ z$mP;A|96E;hoRCdj1j5t`Dcfr{UExRmqA_N?J&9n=EnekG?9xm-^BBw&&qCQ!!ln9 z&ny+8MD|su05vO(8FQ$*VWGGlkJ5CCX+KxKZ)Cl&cZ_DEqpZ@}&UUs@zh*%Vd|<)B zc_EN(Tf?VLrj>o7wG*G-X-@nNGd9GNGO{Eb?oE6a`xyuY7k1_f_^_jnyu?x|m=pq@ zBAK(89{_lFPG z0D&bf6(#QXkop5LsrW?>sJkv5dNS8p{UzJ$6wBglX*aETj=Kbnc7}syUzAuxuZU|M zrA)_UZ>i*&l4O#guhhpS@w0;juw=lFx#Nyao}O-fDH}Z481S5;(TMy}*VWP4B{Mnn zg=>-!++$xy%*E~S-b{ILt?g?9q^;^wXwK_7UH>Yc4o=tVGEPM@Cp?sHuVynGVFb0; z>u~15#VTz_U>FBiR>KY(5>RZf5Pod=8pv9y%wK#|nlQNZA!G?|tyKJaN^fp)cC=U7cT_{4 zO{As_pzHG~z-GQbq6pY?R2j?r9xz*aX;UbBY3xc^7%0Pc;jVIGCfPdMaCG(1h;M|8eAw*lrG;j3DO%sX8ym3y>~=ru9JFkD&+lALR( zr!u=Kh9gu%$N;A&H;~cuK)N`9KW4=A@U0=nb&SFT&aSPj*9h-BQHJjH4!N33PS?GD z=s)rPsoT#|w&y=uRmQRKo7sOktCx%MBd6IE8RsSiKk7H$T|FS?)j3+x^A8=2*><+> z7#%>>j83Olakm0^mf6vAzPvW>_0ix4VA34k!RP$?*+`BQ%<1G_Y6sMtym&{HTGFY zNzVPel}}P)Ikb_S*`M3Af*fXGzjbw0KMH#1VV6CpA!u_9eb;tJ6H|R;SPsu;!R;`l zFbbtC#pLYpD}d{ylk)kZY24`dMKkXztneE>9glW@*KG%XqDVF=g=OvELA?Fn^E3q+ zjH2O3Jni2#^Q$uM6`jj81<;IRJXPcgkxE-QJ3ttS#_x#eS6HU24U{9LSuTYQVX4}) zB9GmSfA6VNkym{5y-Er>@@_}44HKUEdEv!~_m0L10ia@20H!Ox2)1Glx$QfMZQ3EI zkuzy0iYy_WH|WJnNShEP<{ZU}k}&kDpU~u9Yri%Mn9?PZq=s;cdSMC>n9tm-hL8!Md`=T@J7-DnZKA< z{hR?zoxs3IOtf8C=L8i&@8NHnGE!DcML}ThP9dwH|43N>_3!;rK#@#2^SCv9MBmC- z#B}`;U+nH0y<=nZkIDq;^)O_Dfl1*9Ggrh0^QF+sNSoClE%k^kT;?F_xcnZS7r%ME zus_P_Ob3UPhMsf63Yn6laT>QIij&l1b49Zy0RWzW)Oq<8i$7bG-Oh2s{J?QIk2CW; zY@zhOdjlKy^t>e^ECsxg6I0_C9PgyN>iT{?a#=$7jJUm|X=0y9~MhbH6qde`!fcA)7c zLZUjW2vM$Z{`ndTxh7?9`i_v@6r7(`pzkn&L^V2Vdet={O(;&x&L_nkrK;f_#O7Xw z-?e@!SE_~i5C;jXoA6pw+#=7_hJB2?09>I7Tjw-=(?8Q&TXn#EfLA44h^R%Asx(-G z_@{{AnA=l>d~x}Wyv*4k=j8jFQVf+!2IsP5U#w~Z-7M^0=DwWW#<1-2+VR~*W`%R! z*eY??uSC1K-F7U!9J1}?v0Y-a)Ho!$dGWdBW>JKEvY9H7tYk{@zfsj|K=C*GRsJf*DSxu$#chI{ zM@@3EXp{+{Kfh;T)<~PIL2h3t8w2(!fPPo*>2-hQf4vgt8SYhuaF&x%U!P0n6aF-) z(ezrW^=%d>v$aG82ZwODjg@fEON)m)G7kP^B%G204HNxZzr43u|xOgez`JoJ%g=Jch=s&i&D{g?~55WghUQ^I&55 z7hSA`y*XS{)l?}|Q`7avQ;57Ju`W+)oS@voR6Ol=8F;GH`Mm9N+8cMFsau@y zB}e2*_?#QyyUS93$M5H&_k41?WA`0es3;V{?z<@gw&!=0h z#=H%4p)OqSupqA^{9Q@W@~^;^+Dd^Shk3F0LTlkcxfKr~xyO6nO_rK@vUl>cry9Py zCbR45`A4vX{=rd|s|tdMXaG}rT7buG(0LeFFe8_fAv*@g=DF~7i}Pp#oPB{(+=B_~ z&I$~5QKTl8)f~}Hl%s;slUpRN-ggK-_}%v{r?Anb(BjMzEW{-ld<>uwwTm9hKQnMm zn)Nw>B0@QCFLf#!K-i%~#*#f=yJ+kA-OXGBM{x_t>NkfH#0`(i_7}V{lK(pN$1h*s zb^>UT^l1yKf3M3ZuYZ$skL4XcyCFkR84L+RF6#XoPC)AwOEh`lo^=DGTi{`1)pspo zMbUWsuEEGGb9Zr`oek_99I?(FIOu}OU{I9~MZaWWMZo%DdsxC`HRLDB5o`}QiV}BU z_$^=4tp?d>0PX5AH=S59Clr8+A0cOQgqKl==B5{B=e&s`+>QS~}Ws?BIEihgn)5~7ON@-^bQ&GHq1P=xh-*lh8 zKGEVwZlJt=efk%V%^r}*Wx+W5%fi2-$PoZM;GK8l{GnJTD)l_JP)zIXN;0|_+ zK$)xPFYW187~K6?-pn>ls7TYKU)vZBKjPDG)0?54wcT?oa*j`vaCU0{Ad6;z>W(PT^*JY3uY9U^ExdJC^jKXQVEJ0FM@dZ&VlT65`cZ;s5l~)x=q) z^-mvEOl&4$noVn~jy}rJsv}QE1tfkOOkv1Oy_$(=uFxZH?XK4J5scT}Kzt^qKTX-Hw+XAe)SGh{&u9BvW|yoZ}Fw@TzB`Uoa|WgV0zI@2|hNRwD_QdJK2JFTpvoM)VXIwgDii zcCuQ?JL4=c%9mP+a3z0Mym%6~+JiY@=24GQ z@J-5m#2ZDOFE~?Qd;Yr2N2iD8$O;Jda=o~c7OA@cj#msUyZ&Hgfbotu)=rd4B|$K2eL9pVLsYR3-@DSV!>BkKfoU%kuWusY%pY z$ySFRZz-hgqy-#Zq}J;k=xG=T}hQ71CNep2k%ECE7U> zPORz;$5t9=A3f(#n@^_EV}_`p<}>i)W65t6p|}U)+&%iA_C6arCN_Ms-e|-u9W;dE z#zGI-TfW`+t4A~ih^E$?91$CMBM6%LZ9uUojWu_+M7l}YNj_7q!7`k%_u2FvAmyOS zWn7Pu65dW8k3HsLSHxT)j!d^2Eo`60&!%jAmugYm`Zmg!HC>?TtB^L)urS^VKQ3CM zSAkjee<40%{AxqMs>#Pv)ve8-@DL4Px|iLeZ; zK0($9q$1);q^Aa3=3MJ)5FQ$_SQ88jYgD>V?Ag*I`LpJn=saJr=QC;gVE`47H{5*5Y)9k zjm&_U?wc)&+{YWL`jj0>QEKxMG&UJz2O#c;o2Y+cInV7&C+%##l&Ioc8yGxTX5-7F zT1eUMc7j6 z0f&CSH*zy_O(zm}zwdbrp8vg!9nfGxl~dbQYE;DZRqI%z`^XkhbGLuT_3q5`LCvmV zHL~7=m(n4T3`yE9tS9dB-+(X&-jz%4TtD;6z#ZUvc3$t7mc13zDoC~!QAC9zHJ{kY zVoCu{6PAP~*<)Nh;|j|b*871Rgz#489zFJjqG3^p4Z+AO`4qA?k%mXLhyi`!!t`-e zgY2rAI#rXk_)rnltOG^VI{(PDpge={nAowT`b(u5lF;yt(u+HK5$rhgRuT~11Z3t% z9T^jR1dEff*x%_R6~DFiMVd)dq=&>!X{l;61=4L`>f& zvG!Duuf_-e%~q~17#8l?--q0&g_`AF-@~L}%tRYT+Nw&w?tdaJ;j^hr?xEB7rs-NW?&a1J%Ly{Xm+@%N z7*?vR$Z0`eF*~L9){f=YRHdQ-lG;M(yi!FmVJATc}!z7X1}$}LRuu0K$0%Df&1PvsNnpLjsjU7C$E_Sf>J z8w+|}pPFh3%Gjzr2R%;|cX~G{Aw~&oe2I8-7hnGARyI(-AhF-1+E&i45dxmcflZDd z3CA5nRTfj{7jd_;RxjN?4}cURO%;R1g44W%F0Tp*d#8G=>soZ!I>8hSQss9Dzr!c? zoiySrIQk=lz6mS$bE^K-%T%Qxsiz zZEU^}*QPfCcHU0rw&)Y}B zGwGw)=_to@#N&^U)hUBk7@5o@VzzA+$Sg>XL;TtVnSYJo>iBJfcTd}?DqL}UJe+fnU}wNTuxNCC z#9`@Q9lusWwS-nl)-Nrbs(#+Pz8i!!!4!@L@tz$txtIY53{We1iyOAO^fXhm3Se&q zA?B_7czUhFLtEte7|B!7(aEybONz{I#R|qNyU{eD0C0)Q5AO(1Od$i_=5#Wf>A9^! z!WgkfHNZagwsMh2Y>T#Qjmv3AIwpkhPQ#1_Rq85P^vT6OOHaNiEHB2;6&bB71#+fG zUXPy`8`w1(*DF;C$G!*oiS3Hs6cT02B9DI;Y^?S}u}$xjF4t#+`%Z0mGTZhKISp5+ zcyOE01R$6>?O8I2c7$CYmAB%5b4h_|`rF=8K(kADn5bKs&E1{cVv z0{_wx=?4e2ultAOXK1W%S#r9RA8{=>TavXru2|wodg*vgLYWy)Naq&Thn%}@lWhFF ztl@E3FYcJR8fD07C}}U?pSIXAvnNp+i$;p+69w9fzI2}*1ZgS(UTKY@YTM6#$6C`D zeenk6{+@iJ?;0LKd<#VNwzdZFftcK1bRA^*mZSqHN)3f8HS*f#;`;21$iJAtS>?Vu4 zywpXkls5l!#xX_ah)x^GBw{y2u~M!2fvWcV=xS{L8>o`e_%%~X5jcKSKpxz-R{a9K zvGJxH{>?h&|&DlgSc%q zHtPSf*d|0^qJrwZVqj+j@@YKZWSJ(uT2X1kQj55{RuqmlZ#fJHl0<11e4S_+F}*~t z(9VNwPGsDt*=MSg&(GU_xV}$3-##=5M=!j?R*VK7-+jB-4nvS6 zvNJ^byAj6EdGOW6`Mkpru+ge+zcVOUu#efR^1F808_`u*sxNlGTD>v8Xb)rbaj1i> z3hnAbBA6IsvKL?ibeq|b9|6 zv+%(`XF+ylNI7I9`2#+Dl^$*|AwOspUq_7soW?Ksa3tTnaga)@wC?mv_4R}_wXEzR7IK`Fs zH6O1!$E;Sb7d07w<7p9EIJM{2uFriFu3D00d<`rc)zg;uqB)I1p0xHs?$Sb+R*?k* zNgYF%Hp_Gm>3m!xZ6Z}k=hsKwNAur~xOsqwH3&fH(yh4Kn*##D*O{S_VDL4CMe{;u z(4%p1G9s%A1x=cnrHa3_*8SxodNfu5CzTqAkw<#te|)8By?%3W8+|TrXT--rI3+%~ z0w5fqP2*sU*dOLLFX9{5=LW~`yyRHe?B>sp4A08t93=u4aI_IrBe}?X8efiOsM(03 z^#JqV*O{A(w+wtn+~;DCzpIR6aND|Q@n0H1qHnjc;UwN=)`oLB@wfr+7iV9%1tdU} zV7dWX2nQK z`DgB$d4qb}&W}=CSydH-9Xbk57Jfwhj$LIYC?qnyAh$DGo82ec zpe=Qh=lZCD?=THLww`72gZ6$C#S58G3$@DY=MLZIC{joC=A6g6%oyTxk*sbXjrc!c zg;+VRx_;z7^Pb)&5Byx+iNV^oKLm=24rgRb7HHvRyGC19C+X_4(~W_QLc#gerjd*B z(D;q=>0yPb1<}Kk3zeh20~y-aYJsCG0VA!WgMF{4aOA_ux**UXnESMK{PS4!pQ!0lp3ZFns7`p zg08qE-n<}u5&~mn=Fdx*C|l?xyhJ^M`y@^=I-YRZa9f^m|DCU2@FDUm(dVrX0@n}& zA!q}7i~B!Fi0rMvFebuQJP9w>|9DOlj`6oWJ?KOFK1rJ)NjpZ5(f^c>v=vXvi}yeH z6u$bhfW!qkhdws1lLB2b!(o&DcN~SKV4m@>Rln_H=>G$VP~!$@3knoq-De-8)4p8Y zZ;!l15{`phhp;U1*B%!50EPHjAjG`M~Bt$b%OX)$Wi_SL4S zNe$2{J)7MSvwXg7j$CGVwaIG|2eeAgrZ!;9-kx2mk2~}Z$~vE2Dvw+B2FrY(UCNKy zDrRcr-fZJ3C;~6iwaECQ}lDi1U1be9Ah{;w3TQV>4LCxsv5{okKFk9R`Y#}12JMvWtcT5B7EzKU+o_aVnbOvf|p_Y)E zP*(!H2I~$UPtZqDa~^FU5LnduZVnP^(C-$$0}VS$j-C;~;TVS;`9P zF*v;kAT0vu5r_AJzo2eUzm)AE>OlgXz%!DclJI6hdyso>;3p}xe=Q2RlWlqT;DRDSqCFjYaaVHx zb=4dUf5`T~B<&#tt-yB)y7O#Bg4RHQ+Se*_ZQ(^Rci1fp&?sCwd^A~xq`F)RYUh;j zfWTHhr~`D5zAocVZGf@`+j9p>Ms@v~CFf4HCE0`3gARXyK0#tlL5FsZ^j`;K1C7A> z_6+M3a|z!A1jD&~wWWT6-8uttpt+*!3bsVqBN^at;ev`$8OW`vc*E?!8}J#3J@niM zJhJ}R@x0pp$R?*lKd12ayCmwN2Q{PGQnZKF#M{#w@N8*-%HfmI8A!E7fJG6`)S9Hr zz0v<)%SrnGF`Q>4+;@;kPbLWE>$-4D;3a!cBuEX_6|D-Ow5H|_w`bdO?4bmO!==Mf zqtBytdWZgBET^&#_C1z7xZetVbt&LclYI;g#%i(3&J{?0etMdkj6hGJWhf}tWjjT@ zbbe)9(>c5O<^R`}0#4xj#4W{ddI)S&wYVSOCaU8DX{Q5wgN`?3n!lU^)0GR$hnBBi zV2s~q>C7zvwmNjvfTN6?KobCb{v(;nJ>?cINK_`bUMH`gj-@+uGWSGLjk+kz7Vx|q z{Fj6OKUw8$A$2@-aJS^R^4>7e+4JdN%U6!aMh+!`=_W{Ov5V`tw}tbDd=R zdu@exikjGp=#L!O8z8A^-$0%}vEE#eNQnbuVFA~K6LhFs%`dw8nAu+{DDoowy z^86?5#^`i1*XZ*5D zTsq^F^A0!(!%gmf1ji^4Jc!vVY_rgj&s^}lz?f9FduhQD~t6Htj|KoO?@H(0=Wo7y0(xo?o?~84z<>wrL zHbh;^*Sfuwqc^)1WjwRl@5=D29lpT4_DG%!lTstE>XgOp>R+^$Sn4mmea2ZmRWk+G ztXT}ZmnU5KZJYmK8lCnTbb0R`*jB;_TcWuFMuco6biO52 z6k}R-6c`@1HfP%~H%asS(7f+g;>oiB11w;BrcHUgEt*SVPwISkB~DT=o*dOUsbgqn zM69Fy9OHkJ#88qdVA}0XIlU^5#fwuVaklDVeTv4jTP6{XZ7`n;^+s)Vi@s_2cT2ZA zDL8{>`wxx*d4K7Z{YCJEBGK}*16!8D+J+9uhhm_YFK1g(=!op5T;)E}|BpBzlAO)L zN%V(D8ULsJeafMIH0~RyGK6c>aL&D@Sv1&dW$48|8lPBlM;+N$oKG!-g~{12_Kr4e z2<5)#(4LX5#B0;ux4O&)2c>Ecv#KSa_0!!<*_$UDQIXyiPgRSB@FABA5+yrH zfpQ_p^W`YpGvbXGHl_+6GVRx0B8nGwc(Oy?Nvx%Po=d7hD)TiJY;UFv3c1&lm--AR zzU|o`)CLI=A_5Ho1pz^#g9HJA1M#01NpACGBBU7-MkXx$_aKR&dnCxuP&xi^Q9u0Q z!jdKPA-PC2jNJ5@-?3H<+_*|)?AEiE~k^YbB3V84j|@P`zH zf`t5Gl}wrrX_EX}1}O?~GO_<)Vq;?C)cnEtzczq}W+H3cmxb-ZU;NZFNZC{l=rgDc#m%o(j?gtc&FoU@7TN%P!$3JUb{$sI@rcrBdz d4+TK5e@p;|G)MT~^pY%70m%isI0N}X{ckfi)kFXQ delta 104488 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 vR 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 G-u^$zx^XlB literal 0 HcmV?d00001 diff --git a/test/resource/bundlemgrsst/jsBundle/jsThirdBundle/bmsThirdBundle1.hap b/test/resource/bundlemgrsst/jsBundle/jsThirdBundle/bmsThirdBundle1.hap new file mode 100755 index 0000000000000000000000000000000000000000..c9347d5bdd34865a9041afd0d1cb8f63928a756b GIT binary patch literal 44717 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 Ru+6Q9I|6&u^()ca{{wduORN9@ literal 0 HcmV?d00001 diff --git a/test/resource/bundlemgrsst/jsBundle/jsThirdBundle/bmsThirdBundle2.hap b/test/resource/bundlemgrsst/jsBundle/jsThirdBundle/bmsThirdBundle2.hap new file mode 100755 index 0000000000000000000000000000000000000000..747254f013c6c7bad054d686c2cb589c478ddfe3 GIT binary patch literal 44349 zcmeHw2S8KF(|7`*i+~MKkPuKnLK3PJTSD)>2Qh>IfslkGRKZgev5OVEs3_RWS@7(5 z_TIY(Vz1csEWiKkOCc2Rywkh?_xnDh%X@Ekc6N5&>};Fa7Z#{W(8l33aqu&DcaA$$ zo`lEYP%y!%<5*%bM5y%a=s=(C}9{Rw&mMmQ#my#`x%HWDp8M*va z9>)PvSVCbkpOwwQdCCA00yA7dWO7)BfX_+x&K61vi9Q^bBv-^C(o?uRuA~rWgv(}e z`7G&Eawl(BN;!FGm?4OCk|*Q*tHn%Cb0xxIe&01>*i3AJ8P0u=o-gx<9~2!Kr>7 zJ_)cxj;;;93r~YDZ!p5)Q0Vtn_!RuZ;l_uB`08r+1kuLn`ullBz*U5TraJtcdZVla zhcn9e_o7D?Tz#^zP`Kd0ti3vF)}#8FYh z#QXRh+Z}G1Gb+fP*D+feqny) zY{ryl4?iv2GwtA}DZLXN85@UQIPdpc@o#U3?z!~o_t%f!4%L~tG}*QDM~|?Pj|}$) zYBUbhsKVh7Pv2u!PSO1fm z>oQJmxFghExTyMe<>!6n@4LRN<{g;5EwW)4A!6_Fn$*h$w8@6rKbIHB4RG@{(%QPU zuQO#7!vK#j)oc!znBQki!%wMxT$}r#`ue__n<3k9JHj@re5iQWXTbT7o0|k?vxAO` zj&Hl1PcK&Vfd zYxS}sw+V}J>kkfCH`W9~u;9QD$80R@9h1 zE<7Ywjl{P|={g}XG`Zqx(eF+MtJP9I*6Ocb$3J9yAX9B|@8k0}W{Is%j;0gb2JhZ5 z_E|-fV;rsDuPhZU$#a~ZQ?xUN~2$sroNsOdaZN{(>49nsOziiyR3|09PFd&u=`iN<@V2Qtmv+2Eu{rfL#8>A) z^$GK!m3l_=HLr|t#n0YOJhixjeQ2ZQmAw_)&5s*Bnzo^v$CPax=#7vAZ*6;gLnn z_qA0vs<0M2{i?I1A>-uTxQh-kYadjTSl%W_E+70HN@_l+)A=4xw21a*i%YdCWBJkj zefCZytc{<4II3b$(7Lx;7OW|OqnfPmdX-vSaqy|uyRxyj>7v_yl{cEoBiHOrQ`_)M zdcvfD6;b<+4jMk^e2=wuvwAEYPwW%NFrRqxwZr)&J&Gqipd@R1-Gueqme)H*ueGN{ zccv`Q(LCDZX;68=ka8fP+a9$6C9BJNZ3x;NUW|q^2O`Yi&KvZ=Y6

    T@Y-q0~`_V?58k{Ncs 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 h7TQg2xu|8W_Lf8ZRnWFHYl{{T}~WNQEb literal 0 HcmV?d00001 diff --git a/test/resource/bundlemgrsst/jsBundle/jsThirdBundle/bmsThirdBundle4.hap b/test/resource/bundlemgrsst/jsBundle/jsThirdBundle/bmsThirdBundle4.hap new file mode 100755 index 0000000000000000000000000000000000000000..fd9201f1b896e4e03af03cdc620f91514e8e4ccf GIT binary patch literal 44413 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 literal 0 HcmV?d00001 diff --git a/test/resource/bundlemgrsst/jsBundle/jsThirdBundle/bmsThirdBundle5.hap b/test/resource/bundlemgrsst/jsBundle/jsThirdBundle/bmsThirdBundle5.hap new file mode 100755 index 0000000000000000000000000000000000000000..62349b1efeea5e9ffe1e9f84cc4f31807d532586 GIT binary patch literal 44719 zcmeHw2S8KF(|7`*i-3xtB7}ef5<=)r(S*=@lNQ7f0t7-5lF(Es?;-PzgM+1=STvo9i8m7tBoY2x5A_k1|U zAUPS2!y#vaQ^&EyVva;?&*4i%MfM_&Sdb@TbHo%bKaErP`6!AL#Su#c0v^$ULUnXN z9{=)%D20Dqux~>2bXnSgjOb`p=`(&4+!4qPxU0b35?*@2vz9DeAD5aVj>+VT(&%~o zG#Fr)658@C*sx(9k&CVAggH8W=ORPl{Ct#W+%oy$RWNhL9Z z#e4Z2+Z`TR(<;avYnV$r<=Z9&j^nvzsI9oHHJ7t;zkUxZ0$V)mSbkks*Fo1VzcRma zHgnR8$Dfw$nR0OBB-11(`i4Ol&IjBYcI(}sJ(oWH{^rTMK|0eHr?_|g=oK;IiBVm! zM#Er@Djfds)IAm^Ro!TvsX7Ziemz(;t@n9C=-hV~o$o}ACru>kx?5Wgwy3aXxSiCj z$vnCKo=|uGf~9vWKkqI7t@G=pyaO}0M&BMxh^iY}op!m9I?+h`*YaWUeLeh*wYF^O z?LsM`8{qM!noW@s^M~{)_(@BjuE=||^!ncFn_*jVJ0doze5iQetMB=bn;HdXGeeGw zj&Hr3>#x%NcdKLfn_1n)1(zHfF+Re%DwS@0d+zYhW@D?=fAji0Fo|gzOUk5epX_&0gj(oECYaSijKlK)7F- z`_d&tJjN}=tvlGaW&}}yXm{%RiV@|JeF?{VJ~k-IrcArmWk^HL zn8>g=H4@(3=)ZgY z=ob}@PVv+}`&lYll9xC=ry1AYn+!OLPZHH1J+ph){)eGnr_ZWS&Qaxghfg|ndvWOf zNMmnd$^2n6e`%!R-=+MDyFa0vvWHQz@m(SVZ~DUO?vwZp`l@55SLthOcF4Gh`xv0V z>V3C!20dv@AMWjSJlA7LAb)~wr|y+;`^&o35Ic>E?AB~^IGDDSdZ=@w_KdnX`sHIlQ#7s-H2gvFOTPiPd4hGX30{fGBnEzVsX0Y0s?Wjg<~e1KGoKqw z2ps)>3h_zy?$r_Z(nG@RR)r_n(Z(+CviVkwl{;xo#HXXZn7Q>jKJI&LPCXCv*Ez8C zgn7tHJ>$8WSBAUeXKo{&T3Eq8w88R9UBx!@>tncDAX-?x*m9B30FJGNm?>66? zKI>craU5aC)nqnPD>(Q0`@Z%)!)EI^j{0q)ny2cK-Rv+oie7eJ=GZ-U_a@ChvY_dq zw#o(-)+p1dD_(Q)9~M@va8Uy~!34}K0OH67IH_<$!`Kz+N}b*Uc$h+Cd@q?Q{f#_^G?fxH7U5H(fU54)Z&Vx-%`CR8%%pHxEoM;qp>`CO^$WbdcZyx>K#A>0 zS(dALw9&_)@`4fNKv0)GYJH1Wmzi#ynpC2;r1zaMC29eDyQATYi&u1d|K3{QXEMxW z5hvbcO(ni^@+;2%z4taeO{Mjz@#{8Mb4k<5+y)Qp8cKJs=MOVY&eZQTDYGr1fTs6

    c3@CM)ku0YmGR|Aq|erTgF7~96kI&X_u=f>Wh*)@jXs+-5>32jXW%{@0-tJT4>1Nq@%(S}bnrLk}W$LHAfg4Rtj?tp+u8Srub_x=HCM-O{_4UV3x_>*uh<8(G$F)V? z_`H=1_EuCFQl`wzJjaZGM6EAyZ?DMxTDR9|W z-`lv-bHlc6`eehGukd?crrzek% zAEQ?LDXQ=@|NY?|Lv(V50at~M9!*bgG}&KzG^J>b{)^$$X~8kL{xQQIC0>?P4$s(l zyyDsKqxkz?7d&x|tlBwd%%Tm6=UgMAUCa;8yj1MAcURnk&$f2>clPBg8*lGfV5imH zY0-g^l1{r{?zTMkV7~XI9_N~l8Bzr*Yle~dt9|mKNCcNoB}s;~-v^jJ-<6&@DqeeG zqDuddJ!sV#>(j=TX*TWCt9w=C^CWfmyPz9>uSSx)jqb`ETcm$*rO(nHZ}%<}-nuY@ zmU|?ma!2L%#EQ?vo<~OxT~~I^D0cMB4>cEadYNtA^=egYP>dnr(Y^`k?{9|AxM2T| zX}*m|J6`vhs8@Mn9kaYo{X72IoSL&MHm!Cd%^2v>7(GL9Ca$t1XwS=kF z&!c$l$}QVBk>_bX2pdVYYL;}H@osF)(+%D4dVd&qf5MavjueAeHDeQoom;G>?KtRg zvx95&s^fia246X@vg7TC^9P?#3h6rYgrtHL8Jn2ZS$J-ZN&d+UCY`naMJLmXR;1n+ z3C@?^tJX|@W>>Cj;$_b4>k)h`xAN`IoOzD=Hj^EWjA#8MN-z9Y&;uq!top zhiPss3ijI2_=fH2KwdgHIM7w2q?7T>9ciDQ`IZhNI^WW0QoZK4#J1zw$^)hP%THK;`K6Y@_ zJW&&?y}M}?U%Yv$Va}4CJhOSJnY+Tf*{G@nuXvt3M(~H}@`+{Pc58?2%Qy3BwA*4o zVO=bK_m04=hU59w`C$PjE02yhZjuCWmu8#ku2}dChKcHDM_*hMDqcHz#hZzn%5+Dm zc=jECAo_LTh?Eg#{WXGnYt1|Vy?-el z=P|7=usOtD+r1)>+EDP$)8z2`u7SZDgjvJuHW_$v^t^Sw=(*P`Ey-oJT^8XjOcp)V z?!_YHg^gN9u+ezsef>AvTK3pG!EpmeFACpc?Yd`Kz_Ov!{nPf{-`Xs=baG{fo9l8S zK7RBlduIJOd#GOpj;{7w#MCVo?0r_|T@DQ!+l%;&p*qmiU>L2Z#$%1>Y1Pvln?izr z-%lN$vU>Zwc^WC(v}+c)NRD66*Sz`8>2d+}`Pp4Dv9B%Pf11C3@SW2Q%so20Uv=rb z%Vl8ot_KIq1G*Ky9*|n~+m?N7{6%O%Y?$O|T8$Iu9)-|;B5j%Y1?BOfo z_XOv@6D;eRx?Qj&`xdRX;X#v`Tm8l>5smZaXx}JcHod~XzjCap|FykO=;cGMH79J{ zwb(|rLul^r(Mf|7=Uf?t%N|tfVqgFM<$7LM^4!R(DrQ!4Nscc6{)>LGt`2kJDEN4gN65KPkQU z_|5vu!^f}4C0MTBy0h?s&c-g}wF|nRE8XsJdUm}#d)svek#N{DWR2mb399QRBuW~i zF68ldicM6O2uDvmtbcg#6pHVIT*<>di?W^>tF9C!E|DbOSTvzN`_P&o$(qD#hZd}w z(tL@0n3$g0rH9w}!B;v|mUcS7eLCxD-RK(|G}5TOjW$Kp%+Xj_ODz$cP6~6*x6Dpr zgioF1@^PMtY4d?mm-^OnYl|XZ-1Gl!$NJ&3##EZEe}MaxRFh0)iypmdjM=E2{CPOn z?AYYA{>LWo38Hm<-C3t;ftt?)eIa@8t8Jx+UW|D1OUI#;o1f{=a_wfir%}>VrS!hT z>Arp$9tB>6EeDEEuiZ`MTqra4n)qUu!RO`;i{3mQ(e<<*e{pk%RSVwCKfOnHS)7KX z$LD5;8_W5pVrNXgw4O7&p| z4h+4o#h(@DvGZNB?(6OiohQ>>t1I0OoU{xsiu5~VKia3`!GaIFqK`+ZAM8!<>gMOk zscW8&PilxC_b%+zZMEBF<7QmywJmq}z0ln|C`}J}wh<}SW1l^Yxt>R>Kg||C7JeYD zC>Zv9C~0!GR?pQ-1_Z4r@R{&Fd6eekP6oPt1_xzTOfQ+Jan5h%y=5m7Ze|vE%=vYq z#fgkbuQLNi@2qtzGpaXQSJvY}oc{xY`_3(wXcH!Xh)pWGurEx5Kkvo*+=VCH77*N4 zZjL-VsWvmUqs8z_cQeYYd5yJJS1!ynzI-W5GL>s=Ch4U0?7hqE!#>3;f|k}D(>b|N zWA)5P7k&D}vuu`LzY87S#BUC1+Tqr4FZn8N>PtN3pw*$7P5mMqZk6{ryOZfHxz?lW zus4qf9r_$&93v?8&C?A`dhBYn^aAQ&JJ?6>d=bjVRj9EQ_VUbXA1(!a#Jh(ddVEvA2+KIxZj|Sw!CsoMv)gOeo zi`9yr6XKmiy&n3nA@0)ey_7ZV)p5h6+546{8(vy#Xqcw|c=2YD@%=*$lbr3#Mt3pn zAF_Gl!AWOll$WcH_By+>OV;Y!jCD_6`P9FxZ=${k*b?_7ZCH-+?ZT3Ag7E1x93wQ# zZk9Su$Tqa0WzeSRjGs}yT4Sh}yA5Zs;82sMNT8t~$XtDVdI=q*^?0iX>ctC3-g!ou zJNu3IN#j!iH@vLh7HAFXo5@~Tk#(LzPTqSl!Sq4cc;TH@rk~?i{AziXJ80LDvpQX- zMXTKpiF*1>;{J>1WZ$zUzU6``8@m{VpSq(vU~7lQkqb3G?x$@GdQ_otF5_|X{0%!c zZ{BWE<)WIMM3e+&<~47=7?Q^=T5CAyhHCwVgEI|Y1Qo_h#OhhMhdx`oHqgRl+ta5V zPHkQO@NoRWEAdWqhb^vSpLn80S(B<;d*TDZev75#p|8!|ywH(zPpveyds3h?=*Emu zTEZKf!WLYP^*cI3BRJ#H^pYHnsj3G_fhNYyjgRMdxD;i4!>qqW*wl-)xD|_x~Fj25XpP7pDAsuUbY!^qz$+JreVS}=YJaTr?`4*KUmL}5+r2UL^Ii7#6R}5i zwJaBF-_u^2e%oShpF?#g1Vw#okDRkO)2%kTp?;NB!=gA_pJPYgY+q}+GHl-B(-s>& zIe(bkSReb#nAns0^#uz@?ijv$h4{j4eEq77liQ!Tt$#al(T$YE&9to>j?PY8z=-U5 zXvSmi<)epg`>bvVxb$e3V@%U;o14P*_D*3QnKG*PrrOgp%I!aUpQ>CKQ$0U9Z)xyW z?mc#|o?8<)^cuH@aXNPM@aVpyD0sb`QRB@{b9{< zO`je#_~^We{AIk=oB2;>>20b^J2pJIEAK|fX490NzLHhLg1v~*P4)a*t{&MdsXT+} z9&6@x`O>0{qW*Vgj4aJ~r#XCEZ2$46bGpy0=;~XoYtnPNPLNa3%Gzq1UrlcnXa90) z|Ei|48%_23C&uVh?|t*DXj4%j)8_DdD^o)EEr)h_C-koICXN%#P+44flex9$#a)Dp z?zL%&>qZXH5w1|}9&H-_!rkX1*k9XWWI&ufW|Jn4;o9E0ku+F0(8RC*=B^?77h1mP6#)GJ|uEOkcCDTg_k|{Y*^dCG|1X9*Hje zQN5~`n=l_zKkM{3QD8Zy%GF>|7w6tEUG8P0TIoE4m2}WXl|9Y8^EBF?o%&-2eptEn zoLz7K*Sib+jILenWOCx_!LZlAcJJGJISe`1Iuu0v3Vp?+jr1;6yj(h)*w4M%CVb-B z%NzT1CIoBNrUs49=(zmE1T-YNA>7RkfCaAkte4_oLPmLi9~~ zrS2glmQ?zAIHorAs){AO)c;sC-OM7N@wr>zF!F@K{T7e2Qkh&Ip>@W8z3Gsrr!odh zVkQlEFD84XJ#`o}!fYa15t$spu&x+&z^&_BgyT zO8wQMy2*?p2hBwt@lRhZD{3&;(_VDiMf+%-q1MD>ugi)w=TwhR9mVSQEULoi@sf$h z`f>n1e3c*J^4;~@s<&Pzyn8F!=iQ%n7VrOh=5vByr;-gT^@HoqtO1_mLLZIrNw_vF+Ozbfi+K=j=t+~xUWT2c z%r$l#UD4f$#`dh!QR}IulcfLbVZikv&Kdo#_E=Zk$=v+7X=6W6*KRk@iRwP}UdeBm z`m$H@f`+j*=JB1D#+cZ~-(P8F;Jh4$;lb}1`y3Z)`3v4n9~q3(T{)t0f$xgrE`FW{ z1~zEXi*0kT7kyIEz=W$Sy}M0)-Rsa*yZa$;p3k=1=|4F=dLH@kFW$fX7PrQ-Y{2zX z`$DS9PLWutIRP*i3#lwRI-urE^-90>zq&+TeC{88^}(CBmL(ZAi8DrZPnuC4JRo}F zsV6yOH^!`Pw60$)z4J@qx z=v?66=Y&c$^QDdI%&MJ3=4tb~@F)IGE_j7w2c?Opa-H-EBW~l#1Fd7Obt{tGZrXnP z>ZrkGBQ(@?EGkF$V~4JC-F#lOw%orgVRNs8`vPW?;@S1$#wyKg8}qe;uTMIWQryRGlMC!ZiI5 zLU)7nivv`-gpPw3tzW^2fOTv*6DeCHrl$f&Jm>L@i<}|;!vW!J+Xk3DrB*< z=>ma7ED^DU+KL!j5E_%oAxhziY!*9{qZFFY5)rv*?}*3aq=iax68jN{7JDgx6c0o> zE)gd;j|&@Ya$=MqFq&W;sOIAh?ShYkP*bd}>k_8>8;W%S9*PZ@zUNUX#!HdGf`Y07y=mXRvIxA?bH z6Kq;It(*{$jv~FR6jF%}X$`zy~SkYD}IgmLSaJ%^f zUVV|^7wx1y#B4y^w(Wc^1rS4AK8KjWkw`cqMRO;n3q-_BmMBNSFOoA>i52Z7ng)r= ztCqElxnv^R$|uXPw`sJ{z|Gr3BxoJmrcE@haE#*=Dd7gdC{7 z(M36_pw(gCuOHD0^dhhVO0y#N?kx+UNCeTKTfonVVP&*I@>k4}qE<$LSe4J>VCRc|4*}T9vpQXw>O)d~%7;7q^SR*%Ok$ zx*m*&#DYu?ACN%~(u# zB0z1D^TtM&mwxSb*cgh|jiDv3yG^U?wa5@?G5{q{!r2B@PFd}hGNK=g&OeR`E8$)9;tj2yR zH!zarHLOkBXyKLP7d$Wr7Qj#q8mg5I5~$WFL!b);vRTRooAyeCk_MEM5gfTip28ax zaI3;d0>5N0VlgEZG{P{ZV3BNEXIfS}`K<;%Uu}BO3oxXt@WqBp3IeeHfGx-ovLsxo zk`=LlE6F7C1$;YsHv#nx4Ojo7{_>UUuQW=Vs*AWJ>yG68BVw%-R;lI?`zs}-r6uos zP+VCitd)2sjh>_^YQ#FC=T|X=VwsV0LHs2ih}^0%v{wVutfjet`o)5pC4FhPbfiJb z2$irakq81$R*6AYNd&0DQ8HQL@B+TP8>FCNn^KJS=n^QGfV7E{<-$+7mVHZ7)?dVL z#Tg|^fc6$*gn6kvE;|KkQ)Wtv5>N|7%P2_*i&j(#ex%@{1 zcUkq94M&t>$O76)P-!IBLIjdRBnrj;%l|BK0841!MvqaZv?&&`?U7!h{TI`{{ures z<=RlJ7%oa@g5UFN-;z`7q1xDs{XaoJYCq=RL#R?*^FB;%A`xLDay)@!f1j;Hz+n!! zm`d2c=Miz!97G)v=Fk!@TR!9inFymZVjn59znr*}<$z?Rny;u*Na$%JQD=!XUZwh~ zmQc&utC1*q^DnC&_+S+)KSi9DZ66RGZ5Pc5MqZ8-2lVG|pPI+zrP(1JVX-|7q3p1E zmdKvRO|_S%2rCai5;0l`Ns&rgG3dgka(J>N`wKyV8MK*`lKc6h!iCk3|Cs7l$OmB9 z?WJh#IQ;zHLS9}5OnQEJ3K&{DSaIQtp%2folV#5idPA5UWr=&E2c$^b51X(5NOq!f zk}H1Oi8$#T5r+?@_>UAFN-KxO=ca>BxvbEja`ZB&O+(5usFhn9M9OlPRk{Os1^XOMT__p2<|I_)KO?&1W)|Q)DuwwTQ|5N;Udt z()y1p6vm7{uLl^&*NYEj1mr33rM132lZo|1OeXYHOeX58VoW66_K9*4r<6vL&GgmZW^$45WR# z@nmThx6T2K52QK5;-t!#fxpT+#mWI$@dT_#i^lda6DP|bWvx|v3VBf?B7!1Mu$FOc=Ac^M$|LuKLxJfutC@0 zctd7j-;0~UkK?9EGQq>mk%}^qClN4O`C|j4;$k%2`Kka?8r1w87JSn<^MBW{;J;V; ze~%3N8TY@O13#+kZxMf3kNTC(@Q)tWf zO{6Ou@{O4m{RC3W-X{rm$YD}1+h0U`)ai*yue{@D)6_Ys5UX^NU8tLCBDeyFS|p!un^Vqu3;5XD7e z2`49nD@Mu*NmkNVibw#8XChd`lY77{R_P5U>~NHak_X^Q=Vs)Iu;o81R0-t~xj8T? zSAvvIPL({c<)+*`j;Kh<6IPpYSQ3FU1sNi4ni7P3P1PzH5<`125*8?fpiEd)TAV9-LK@&v`tG*IzD+**> zCa#niD8(q%cEGrT_+o7?^=^SD5>r74W=oTjW?cTOlm!`ie}|2VoXJ{57)!{tR^$OI zG1;cF6w*t(82;@0z{Wox^w1=nG-7HIv1Km;EhDuohe)5GXGDv$u-R>IL6jc&6AG;c zG)Q8jLi)iItdxT66Sh`Zo)coWV>AJWL(b$+bc|6<+)$Ei{fOl0L?+1&6@rx@l1!J^ z)85`*_GqtIWG0c7ga7upv%iajyVDQC1*=pfKGb0`qFvqt0&ZDH2T!Q0gPVXa>xST2 z)_=g0v=N{O*`hQ&$_f@?22LTa19FmAB#lOcA0L_*{Q7?Rhy{JaPy4Zze5GlChyRy} zv;{-3WU3F1M)e_Qz%9cEAbcEr(Qhk4v3Cr*fI*`bFv!_-8ZDcy1Wo2b0GB~#(`anu zZO>57s3N`;^IyM`i-4RWA2JtiTp3m5i~t}pfSdzq=g`T%G#W;zDDY3nbp%*PI++SL zYD<)Sh72*8L!)s}^h|~lW$-8~A+i{9C1#Lq;btq%ktjfx9NZKv_EKClAD$mgP9mZ- zoD5m;A-js<<|?6kc>&pl`O-TLUVzapKPZq!4u@FCGlI5Ig~~V#ljdU%n2(10RTc{5c&WKG+Q4Z zj8`%y*~ZXl3=~1afR>cb<#C|t$ajCiM=EHdVAl%#NyV)NnA0ftY%17eAZOlUaiOF& z!*y`ygHnxMY&5o41aL!1(zS7DqQs%3Ob(AHfG1J__5k8aAmXJVk2vh1xJ`K6hnGa@6Ahk^~*yzcgN01tFX6>dZ zmqhaPKm-LcP!_(}CxGN25cS|Fxa}qZgeq+jAPCqYXz@h*1K{ZZLhg(05Ab&;OLqt0 zF-iKQyg7hmW6Rcn6b9`KAb;t;0Qe16-WGs&v@OtfR{*?ay8^AN!kEe_$K9Q9IOKY_ zTNSXq3uT&sU%*p^HOx=@88nE%^mE(V0JNBQpmCFeV?XU@+E=&yX+OhLwj+}pSxJXZ z@(s=w#Z01-J(Z$zDIR{>&nU5?9VI`?Px~3PE(nsVJ?8whpZRG&gH?_eo1dTdGuV>c zPx~3nEV{)6`KSHNPx~3I_6Kx7?PoxSDuyA7hyN=3nJ=e*nK``wUUQm1%g#Tj64h31 zz3vK$fG=ESs-Na;LIAp?%e!_Mpj zZ`iKo<>l~6NP!KaWaWt^-1H(JhzNod3x_)(kcG2&U_ccJLIrJPli1QQh>B@pk|+|c z1Z|}&5(6~R+#%S$uLG4TEF>XNB)h(5*x6b_$c5Kerx|~yRrt+Q!T(}Y&Tp=V|D)uD za~7Vu~dwe#$g?D3}%xQUbLlTEU+!Xr3Yv46BXY z93B&l7;-r$B%DHtf~0oXAqB<+DaIZm5$XF%wL_EtOm_a9!=NKo{*$v$zQHE-ADhGc zZy%X{bJz3}@ITZbwcx1Vbzx9Mp2yrds8HbTo>|0jk<|3NGI z3Hogu_-96&^3j#dyy$9i4)4%?9OG7!!z;FsX=sxtPecMm_Hq4Cir+u5WMSP2W8@72XT`Ge^XrWokR@LQ; z>clThccli*EH-?}UMvuyV^x!^q^H3m14^(7mB2z82Q$(Xin#f(4{w$1rHys~6vcwuX{Sk)Qzk;DfJ71ZOl``GJ|@ zz);y~<8Ts`;ydm{EZrPf&x5l-B}BG>Q-~~Hv2&26S-_6bm1clU1T?Z7P>2yc4t!`H zWDRC5Dn+Ce4-6l{T9C+r&plv9r{)TBvAjz2(%KKLNP?0RQD)5v+@~l$dk-ngLt9t` z)|bBUVGsqEl$nIK-~loQRu&+p%-U0to`PjkgH#2e(h1*kZYz_6aZ7P_H>_#EI%k_g zlz&J9sK*kKnY|LR)26Z0vXO-!Ixf34F)hg{C#aPFBoq%>%@36_fC#68vDp~EnNgFR-N#qN2K_qVI~xQB&X}C@eml zJCD9wAq9jli?H~zT8GsKIibiLwD`vwlFAR({L+*(;CDgB4K*ANxjtZ31H}fXwn`6d z#kR@pzgW3~rDTNX|Bqeim(;+@C9=knek=zWv;L4VKT@6e@mP`Onp>K?^FM$Z_H>mE zWKm;;RAlROU=xdmTHs+R`DyL?f7#kK7feHQ>B@$j?y+F(8j8$G9l~X{!pgw~5KP5_ zh2ibk%DUSE!U8Za1_ZwRoIkUb#X!JR8MB*3R;VaV2H6p8brly__tKS(Yym>)6`7&> zqgVmxM>zm2Too71Cq^l#1@f!0TR_@-BD+Hl-RUUEgWh8A+a73(A2PXZb8&nmbh!yI z7~2L)jiLdopAR{jMhlj|GeUq+Mlj$)2EUQW;8y?!zkUdL2nNX@2h(T>3e1GzDcBc9 z4MDcJk;q6IGaznd{tNA1VW9h^00qhM7v{QQ#KQ3*8aNzsIye;^wgmtmK!YPBaX9$V zraHOfgid$0OUJmZnQ0h85zJ@2J2uzvm$lPoze16O(6bZ{bnXNc6W~4?04u=F0=E?07I4SFodtIR+*@!) z0P6`Z8Jq|lIw)ZdxIN&mgZltZ7ka#I;OxM8feQyW7~BYOBf*t}8wYL@xJBSrfLjl4 zH@HLKPJu(cW+OPr4o0^o+_k`IgVO=m0UXL-M{p=V`rwSgb(h@{47$33L(hdkdk?sy zcq8B$4_G0~aF_A{4ST@5jJgH7Nm~K0gwGb z9RnDIPpFR|JGSGGN}(gfLVr*3DhY7j4ke3~&%$-~2@j134Dn5YF9@Uz^o@!R3=hMpF?{K<{y2Of&MX8} z!R%#c)!M__izv-r35Qp^0HL5LL6d$g#tUcO4u;SoTFW6+?Sn*dqz4DYpznBj;W~#P zYVCP2cD9EPA;PSR?}h86P=_6Z&@oJEKrQvlyVV5Jvi+q0yE*~PSTR+QC}&?QnqS`a?-f06fPjbb!wGeX?TYS znolsz-!~}Z2kBUl3wkI+I5-UfKN^m&k>J$PgFuMufE`>c<28XfaEM*MFpM?tEu8| ztKsqQkq=%Cd@9t{@hj9-q23d)SQ_A0r%o{HNl-I0GEq$feE2lfF4CZ7z&~o0=tAuT zUFhBm9O`>eyH@Uhpb27q5Rwb>ehA51d0&LY5DG*65uPZOi>Oahg=YkhM$wD=FMleVwqD}$PR0YrIXoM~}O-&@R%st^paUod&l?rRWU^Vb8 zJ~+IGgTD93{lAPE*e~|XXa-}3=-AYOeflt~?nRj2eHyk=bslKV8nY=~}yK%c~~=>Va9y4hJ3on6%~k zyiRT=GZz`rPFNJPZtZlQ8++Dq=(f09!GgvJ?ZY>A^x3dt;?#*92z667?%2-gJiO~w z>d8kpRuEPlcDi+HLH^SHhFU7D^Q)rEJw(o$+n@6u>EfI1L^lg_%%i$IdY;Mku3_#v zt4?y89yz7_&VyCAq7Du7IevMK-O!;yNuO$KI_BAO40k+TxV^f=0p}CPj;=gbwQ%Ew zA|u)e-c-{kFYuWuEFQHyGAEL3Ww7$t*`3>Kd>${JccSD{*$Vc$XtO8Q)8ZVr^j+JZ zymVat#lw}%Rp-_O_MCL=wEMH2TS*V+&zoGmD}3qBk>>+Vf;s8NC8vGYt~hsV^1R`v zx*3}Jhi$F(?PB$y=UTVlXQ|^{#!=OFgr7XucS3bfAw#!6d-R2C)!MFS{QTaliWueo zyJ{jv8b>vBI?zkqx!|O$XNAsnhXvDPv^(ePJ-n&vWNv+FgzIeWPA`JiU5kr5F+R^L z?YvX``cZS=23SAQcxlvS>&5x=MAPZAdz!TVljZ5gy5Ryi&zD1Fc03TrMd~~T75G0$1>XK&X;X-w{ zV|j3>4o=SL=^O`lBzZy9r*S1kaDY1r7BcNpIj}Z}Qgn6jaB}u=bnt+awZNa1j?@%A zk*6CKc^AV10;YTfCuLy^nt&`7^p$xWJM642zz1i;aCqp8oOT#RsKZrw0d%X}u;II% z+;sH055xsKbkTkN1H*_uzELrOet|x;7+=hn$qx+-^a&l}<3mg3WY7u%>9mYMUskw} z{SXE%l%A21o0**z9uXPIpuzMs)IYS)X9z8bo)I>XPD_ZPWru|WhN#E_-;4ytz{tp8 z-vUVl+kaqQw7*|bYMe(NC&o81l+O02ImG(<6oy8|IMI2j*_oN_9Ebc=es;z{|ACoI zerk+wR;Z6J21P3jWwnKhjHef*`t!09;-iGAj?Nj8RNsPtOm48$ZGDAa{{5EM8`p3}X zrTG-c`1*PjB*wV}Cd3CxQXO4f0{xGXmym}17HCWQM$MhfFx($lgN z0>YeK@~QDov;bD2gJV_%JEeLQ*jNv$uRAZ0 z8WW$8$PdfO2z3w(^7B$Tk-4-OfkR+HEQ6MgC=ZAZ_4Q}a;xgzlshJ`+m&x~&#D)lB z^PHTb2fF2@`}(D`0wqyHXyF)iB+Ss$-F@k_P#?N8tsnq#G>RHdrziOOMMw%od6_&W zpB+Vy6bGdhuoH7b@;n4#u>&($p|k>jAD>+R=ul@5h|Qo!(ikjQ&Pa?5ETjcVSk#C} zN1-z#Fwb5nX7WQq(?Wb08Idlr0S-JW-8sTPlg}Xp~nq8}qq-1~vI5>3^@CdWHm{1b& zSv*p4RjK+jYN<+JYAJqCm8uGi-3V^gIlHMH)HOkLp6o|ZRR#ITcF>_}sjJ2k)H|#A zggJDfc0w=Oopr*69DacGatkp^Dm1AH)XwS} z7#mdZGJdGyHB{+1Lfk2pC)<{9yhF>~ZFpp=^_;bSZX1jbQrgk0C<=W`2q^=iq z76os;(QD|omukg}?fj`75r7^Z{|AAfs-iK1+7rEZBy=ToImUXlt9nS-`BO7~9raZ0 z)7unXd{pZ)Q|02Q=_(GmHIr(zN>ht!0xS*aPb)avGSxSBny+8r=l$vF;#pho&?l!| zPk+-;-P|xy-F5KiRr4WA)#$7tw?239q&>Av4pB27w|Du7aO!o&?Qy+tM0Kyj`>c3m z`RfuF{lb->#l!F2)%z9d4+HAY5n27wYj7Xmnigv2cNU#BwYRkB%)VB1=)Af%mB_)_ z!Ck2mVXyxpCHYkSmdc}MTSCB*R8w(;P}dtpQ?hkO&U>L7bnvsa;5nO?6FhXAozA@c zU5^tI&LquUJfQUVE$0#l{^LXaX9;K0m#wL4-j?zqW_gE>H`rq)U-maxQl@*ecG=<& zDTW_8Lt^3-3ny4$dO zxbQV+W?5~Vl~~a6MC;O1&A?I9RHy}s1y&9x-W9CyuAF}{e$(U{tL54gPj#sE+-6!f zqL0fE=CVa5b_>oQ5D+Z5309K1DpbqWmgR!vH5M9CU6xL4u9`p%>R-h8EzkF!aB2Sh zdCkJba-(LGr`GUe3uYfZ_&Sb9pr$ichD17}ZQ1m7_wxbV9h`lv-M7PYXfv?U#-fDRE@kIj=RtGf&1uH#8i=wvnw)?O-e$9cIGxh6v zUN^dyntU2_Gi;*h-XvC|FhMdgsM-HYG0J+>)>DouF4b5u z<pt4 zHu!c0ea5!pE5;@_J@)v%!{u+dlzB?+jOyaOk>>LU4dR8dokv@#nyoL4iM~O273Cb7 z-)-KNDyJmt-S={o%|lMEe#H7pVeXvqJFeUBR?-IVfSa3my4kgQ z#Ni#k^T>ySHQn{^(cV-JDD0a_n|`?Gc;2m7Mg2C;{MA6E{~57x*@s~RRH!{|M_kER zHqidzaV_6-bq{!RPI{iJrq>8f8t>_jDD=GGGzFJ++o`8PIaTYemOb`R+YTl zYMgbSS8NuLe2r4d53=83V(^+%*m-gNmiM^_l)42KHJo&O(p^jBI;@I+{5dX0<>G#h z_dS)vBy4; zVy{qT6;t3F9Dj=59@~(TBFEvLeG_`vkP=H+@FjE%`=6qxD0Bf(68(UAe@(q?H&%xI z3-lMBhhAO}%k{|hX@!2`H=#$Hv=kvf1L*lPzT37!JqFY>{+e=R*!4BC=fCHo_B8$$RKJI`hw96- z`P*V_d)j^rMqcPwF)E$C-xgonv-Df=-E0?M>y!1{VrzTkdvvKJ8yQj&Fl*eP$%gU2-*brnY*RU zUw1r_NFbnKLeL~|rBc33YR?zRatiHp_)>9h4v#OT2}CLUg3m`$o^ZZYCKe0H3>w{m zfg=9pAEFfg69T;ABBsmB_G3pxsN?sjjZ*Ws!LS4(*41@}7gbVEXNmNYV5kdwm7 z6{QIIeIbP_ktB(@S$u-091tNeBlt%og{F%|{3Nd|iL8+9&F9K;bNFOtvOp-16%vdI zSzLjLi$5i$@TI&QfkY+{iwMqurXvKbd_oIm+9z|ReETeZihye`;E6>vi71VrK|r^J z&}J`Z;&Zh#sH!N?;cwe7M-?AeCd&~d=gQ!fW%3INe}K;(i2HMVK$BF)70Kl2{s141 zp#F9EWWWvux)%7(KMT6F-k3l@q0d+0Q}T~M7#kYwqp#Z?M4O=R=gSU z_3{z|!8qTK&5SI#@^pToWZr=pdw#lpli}Fi&%-jo7RyKBa@3TpcrPIZSo+XTOH!oF!5D=z8G<*(dt*u#p%lg>Jpx2H?r!B;Q6 zG{1Z%ebVzszc1N6<>1CirU{O$4TI00^SxPo^WEUx7k~fl&Et22^`W64m5r~JU?zS+g>c;Fy*IVfN^TEPtz0Z+?=Dxe&bUS=JWg=PM#oBU+MTIrH z-%0J7^porFO7!P1sJ>JAdGF{C9bZ)o56s*eacc-Ee9zG3DVGZ96T9mEJi0ixzpIb2 z&Xz5`ooS^kBO~={(v=wIH~%{irk0Q*Y+;I5xkYKJ#>@W$BOs8`k(u>sX=Tu zGw^86@vWD#ebl=DW_9e|Yi_r30j0-=j}LXKN@f|~nmg>X+1M)05AL6%{h7uF1Q*>M z!*6#RVzK_2%-5wS^K(xlGxmmgVRWru?Jj8!DeU(jQf8^o@P!MGW-et6V}_k5F)ZkO zAjG@erFuz`>$ru4bqD*`3@2-lxGpi}kIdCfHM>m8*_FJ$V)*E={-onQ9~l*9(xzSQ zR8*feCM-BcgCep>?l>+XB&p&`(Qi&ht2L58tuS0&BRXVzAVXuJ>G3%mGNo20M=(jQ z19z<-^}M3NF_zwEKUYmh_JUyGIOFPjlR-y`2|0B~f8Din|AQd+(`Pg%XQ>N4LMENM zwK(Wrn6ZbXbbj&7pBm`IcS%1J?oAj?+s&@n_%5DJG<|M$=W*-?L-jG!s|Sl~< zC_Hv;&A9B`f|;o^=^cl;871pHu-58I_b@vBEY7;u1o!wv3Y$2)%$%kX-sj*i=2_(q zGoKkv@Ei4h3i)y7uGOJ;Qv-wTR)xgbF~=_JwE1SFl?!D}=MTh(wv5=YF+x>yL4q{ zUBCGrtXXG6$>T`duO#v~Isw_w-uJif89ZChVdRI28gA-GcJYGy(F`(k)5q?%yE|$A zkp+zpbk#PfaThx6*IRTe{p7va3l7n1A68SiUM5E_9sC?ZX*{Uc{=P700sZafzSZii zrAPPm+B2TCHg4|W$O@0Zns+)D+(`kY4c7PAWfqqmysHf^Z!qn-;Er$Q^@hT=VKQxi%xmh`?orc}dMWOp=Vamk7f@84UC zy-kWu7V%?E)>INJC%@$H-+On%lVoO}8t-m%wU;!W%&vE}uAy~zfA%2VFF;O_~r}OGuyUyKJ%MIL&V5`R~UF2RTG7o;Bd;L?ip-m-~81HT8$Td{cH|@=?j0 zk5|mIbbilw4VEUXGWFTAC~f%zUu&%x%c6RR*IUMf?-(`gep#n0N5UqZy*7EiL9eVQ zS4Y&DFdknmf4=1X=+YZ$wqAXVrs!FQk){yeYzdFuQa2^Ek+jSBPB&sX!R^(!c&j^- zlXV8K)sAe~Gb422xuMx!_om;@F)25^HTPDZQn!AV4aZEE7k--YYLSJ(;E`|l^)c*_ z5qfU9#iNdDEJu!-A!|w=#cjZ`S$%zMI59?jw2PUi&1icKp6IL`a%PCdna)OQ3rELW zQ3PH^nd9~@bbXdkFeN2tZ3u1Z@43+%O-+t5BkZo_Oj_*dFZoPbctqgkL!5N)R%ln@ z4ZZDG7kLnKS1#CFQDKy&F_)e^h*QE$xUtyWh*I9(_UUm?A7bj{5dkMhj1{E&GS})I zdUd+qOX&Jwy}&+pQAiLgyrF%6dM`t3m+1AgX6a6_7!=`fd&rHwQ^p4-5lL5$m4`yvc7w!dGb^mJ8BK0#iQ@%?H^eC+kjVdUsd-!->-%^>gdb3`D?C6X%(J$(JO7A zk9}#r^S-*?#+7axwrw+{c7E}axc7OUWkE`h{uet09D9~_W$bVgr{B(LRyWo-#;nzd zb=y9EU*X(~Z!fgJQzc%X?Q78Ia6u)RYvY!<&ow-Kd12MaRH2O#@z&ns0?G5vl4FHM z)90_4P_##_dxYeC;O`#}Eo~g#C3Z7$!OhFB*wrrGE)KHr8Z>n9psLyj!o5dr>*u&u zm<$;~;Xh<-N$F0Vt+{ZQ$*`TBqklKLaYe7%#Wg;bd34fi4rkfbUXd)ZX6X0(l#Eic>3E&(Y{ytkNbvI?HDs=(T4c5eM2Lh%@5AJSkiCr&X@(CZS9Ef>_@L` zxV3wMolbYhMF&R6I_!F}%ktR$`5qU0oNYYTnJ!jaQ%n)9_RI~ZkeoY|CUj>0HpukZ z&eZggvAPT6)dqg*!CaoUK4omVcH=&SJueGAA1Cj6=YQS%&mZojT$xcW6g!EUS?Z&zFZaMAK97oaNmT~ z_cwxOoVS0+G2bR+9^dnsY*2Y(9cOf(x_6>8Sv6-?Y+CI|nGx;U5HUmiYfNQn;MuKO zy-x2g$&I`F(0Jjv&NYZka}n;II%)UC49v+a`6FJbeoed9mQo=d6aWxshKq1Ha_Pj;`{F4E@2C&ts}67zZ%Fqdj{JFqjqV)D41?Uudk$Q&9hxh#u49hrE~ z`Fx%8&!rrl0j?!$S8n-b6Lp^U{ooOFtJkt_Gv1Aje6peY9gmOW?oF7o!GUJXx(y zKks0A!HUxR0?Fy(d-a;hPwhtQo4A{E`nv`k%dUL8BWs?6q0MB*kumkdSr1-TZp~W5 zm~*MIcCq16?xLk90vd}}@2kCH;{A!XVPn_6cONv`y=^yj!I1o-GY`slbx0}pOJjCl z-fnnGU~&OzcChxw!T|RT4R3gE3~Kd|0KdLkr5%i4Y)|?9saIJs+3BWMqxx0vCARI? zRvsubTy{!(=O^R#lBa_=jeCEEKIp>5)w#sGu4lcnBZ?%uVj?eInt7wsq*04z1}EiK zoui+B?K)@mj;l)-m&xp0rk8H%pGGYpnjDUtbGGxal0>z>&qrJ|Sh%h1+A!n6SG61% zWg2n3eRH$czxdBd4%1_M*Ns`X+$>@%)QqQ%OcLK;x8xq@a!2PiH#9A6YvOD_4l8fZ zEf#6@-}UPFw1x)v`jtK7D>5wgHeS6l=~mK3&)5UK_(|qfi^pX?4MQ_KBJ(-Cd0%MbgbvJ7+EFDKwjxoW3)pn~l0!z=~&yW5oY4T{f{i#BOcz zzC1I}2D>fx6V^o$cWw9E+IhTad0w!u$;zYSjT>dYg6d2&{S^zJ!Z1~HMjob4@A5w7@joTY@k*^Z=IPZWh*(yt8Nb(T3UE^=<(0#?M%|OdcKc$ z-7)vZ%l9v&<6Nih@p~O;uj^8gORvv==Vo&FeHXug4U&vudo~%l^9?-o-C5b!DlMty zww)FcEld_Y(Cx(~2d9YZ7px??SPo*QHw&hSoht%)OYF7={_m@?rnW7 zzIbwFyBq7WLO*?SEq`kLD08TH1%ajUA#~~%3*J5}^G=6~$MzyWWvfS<8Wl5pYCY15 zn6`YHLt|jTZ~N)Pl2-rnZk|@sHr<*9&a&gz^0aTfbG(#Ke|BbPWYjCm_rK3yKjil5 zdd_aWT`xQJ-{~B^eCPcG=DytuUJXjF`mkkR-#HUTyYa~>)2?;_P87Vs{5*zY{O*lKhK!N#;#vZT(0eC>g|HEe~U;M5L^QH9(8}1KUB{uJ3u0OQ>z7qpStiD%gMSI<-pS)?G_N0{hL0acxO*0cn_M2+w z?2Yz2)UEfSL-edCuNRY-Ew)o%-EZI964R^gT`IaBoO>x^xo5;L2Dw-6-&xY_^SK_U zuM8gYaj;K9YVYxz4VQ(CUy)6+T)lNi!F|1rov3RUbU$163*+?cIv3uyYiu&iPz)6ngKjn?h^mXf3Rz zmx@m(1UuzfW+t#hrcQGHG|$BJ^?{KW`_~F;3&Wn@_4%-U{jgbMD$Um4C;XmJlSt>~ zJbc*@xluRq^Du$gvB@a|k4@g~&+PK5qh8|z4bS_A66)TU+sY0-AO85K_CqJXerhiS^ybm-n?mD>fdN9DYXk*9kMt2ya~Yd>v=1%^v+% zx5jO2eBDELDr1AjfuZ+wM6+UCcf3o~f7QLd<78If<(2&ooU{xm4D&u@KgzTH!TgUq zBaVk_9_-EP($CwCzvuOIVnTiFxOc&)ZfV>qA2;J-uWi}G?gs7JPHTK1v<*#KKKAK@ z$ZNUGy3;(#Bgsd~iu~edLn)Ipb$YH|GRS{LzUPGZi6gZibuiNJGsHimVtVOBt+U=U z?=C$NcOyODb()=f%MH4jZVHXF*lb}CaBr`^ z)V1N(sBMz-my33C1pLq!lEV#!wRbrukDq-;S~F(#1hz$7#brY3f_T( zS)i@QTiw?zSvcbMQ`+3wZ#+&KpYpx#Zv8f2XK?>?-pY!Mb2Mt=-V1T2_k+hvZm%-^ z9J}IY%PWGxJCB^v>ohGw<6dC+lczG5pK?z2KV#xGT0CWAr>-HVZtD-)+OA>5Lak5x znH&8dR%o3~dz3hT!}iUaf3c`?R?kcz%ly-GUvIt;m@6n;+j;PH^}6#1XBs{CFNl>% zH8XAveY$q7pM~?bCr{d)+Pdt);n;(hV;$!fFW$pD@mPnpCRxAs#7C0-7E9R!FPl5L zK_lj#T4`$cIA3q@^%)~|B-b|uFSr!teRQ~1K-$CUrCC~2)elnqOpISQJeuF`Vz}{j zvw;@ni)l9RpFf>t<~@MaI6fv>|B6=7?t-O7viIiwH+EhzIYN`dJ-K_B=m`^1lVV_eJa_bD}VV8q6yKV4nFy{Ko#G1`iP^97|-XC$r4xSD)kGyPc9g2JT1 zT47yF#C2DG+iJgVb^o4OuGjCax)e3eH+uky8MMBwhvpqLVErdv2In`$zLA#TmN?A zqU%ZVo0(fT9GxA%fF0KJ(2PfdOGgjg@?2f-d-35;hseecn;Sz6_Dg1fw4J-5bh=rwK)`*hUiVG;dD(uf9GBgdPKT)1P! zE?c{;epbAxG``@mVe#vj#^3MPd+NOj`)Rz@oB5At8EmRdIW{b@i|~5;*QQB3ykx72 z1Ki0Gjdh}0fdSP$VRRbDCCbeG(#1t-g#&NT7*Uq?PJ7t4sDa~8XLX-h(Zy@IzDdvN zdj5|7D{GhA{A_x&B=e_J`&TuVUvI3-J26IY`QA4_=WHtUDu7<&J(gdPxf4BZ_6hOY&ikhN2agY z)~#lUko9Y1@f}xlPE#wU;&yPeXpu0$_v9!h11O}^4Ood`4v+q3>mO^ zoR!+-x=@{8eb$>6Jvo&&L>4(|(0eJ>J>>~w%y6@bXhmdlDBHSX=DdiRXGiREfuT<)=x9yX^v za}0?6I#fJ*+xxxSpuRm0Zw%LbxoFR1b|FK1QG4Q(mrD!l%?)%Hop#nex~H?w#AC0@ z3$^DgAD=vu+wEz1h3BIs6OZ-h1ANFTZ_=eZ>$ff6dX4n%ZO$g|(-pcmf66Q228C|Q z=p5*;wW%vrw{+Xt9VaLHUNIWI{mI68_okg8`n;O?jO5*+bi+!+fIYvi0iF|r9uD`6 zyILIKR`$Z#+@Cr0q)BD3&K<+ewYDE!(Y-5^=e9>rqo;;mg5lE#zSoMJ(gs}Vv96?p zx%qL^h5>GUyWKdOv*-8TD@FBFU-U{`P(QZDJhnr1q={|py_IH0PRn2z9`KI6&tajC zkNDm65dj4KmBSkrc&#|@?CoY`WP=vHcs2)nu_hHp$6Z=YgCZuLdYm$(*a@(#T4*FQ3RzE21K$_rQ6?1be9 z7HoKypLb(w?Lh8o55eYc(w7HVQ-Sod|-TS1`MVHKgpzTRpa4we=wq z!;TZa%hPh7$8K*6|a-zY}bI1a; zcO(?@Q-W}u-xQ>BM1B@4ye6n=^-98M5T2n>_u z*SsshrKtZXZ^EU26uxXt15;xCn(;}Nr2*z<5 zPIzdJSi;Yd6*kX91(nGc+6>f@(mZ->Q3r)~=V}h3>{uilww8h-CLeQlZhk1wm_5? z$xUm4nzCe~v7Kuf6if#hr4GmZSM1Do8@{4C_A-af5^6p5{ zKO)xRuqu*69;i~3j*g=5L3!nsuvXz2o;^YNsuAnRZePR@gjELTg0wXr$lRGWD8ZFC z*w8ExhLF(bgRP`O|D%DsT>Rz35tSVBgfo)pTzlMkz&A8cLMIMSLdsEr0EsYHB@H7kjY(C+J7*$NXCeRmp4Khoeg- zBWz^88*uFJvy}`u%mEii1^c($B5s<4sw2Z3S|;ErhJ2tCVRT0BgEPDJ#GR@Dq^d~1 zQlya5(?zPz5?Q?B_Nta3Wo=0$D&D-c=s^r7Sb0g(luUcykO;d7b^wZUpfS)t7yIN~ zfiT4m*$7MRVF+c1&9idsg@R;zyhK=e_@0Q-LP!#>X{BHbo6Hx=iySBc17@&hPDmW! zgBVYkQ8+VMqsy(PljG??^!_YyF)cCg|il0qMzWhbwm9rT7UJIavu zMmNZib^tbC|DNnb?@3|!ZI{DO<>&B4@D~4(SBJ{V;)(>RU{fxCX&@W}k%}Jhx7(vR zO}@MZtpxN>OTn{m_DWUd1%t#a-7z9mgone)ka9S3@!@dfQjfRYt*B4!H)k zq~ZwVUAy8DZ=IG%yW*v&7ADuS))*c+WZP&Ih1kfm!)hg-OHrKaI1~n_7)E89d^*uY zguJryA{FaqpzYhtCoi+4c@1EEfY%7ildM<<{vzv?D+g5N9k3oP8r#E6oT|8$w@Rh# z;A->_`h_pQbga?Y!y+j^2XmB^6x!R`sDTp8-tqj4aZ2yxT+F#U!OM!@4o!VHTFGhI=NI3LAf zV*BM0A2z1L8@Wmw_m2n(rb)OtQoc21D2IZP$Dz1!C@^pUFm9Ga$fwDW7gS#kg^B?n zS}_nyeEq-;GGSg(7=TKJFd%UMQjJG-gLnp@YF$A{aDoJ^mT;dSzlBx{US;@S4kZyF zniwDlL*7?-63!2ZhT6c!mmp0PBS?{@LqtCZI;udfOw4W;kBy8oyUVi-V9{By2Ym6V{e+vixxy9I419!!alH3eNWjz<0f-BbuhEj6D zC$>YI_@r9-;$p?_ zpFFz_O`%Nx#T9c!k#7Ag zf;9-Lgq0PXugIOz~bvh-cX1b!StoDQK zAuG22iK`%cK!e&LPJrC3LXNM6QIMi_lNCFiI2fKAEg+(RDke<_>qqq3pl*06=s`)o z{h)-wv_xB)HFmK<1X(ihW{a30rvc{$F8(delN6LF>#Yim(}QfvtcAc{WCH;vHcFak zQdsttSzFPd;&OGR!ay7&Ztj3_1@Xn&9FJ~-CzF#w31;F&;T2c>RjGoUyuZUnWzFO* zBA6=?SS#y*y)pT&G7jmkTLS;=`@qh>2n^9={1kF>A-QQY0<9x8Er;ND&@-adS=jBi zw;6ineE~R#cfE$NcAy)IuPq(32{Fi$G2lHO&`D^rdD&*;y>A7n6w* zn&bBe%4ah9D0@0vg)+F6zagp=Y9(b;ZQ){z*C@wVUL0JM zEOuA^n4Us!rh-I7X$Tdn;7RQ(g-c%<%iSHwF37{LOn3lBH~m40Olk<^LXn|VftM0- z8#jE=>$)CC3)(NsUpI>`C=wGQ$xOTxucElZ(Ty^Pq9U_cp41>FGYCs#qclhC z1&9F<8iT|WNMPD}dSbkiGs!lR$z-DpGB&iNRDqBWO-Hf&3o*E&35Q)Ph^Le^*I$k! zT{7vQw@@%|^0-jZUjl}U2#jj%q9U-pB7hr8!I#FNiIRs>()mK6815*(*bS&FagHzr zMZ{n?B`r#PxMRUg2f%`Yd7Ew-ScygHcAmj_iC-x1UfGJfOLsyAl?C3Zoq2!81WL;i zB_+l49zkg+n6+7=LK7*<0~O@QMpbCNPXOgXD(b;eddp1$NLAS)KoGD)&=iUG2OyFG zTCUap2gEy3@!bKqO~CI|HwTb%Y}y*YVbIP1ipTc_Aa1DYwg5b%ZGo1%0uU|V6=*IC zS6{KnE{+5O3cZ^SMpKamZ0|yqCSVxhhyP3qub&_OGe7)i_&@w-S~~3f@SpiJ4-Pb_ z{^37^Io-5gyZhlkV~<%|!}JOH-Td&M0iO==okA0Kd{G&+YyyU2$L|3$}D*{J-vugYV4!J?9o=dV;K=VJ)L=Yx{3SuBaAP z0KR%cgO;P>n4v5lvny-{|2-Vv+7ue_22e6yDk~KJZ{s>vCsmg7q|z_4yb1W9;Ww1s zjNjNd68?QLZ?be#Ze_Q=`FpMCixzPIhpgXP^HLe}_n7*pR&g}BI>}HKZI!qD!<_qj znREX$dLaX;1zpTe0k>IF_!Pm$g9O(0MKb&agN4I4xMSf3;9_CEzvnL=dm80Z&tOgkU&oo&>9?2#ez&|WN5+505LfJ};XaV?;tG=_rd5rqcUB{J}m<>#PXPRtmIk}BjEu;HjY?94uhhV5Em zZkC9G?AIVmMy^yQNGm>R?G;KLX!z(Xe(V= z7@&y|6k*%G3_4v>KtZ5LcYVpRv$=*)D6cP0Gyce^@T;eS|HZDHUoD6Kqx6L8YyB>& z0-G8B?^hM@w*NtGfxZCO)O0Z~=s?gNsGYY`&Tb5aLf{F(d{1H8(WGybDgoJIA`~ft zJS+0)f3{$Fia;=|HVSumOfh1} z6`YXq3uH=?+F%C`j44u#J!CR6_r;Av6aPqe{+Pp{BUS#&*(YD&lKPL$Vg9#|OuxEo z`T_VCIPkst@g`mIw@3V6T)q0?zxnm&S}9yQ+B`4myNr#{GS~l!q0wJxML$5ljsyS9 zXj3t|l6x2Z&vjHx;mWv*xhyuSgK;c2gGEC|vB*y(kg1Fn@d%}_VbfR;R@YjM9Wnds zuXi+5unf!+u!HV{ez>>&aBsuB7=O68;Vt58+}p6tTYRYu4xxo+DPL7rEUJ@RdG6x= z%Um9O$zCeXLC2~lSmCF^BL7Kn36;S@8Xxn~l;jBVU?1Kp(Onnq04R&0AuWPV1Xg09 zNyS-w<##j4){vm^3zW|_m6;PD4G_ZQPwr|cOV1JKV;_9*%E^Hy2@2U+gS3EZbCKYI@)D^i`^jE>80PE1pAss*alKLO=KPV+-?29V)YFdh%%mtx`%641o(W_40@ z4RC0;VvPjWQ!wZGd~S~Dk0b=GSpY6<{Q_J1AS=Zs8GTnoftm&%LE(zv+Z0$*^HtsU*x(0!OLLcx{YVAqdYUK)+lK=ntmA0k^ zRxXh@7XGmu@5N2&Kr^=fEcx4YeS`Quf2! z_5ZTBYc{xsX0ucsIbEW_*)<5clQKf&zQU@>`H)PXT7F9rl&qO3pi zmBm27RT=Y}MP8_=Og7a4e07yS@a|=)I@tn*$|G_^^+CCO(I3?W@NiZBn4Xa;NllPn z%-sai)*aOaYUsj3Nv^CWf8Vx1o8pkmZHph@Q^r!b0E4rwAMO+lSiL=|5lm));+Y)? zgt7ww7jpOwLk_=UaQO8`$OAD*HZ_3BL{Q)+40i!uC~F|{#SKGF(wGBrGxuL;_euxd z)(R9f$Dg?C5+-dC$7&G>DCmKUCbk6tA3%c>Bnbrgqf2*mA^g@i&;4FRm(o7@je8f^ z>>l8;b@rJhq?JA>lLUH}f@r4>aKV0SGzo-WaEIdcA&`g!@B#)OP`Cm(fdf|qxK4*F z9C1Ksr$!(ghnop-9R+|D5N1KBhOh;~F$iZMoQLoZLJxo)1R)JVF@y>T)ew$AxCcQ4 zdb_R=EFkoQ-~}NLLI#9!5GF#H0%1CYSrFDi*aBe}gyRs-LqI*|V+b!GKy@&>wc)A* zK^KA^gmw^6{n|r7^)ZBC457RHieS*M8w7M;fM|y+$~PSD)d4G18RHF*4cB%AC=QG7 z1XmP?n2N4lH_oNN!}qJJP)@^~>>AKpcKC490X-VnX1ruZ}^9#rF| z_)H}{dTS^i=Z6I1(fjXCupnd`qFU+_GN5FHwKZ)BvI(b5Sr#6z328b+v-bVr3V$@< zqK$5}P&@=wCW1s)ErND`o=^Z?yaz$EKYrC^MfnA?lOp3ny$FUZ^j!cjNr2;aXc^o* zE}^4mNKmL>pjQ%nK_DsGD?Gw4B$%MV_F_f(5Qu&Rav+$3*~`zWwTHDAIIGq^2n->Z z_{U(}36wS=3YkrZOt}**+JZ@E*sD0vP`Xq4t$BqIfn93v2vF-9oD5pSh-Z6m~O;C#tBoN~XYVm=D&aF=oprtbi z8rWVhK@*+YEs_!1;Uhx2mqY>4V?)bGhhd20U*@1nLIUF{p1Ml5ri0`X_a`NAO4o5kcW2yhyLBK|Cr8^ggY+BfAP`Nce?+GwbRuYLBQ0X?27i=4q;o*5u(k{y1m%$d;;Zy_yShI3 zi9WKY`nqm!2{{4VP4m(j!UILdsR}E z?YFJ_ux9Iuz6bj695ONcrqS?41ASbpi6ORO2TDw5^}nS5+mMeAm#Dg=(fLbPPU9>d zU0AuS$Z4DLp{_?8{Z~6@t>UbW%NTqv&Mm54%Bl6P=6-WdeY~-~Ci=|vsFTOyPck?6 z<|bUYxr;L`vplQBV8G0ITZ=4-Fx0v6azXKDPgesLY4=u*_G|kc$nVI$n{{N_jo`|I z?lXS!D(k;!e87`TZNj@i)`T4$*%NiIX;FD;vwt~LI9*V~zgUt#;COFY#fSBVhc0)& znIL?TJ<#Mf_4g-}0^e);+GWO3>^!ykZzgRt=-|3{vB$w-lW0Gu^xwRm9vVKkyq#>~ z(Yw5MV?8z2gzjh7yO*p9m=LzBXZ6Z0Qj@_esL$`2^!3VKzoU{r@bc#6)ArTOGKdtf zG4snV&U*HwXP9fvBEw;k4Sm^pS~&V-To5O;+r0c6QWC*^>5x8rRdky55K%H zuc%^8RbjltCQ4- z8URXq*91zeDkD80m67f!51Fz<3o+2z;Q$iVBS_%mDM&-W5hS3^>{4JEEk}@?i|G#B zsDmPwCLxuSh93q88X`AW0Oz?-oaqkzl3iW-cFw8r$EmM#ik+)7-NlaU%BM3Nol;Zz z40OU2tf>f61hPUnqnrYZb#}>oSW-eI_GP#_I=MP9T;cR6i07svQ#>~m*^iE*OJI_W z8Q8#SP}rg!AWH_DTp`~MJ5LJm!SN@2A^Pg19YzuAN|aFm-K;h|_%@{=6@AhIalsD# zSYAGU!DLUb@JK&zKTl?)7Z%GA1^M}T1{HaFGL!jf%zQrv#j&Hq!UDYVWuZKu=-db& z@51C5*Ia(2S9}nQ=fh+~d3hEDg+)5Dgvpud>AWmPUa}}NE!rnKog+$)^vVeG^unN+ z1wq`FP+_sG{A3?tMqF&TB-z0!EsXA!@0-pG4$AP#56WN`0u7OV1tF0^1u+mC%+4$b z$_Oe@#$~X?L1EH-&oGQeAFq6Wc4UTER1nJ#rz<@ukRxhQW`R#6GZwF>G}6nB^ z1q_FbP*#c;TP*bs_lsxnW3viE;))`CI3oZ2pj4@EdQ_Av-OEMjM~{q+ix&lFr3Eph z;=J5sepog$Qq1tnk76@Z5#_!SL0&#=W=t9@GC4hmC*X*@Wl@3Rs9Z#fh{Cd+^L;}?h3q(%Q;008C?w7w(D1~v950c7 zfq#*YG~J#f!kPqpoV$%?($pU1ss)W}P#dJ-2M*>600L>1RQQ&2E^6}>l$wO6qR|rt z+Bme{ECDP@!@4d~5nwcco!-h%v1^u+kO;5<2M0?69!aJEQ%X4^u8>kvRi^orUZ&Qc zUPjzqrLIO)QzP|Tp0$hKPE#9H=g9#ib#>5>Jcb@!M^inDq}fr;Gnmnd-T^)6cGL@z z@I}7(2X-0V=v`5)UPnWfSaKwvo5ir8o1-N4j@?z0m`%fKvL};n+Ew3yL3f}#FdX3O z9N$&n$(7;Y$dEtMCErK{ole7vu=)}aa8d?ZQXq%pN|PQ(@2IJTu|bU}=Z88`OPxg^ z#hg-mylvUW+sy1;osUelp0n1w-w6F#X2b_;`|O`^<66CG(29O<)X%&)C{nYH9B8)t za8=k8oi6*PIh|A&jX!8SXGu6clx_y(^t2!u)4L4sbam8LN|*C`ivqS@?=^JW3yqS+ zc0Tm>2*7|y{11twuBJ7d-V;5yCv_opI>vptb9qtlxl=QK9{EJ$_qR#<#PH_tOkF^r zr>ZdsYbMp`lqDC|_*xpVo>cI+rE6~NFyAoW+vE2qi)U@U&6=EYE%izT5px$MCb6V)>-}vgR>Amq+XZEF6ht6bcAw&!(hKq_2VUPbJC3$qi zCgIVrEhP~s>d6FBP~Yo?Q!@2O%zLiyfAF)l_!*Cx6)<$0o!-2>osZ(;eodIWcu?7I zTh7Lje8va)%#zGxEnQRfdRx-R$Yt%?U+0aPe96aXNxA-w+NFy>CUySU+iZN!b+S#* zFln6Muzp%TjZ0YcL39HoC>@dDXwcQ+(p-{=nktgi)y;6x>Tbn%2_b8Kon^IgR(yW@ z6V2bAdK!VAqDIe;&$nWnc$dGzqjLU**iDmbtd{9cJk_q&ZJTNN@IKB(oTZCQ>=v9m zASPJ|;;dwI)##S1Ek}zJ*H~zUcdDNFx@rR5e_$c|L$23dNp;@*d9Ue}*&$O3FD&nR z&UV>JALCIPAV*w~qq}lBGUe|X(43Ng@$IQ7BZjl1gQ^^%$A3p7enEuH7d$&Oe_dDS zwd0OfC*6O@>}5r2=)UmPS=k8BniZOF*FLxEe(b_D{aO-Q4c;mcAN0*6`J@v&_f7|7pl3TeJ6%j?_>3%`R#QkIrqToZ6I; zzaV36Dz|1mjCwkO&R3&nT^sB&Vz%u0PwU^ir6;XC)OSI{F2h3?IyRJ~8iw5Ujk-B@ zc(?SeelO2G+S>WdqYFl$tPX06^H;j%EDGP++wSA$*fj@c&NQqOx?k^7X7c-(8^IHE z?oQ%1NaAD@(~deVbiYDllo44VWF9aNplALouTkEkHlK1-3FyYkDTj_aLr?jjMWmZ3 zA9OSr23WV~ni(lHIg@-twz=f&7N#EAi+1rI_rFrZcSIVcuoN?gic!*9e?rJn8G`1 zWX*vFE8-SKkvFp#9yOX{kKOv%ao=bG<>j`*di^d{KYP>5wC5?wK$9!&i4ZjwnA&=B z<=F&Ctm;d0LhAx(J-`}W(d-Sbp38^U-{8HjjI3GO&LH3MdhhkMF&d|xA1s(T*KCGK zSQi+k+yV9A2ybqyTs@@U+I_r*dib}8DKOz;sA>lE_;2W_KOLT29dfIJHDg=JWn+^Y zuDiY75%M-%Oh2XZtNP--VdnD(4;BXVoJLuxo2@U1jJQsE8SWI6*KOYAD#rxtUH5LV zsycq_@Z@85%>#b6Vd(lwN%oxa+pp+{#ddH0uJ8uWAk2+F{kre+;fJ^XCZrw;&~`Dr z%Y0KgsGxs3bNb<)k<&g*dPY6y`tcgG3eQwJjG{$g7o5%3; zWrmU?1ZiZJP|V9DJ2{}V&;X*EF52-$8xgP*kv4zb@kAJupkSihsYPk%C$}Git)-ko z<)^Hr@Ffi}6Zm`-LA1m-@wwU=G{!-Jj{QYY=rUJr(V9#D97Fk{rP7>m)65_ zJqmrAp`Z9w=+X8gO(IGIdj5#-w#`tF0TYBjryMyieTi(-5nUQ+R0077<7V&ld=qY! z6TV@Q4y+1Wk=XJx7m7DWAh`J|No<7%H*#z)v@H*uZ^HCjU|X14A3xuceJu}^Z^9@H z`XWY^UPDDjI6#*$}l}73PfDsakw1jl0lpr;bZX^|yO}e+i zfNd<^|NHIvbf5Fw_c`afpXWM5zi7r&L7$|6FXsK;rLruV?&ZYz(G}+yo+GLDH@4NP zibs@QZ8at12tBT$U!wwPA4&*eUN;%JIx?uEb5xL1-8rW-f)*FD_BY=6H2^jD&BcYB zrUD$3?i#!mFpGQqkXxWF^;R@lLq>S=ciq!K3XxVcjgi_YPm;~|K!d9BGMnHWoaFmj z;4wttZ^bu;zf>SWYB$g>T~`N06O&_R5L5 zxeCwHj!i~pU{^C@uK@WX@Xt@NgHW5WzO+BX0;I|n15WdHp2Dj#7XragXgOAL{pXtl z=8GQ~JZ7$Y68W&bZ=Toun|W482GgSoAm&q#03lTM3R7OuL$xL+mw6THN85_sZtXjX zRQ-7RncMCs`*n6pHq4(63Ir+^bG|yL(rsR=#mJ!pV(yKxq2_5S0Lh*Ctx>VGZ1Jgv z(&v`y^qUJ0@|AbD1Kq8I%*Ac*C)!^52{qSwhK16n)3#2zsz`h`yfb-hroRfKbR_3r z7O(tTxR5swe62pOydEC*M|WDs|Mo+lKRsC&=zUir8goJzjhj$ux$ZQAZkzQH12=3u zB_M6b^G6-c&Fg#iN~QmrMtZpBB`3YmqBJ$2rGsopv`kS_Q0UQ6P<-M6_$VkS-gv(B zb#ixgaC+(a#xpR)!P_a&^PQ`lbf|Q|e}QPjEw(Q15rm~oD`;pauaC1(QsxCJbeW6Y zuu*$nB4p&fnxROq*ZDk4NJsk`RdfjhC1vV|Xol-%+S+EO+Gb{E{ZZGhUqNf`tnF;C zT`Ja=W62TllaPC=GXguRz>Mk+_l1+4O`?AJt#t>My$39{`Hia!7mMFg3v>R_DwgKd^rn{RUJxg}CG* z1c6{G4-+`$u$K&gePu5zatgr&a+pE5a}%aP`r&F&q!Y@3VXd^7b;cRB#Q;g{Z{fX* z9^od)LTh;?&{_=k!-#AyjqU{2c3G?lDCkecAmEBBC^m#J^hWhB8f6AkL1kW|IHoeN zbRcqO|IXU<>@vT8I2*Lxt6?x+9(w}>A4E9FV!fn*jNpe7A|w{5pfjqL!P}>PP(?nt zvMU2C3o0B!sB;liK*-;5+$JD$M*k|jesD()D+eOy_0O+}qg5G5SE0ZJ;`XW>A+De7 zg8D2gQZR!s;3BX>gS;CDMHR4aAlN8^UriP>i3s2(Tm$*Q%@R0evDZO9YYBTkpu&Ct z(I^+(7?#nI)UP6k4FMs4StkIa2)PS+LQcQ?JF|6BF2Zz!ezy$N#1W;yuvV4FYT|Od^0G*|QYaB?}OE2*JPpndFGd*J1!(q9PbbyioXZ zc1|NhZ&v?|T<`%zUjy2|Dk^`P*+1`kPr6>j5E~AHk0Mg_#xa=;S~sl|WSme?29gr= z!oX=s9Rwdo1Ti}P|1gYz$pyDZC3g=aYPrHSp*~KiZ0>Lws372uLURAdSA3Z`TA2X? zhK^K23yvW|LI0_L3ltzm zIsJe$>T*Q>fF3I2j!I{+hxa9`Kuz3Ge;G)k(ANQ(9UuCWxWieY-~mLVJl37TIN6Xa zk0mm!rSz-&>%SO4#4_~8_5*JJl{iTSfTnAR*k||i$_I-x;1h@g6$QK;6zPm==O&!rPS%X?hklgbm_ZzI6YN3AX+%Vd z9DZ4D3;&0pc}Elanp@*z|A=fyYQGf2@k`VggBG;ET_z?JR2$M2sxbG-7dgOlo$ui@ zi*Rv7;{xNYu)75mCjg=P-XGP--di8^HYA@rGroHH6zYBDU!gY1%xY0MYgqSWS3&-L zJG5Q2J)Ip&|FfrJ{pg&l*YVEi^NXqw9kmLdHp*cCsNBP%fAa|4+T|GH6^25eJDc|f zs|kecB8{Y6Ofg#G&Vz`C>L>1r7a^>}RhhY;EvZP0HqQr!YyJX9Ax_tXkSmK+QWOmZ z+M@|N*jcjI79Pvddmo%xytq?ot{X0A& zZREw551tiRq>3n#(5ywNK9(**L*$4X+fQtjem^*MU^vq(wn{HnBxGmZ9MA!jOK`4t zSWbRvv(s0i)h7Yb&Hi_Qx&AdBUDB~Q0$Dg^L=!%~x8Ik(} zpASG6Hko*OS@7*1`HBTQg0$SV^0U8G#4nNu zNKUDkWWeB2=RDfmJ)RWKi;vHOxnD&&7WFPE!WfE>^V-@jtV2HYEdF*&u(Ngg-}D$2 zXqL*|LKX}7&0ga3wcfKLHqIKHuOaxQ#H3*Mie@i!4;99;?vC@_-UF`$k{m2v!f_gI zdYz3CkjbklyNG%E^-eMczT!VIM1_J(EYqnKAy&KZv$v~oq#szl%cuf@r|HKxkTgeO zrc1rAZ-VWfn0H-P4xRRu1}tpK4i&D}N|FPf`;c+ALn)kbg*5n1QwOmW!N#F+^cvm4 zDp5_zQ)j@Pk{sdEJLr(6d)>dS&~zGTOu4`2@z!k17@YIZMjMXX zNsP&kB*-5Iu$u_Jw-o?!Tb18&7K6m)Aa{x(5}dVq28r+xu#m13;b|ZNHhy#SR|xw| zp=`L|WXe(fqHxSG{01$i$@WpR=Ov7$n-4qicm<#>hV2MHIpbBP#b4Xrk>=?Y7zQfu z36Jvka)P|q)Y!S7oKDcOm{K} zE?sotpCT(f_i>0k4=UM$T_uEetGySVLxmOfoC2)p(CctVkus*q$_I%mu{bdJArD!4 zwy*}xN?yH!Q;H`HlGbRcE3W|-T{v4iEZW+_Q%jeUtidn3r9!*gw8(;(X(hG$+%9Xf zC~_Yxq#+M9pKTg^2Bt>za8u9|uv+6CS|2u)&okB&x42xs%6~yU6a)q=V3#OLS)lZ6 zomQ}i`jlo@C};h(g%crKI26anbB^Ml!^;V-v?x8vh3`16XP;fi0@Nq%@!zP4mimOC z8@q+XJiW8OOqiAZYwUMf_V}^sI2rbY%3v@;&?l=(k7g)uU=VioG>nQL<`91$&pSux z1|?&-W_P%G8p1w)QbND-{}|U8N%I|?Y{fH#j7=_WsQp89egrYoUFW3#y5<$z|D+gK z55@gHYfXGOkJ6L{$PP)S=}#5A&n)yw8m@PRV3@R(%b6$7k*=pOnmXX3FH|hcor35z zRcIc8`D)(-(>LNU)j(e_f?dXtMhIO$@YtU^=452ZHSAV+f*^$PWTixe6`YtLB+QP@ zi;V-oj4pVsANZ(^Hi0F$nOE6ayIeB-`fj7EB9UL#4=DU{Ys;N7^fx1>q`V_S9<}rO zM`$wEqEE)&L+S&WY4@}H&eand8DwO5OU3gd-NANkh+T0n2am(GqZA98RQW`~Ubb!M zn;yxSv-9_Fh;~;oqc1&#^t6b`I6SI5s@UfC@*p(J0wbY{YgSc=U&Li>vOxT|;)V3at=_iwb6W6*in z4&j*(RHSEjH+;CEzr9XZnAML|1~Ylx}~{)-+o_Yj8?%vaxJVzPk2ja z)rm0Ra;hYV(R(UWO$h0V>fNT>_<$4o>%b$F3AA75g5$l!FYpeZ=!t^Tb&Xtrq(WgB zB_R7yp8%s9UPg82y1XYaE+usp!yZBum&@{DO`l8^tlp>WSvdAi3(eutvWgmpOAgZ> z<=t}J+W|yP@#c?9ja=BD2hC>$ZI99G&r=@Zr=oGQ``(^f3$Zv3_fJbO98!D>H}DV8 zhp_gKUamT7u8MAuJsYE@nUA=Q4iwr1C*jLay+hV-E$s9k&xMmgSiOA1HGAfRi@i!= z+%I~93sHp?9Kx{_pXnCma0^0*NqX-$N6?%^#j}j={_uKrLD;9ok1aOHL#PS05YYsP zU?I)MU!$ukleb+$_!D5HR--X+G~h(q)pyclE;(RMCQnz2;6Pg+<>W&J`cdiilcBgZ zx-D!E!&%p*KsDsR$!Tn_@eaQS&`ZPCrHQgi?FAf|_GoLyglb?k{rIm8*hjo-f&$cd z|D|iUG8IY7pJx25iT3g6-Bp8qSV$jC(M0d$u?8yr3$3>O^*y%Dw)*=3k~oOH`FsIf z;eVRG@l{~oDdIZLM0OKUdu%km8%|`|oHz;A6YyZbkL_#-^m6 z3bnN}C%1c7TS80_@o;;K?>Ki`F=T{CN=HF&m)%&(3!O|Naf^B!cXFeyvNT#4f}U}! zDzqzErY!;o+=p>&5rLgZcsLD4!#pFqI3gu7Tskg@_CYVj8Qae4%{Xum0)UV(=LqA6{H07JV8sz3a&|hT2bJ~WRDr^!QcO>+!U;3Vr$lE@X-Wq z1hf}5p5g^Yc^jeKs}DDs1Dqo2D(^5Q2F0B1e}2=G%RtyT1!Bz!!H)&@nE%O0W#EH; zz1mHYRH`mJvjv^H*Xr-j_(T(S^ z_GoV;2CdyKg1Rts_yWQ@GA?)D5O(3B;x~|XZL*qxn`7e zJ)9Ef?)us@0!g)@g!4=g5Pj4aOdSzBhqt{ClLWH%pd;{@GlbumeJVZCF5G&nK<3g- zVrS!fwv(o0>b9;90zBhwnm#0Tg&@<%OOhJ9xP8AMG0bdhTPEm7=-a2?wAyI##BUA4 zz_JeRO==m^=L!j(nG6sVbidmd#9$sBEpCeX5#!Ope}(Fq|H&36R`<|sfT=J|ZxhO7 zfF8!PyUz?xMOZP75%nUW9iWqkM0epZ9cBb`X(agl$>Rt&5@#f-L)b(NLL1+>I!KYBd7;^L3yV7_fgGE@F!+Pc^txm3n_3Q0=ay|QAZo} z1Ft_nLrLNm=0(alhJz_ce&#QH93!RxPw}72l|>G%X?vV*MX=gyB4L?~bk6$`<`E0b zlo9-9sim!&p`RTD^V4>BbXY7c9L&)Nf-__%&2X2mx!pRaDpZ;|f~mU^{D==xy$^Bg zBh~sOEN>mBpK$_d;U-tNoYh>r$+@sgqoLL%-?l-i8LJl6a2FG%u}X%(lpFwTakHD4 zbZbmck|AI184sk!m^F(De`OuE=SYmP=w9RH06uvC>{mf;hrOHo>9SgCzr!`CuuX5% z!kKG$tnb(&Wup4{m(<_;2yR<(?zgvR$H-7dbn<V&oU0fKZi{yj#?wZ~tp_q#(iS#h88U@UZYWDk$B z5l@E4&xNv39@%2r2W24fkmgbR1v>&pZ(1M*-;_OgEmU_wZ=DvN2~eJW&#innuWRuf zwxcQ>Y9~vFjkvZ8=rc1@ldbGn_eTy)?j!d+U->^@$kr~v2jmZeIU@6Og-WfKZ;HSo zxUQ@!MbLx^SHLN+?UXpZYEIn-^I}IzbkYbulp&hN-wI~pBJG;bd58P(i-zNXkXVIN zGg=FDFr)j36?VxEsBPCtcFzyQV661;?|{!Ta`F(!_1)6lnp_QCzj=?(WUv3G7Hu6| zhX3jJBdZS+P7xrSSq7l19kC=_GiJTAM(aeBQ_h?tcW_~SXt|ixNUKFKR-Wpy##>;C zSRATev9K^Mw(O~>9%)y__B(0vb7h7JGnAkptaFr=q68Gle`yfp{^t3vKXw|_NIq2LbWSJnEa?e_=dH}$&r>lUN==(OsDI$2w~*0iZ;X5r3Ylm_ zb0kW$LBQRZx=%;CL)syXFw^g=r~FHTo7c?*c<8CE$;wWI;1H_apWUX2nfHxxiEz%6 zJDQJhj;wP@iGNtOPA}=JKTX94+=TO8%fxz0k0NyfZ^|T|2O_{dt^`p5aeqim2802X z)Y42SNHIT2@A?FBA(Y-?-aU0@=QbM178EYq0Qi(bEL%;Av=}h5Sq<*Xk%h2U`x2OQ z5nv>67Y!dON-6ZX^V5K3bjN3W^HjbHsVRRsJm+-NEtvjNbs|Dv&w+roJaA((&3&oh3Uv4HbGOSVDn38BlUzT543DZs!T#G%A z9Y54FxesXFT?G#44&Y6X%tK&(q2#(ZWKqv#e^NUXw|d6pNeuVzZ3gQ&LEdEkroQt7 z-;D9O3ued2Sec|T3s4O&zYzW1wMqd**mo4)5lq6%jRs9uq>-M}Ue%Infx{U2e`7kz z3hOCD%uZVpVF5!k?Kz(uI6c8ZoUIppyGh)wU>h9(u(VoN;k_?Vpkkj32UGTZw3Vp` zkHm|e^@lk|NJgJ092rH%%J$#L3d9ze8ZjZAUs z)ci&(W1ZyqAYd}r8r zyXjrsZIwe@a=r;y<)0%g=4PCK<;BTDWP8!A-PeM*A1;wiqI$dhYX@g095p{)K3nJH z=MX<@I{HeYvCGB)sf)7$cI7UDM^w1KQWHLOsQAW6a9}a!LT+@%q8K)a!zzxhf_0E? ziI<%0`lNQ0rwDigM3VC#;;?N3`x zL|Xrho`z_|CVa$MA9Zr;k`|4Zm>W<+j6~$s{yjON8wKv|$cz1*KUxfe_{?w9?{Ps z{=-v`17|@}lQVk;i!OJD;E_?rSffV`76g%^3%q@5P;b`%*xwMgR^B0Wx;lHu3E+F$as>pK^a|Dm*^Ec0t`VYe-TY$^y0R4z6&Rv}i zFH>+XSzudZGOrH_9y#U8fUn+MGifGi(j5RpmY;M@5)P>AWWZ33o9oh5J|R&q%=;jG z$VO!uiO7rEP7(?E*YdCm`S>4!WeGVb#zj6hC)bDESB0cU_P&dMa&UC*zjt9s;|;Qb z;~!g>lX1mAGR9_IM>~2qkueiXP|_!|%kR(=T9i-r8$ixID$QYv0w>&%G6-k54+n;f z#{@inQ4(otWVgSd?NzX zcis1N$VX+&tzEKA!iSrQNghY7Z0LI|~an&LFkY-~? zd}n~?vy1_l2G>d7)<~h*d)_Dvkc~kQg_`0ODU;#?n<7@}+}kr&^Sl?@ubw_R_>|>x z{s(J}4)>zl{Z#V|-LyZ;BF}m0EXn#a!byTD^)y%a=Hk`18j%DC_LBXt@>5iLf@2}2d}wbS?sS1&gUkD>T#e2n7N`BY<{ z#XUu3zcEdxGP8EwCmxUN{%J=0im3|U$bC*Zz{SC1;uaIb^?(D!7W%sVmSP}{rFFU4 z^`{yQKa1J5xf7fvq6I|gA0z{wKbj04fTkIl3Z6ZdZ%)wk+f0ipE)tD1G-+USxc*>& zrmAmT=m5#WkgSFIm?i8-LvNrql++{4z0b!gSO=0)OpO_`s%ciINzD>}!o~dbYWy^B z*d=9^%fu}ES5w7um1*dP&Vz#mQSs65w-|d<*4H%Kf4%zV6FxO%2Ag0ujNe@ z@Xy`OQ1MIs`t_^SsO`bP^Qv5{;TZ_4*Ob%!wlCt$mN6o6FH@?z;+E>^^oErT zB3z!W zZ?$D<<57tJq&$0wzwfYbDz6l>&r#AaNddVOItv;mZ&c{ zu$R>^>&*6++Z-9&zsnV6?iS9IkW zcc1o6Q~tSf+vl%uR7Bgx{d4B~qDPm;7E`T9>@=#p+DL2Z=HvBPJXePUJ$h|8swFxg zS^{Ln*Q*_dsLndpz9`ZpXDjN;oasdN52ryqNvfS-E`gx9bY_vEA6~|wD9N#gtPo!uLbJ5>1eL$1{Wt zv@5B1=O+`Q2hkbTC793g;>JCezj_+?_&Y3p_Ym^^jI?pLy&o+jx6)ZZtpsD}~)9i2ao~;vp)KQ+0aU^O)JQF-L4)EO!P~!CeE{%9SiIk!K>(Tm59uew!kk-Cr4_uUgfRksfE@wyG zODt@7&xd993IBd!p9ZKDT0Z^rnOi-4dwNINrMDX&H7X5=C@E`@-kp1yQO_7FY=SR! zFQ6;egH-s4f2t6vL?6Neav(zIyRm^TdEwrh&=zk`;L`2m+ZO@>`+Eqh#AWGU3(brB zSxL}dWKaqG_YSzA*?n^Ph{S47((jt{#8>oP!&QLJC%qmyv=guQi+p z%O9zPl6tjD*K@+`oE-QyKPfm(IO|H=C-puD`o~OOX1{wQyE!o_+U_mjrG_)hTh7L4 zEH;n;+}f9HhuqeKfl!%t{CesqQOL?#_3okLUqLp~*cW&Ym9?x!5} z_GyOKEPvmk59!%}j>@wmXnVH}E1x|}2H$ny{A{Rp(|`9ewzg6LAmlYxMyO&mJo7wq z?+tQ?+rxK=c)S)AJL)P1)klGFIP2}yCVJs{T@n?(n+{{yHxdP#HS=l-u-Vt z2w|@2Zng@B6l_cQwkKznGISm+N%qhCTY4VUv2&)=o^qsg@n~mvs?xs3O4e_J)bo>k zjN1sbzI`w`hK7-}Y}>1zrZCT~b-@5_)bUnV$%6-sRsvIrd8?>blW#5l;rb`;Fh1{| zSUK243W@lDyC!y@EA{+MJI$&a{T;xWLc9n%db-i6owv`-XM>DqBYyPWJ>*exi+<%Z zF`bH(+zs+RitPp3>&TNQU22?X_fCJSOz29>iTGT)9{H?-?0)(CuYNJwi9iDv-QF_a zI%T)x6Qsr^|85J|E^X%A@mf|=1sZ;@#3~GsJ)63Y*X80#&sVCpUK_OE2+s?$8v7~N zrMPGGm}G(3sWt{{d?#hfth|xr{WjIsG?DY&!J!96Xre~a@^)b^FOyRFm3zB3YRleN zjmVR=ly_Fn=(qLad1tsVOaFi%HQgQ(B6)TAJXE!JHLc%d1|KxO7*VO7?fsj4WH&7B zJdR(Qs-lw!ef`t%t@lRj*fpr=*%zsl7|&Q2kDy$x?{ z3UKR1KJJnY0pX?=BP!?t(J%MRZ~U%YM*1{-snBftH=@nywp~x$+5885>gftPSZ3^m ztgmd|Wpj2r4kkAAlpPq4T*3@tCqYEcALow-xupN=#Ptn?dzOlA9{A`xZT-OI%&y;T zs=t%L8=Eg^t8EN#h{wMVam$^=74pyY_L=U3t^}z9EtE}mXN{Eu?hWCmoQURJ-lm2s z>SSw4LB|9pxA%u>-~zB%%lmq$U&$nhlu7bLdAU7n?;NHT#hCle|yEQoOH*_|Hug<~@Tr{nG03G9GD6vC|#yJlJwUP%4_nw*0j@q94Oz zR%Vr~MF1Nxu&7wu9!U71shM|t)YZFOIiqTSOR(I>+9oj2@Zg)(>f=V6)As>m0|5eS zIcU$Vx~E3sT`IpcZq@wzuqae2BOQFOc&YwwjA0enDgVAdcFly5a4`CN!xb=;RQ0m? zelgJ*R_Y)ja}Pg7i2wFxMj))?x!^f&iSwIQCwb;D7ATcoNa!Y)Ccz(SshuG*oeB-r zA*<6cNcRRV)<_>H^r~avZgD58!0nFDyxmT6LrbNH|6H%3C%ItfuEh&Z%pZ`BdH;Nc zb814uH`W_OryX9gFS)Li%oqM$65pH~8CZOa6h8;YCX z)BLm++r{L!j}G+)u(^vJFVBc)QZ)eir)VdT*SuZZT`14izD5pP?qaG|snSZ24u$;u znZ!II>iwVHDqZ1bmPth7=DY1oxQ&V@K7s*YvH82+8-ugY@dAhbMGmCmol-6NdJVO$ zp*UU{$?lGW@#rAq7=ZWyb1=jB$M?3o&tC&@0lsDN*MQ*6Yu7I%k9Z?mNU&UmL*sV? z3%4)5htKE6<~$s~NYv2(wfXZcv@^oU&1QXH_o63ziBLcUCp#!3QqP7~ncn1PD2D@% z7fkU%Dk>EpAa6YUE)U0SVr`c3|JpjtuIW?r!t{n+MROLj$nGu$Dgy`Ln$697 zRz1 zq&E=gAeia)#@Wm1*y{@zo`RrHXx}=!zb9ee?0YR+MNErUo(J6v00ri@Pjt22Qn)SOv1E60t5Zwq4PoTk zyEA~0ZESodS_-KD^=Lvl&PLRm3nUOc{;jzlnEYjje;cFrIcRuG_!p%f)Js}%m!=^Ok3j2q_6XY|Izvh=nh!9C^0Ye1B_Yi-XJtd`^Ld89=G^*!gsDd?iK5ZF+IG6V>JhH}I`xHk z7n7MbejDL;l6GG-UgZt9Hj%$=4IE6F5Zf^ajoM2(7wn@=!Dr`cndN>kWe{PbijasW zIIw^KeR*8uJ|(Zvp%)K~zOS^o{owfNwG$+LV(E0!iO)TwB>7WW9>K!*xGNCd2Rz*c zz4xK(cW6)jN=!_=wlT2FdUeSDDa_LzX=phCF&0xL;*|4}ox z1Tr7}U_o5~s=*vJaLRaq?x976T}4J&sD=Q{QzqeAy8)2S;}5Q`@LP%;$!qg73_=9NzhyfeK-~0Pj5akHPNDnkk=#Jt?}xf z`7g^f=~QUw@q5ZV1^TD9wlQ( zJW5pStg5XMlH}SExE?qi9{!pY0bE1^wvTZT=h_Oh%f=-iR;3bmTSJ*4?7a_#6T#tV-4_u*FvtK;~fRGY7Y^_9xqdh6ZHtZ)2u zU0e|b``TsBKT}pBQOrlG3NC)`KYaeM;ZxV)a&Nt^2Gf_R8vOTT{7m$B`n4;Cg4YXg z_>Ql)Mq#A;QUKXgmKkcogNgAH-x}t%s2%fJW9*%kHB%7fXI-xs*!GNSm6eHi<}jRi ze?``V)yQ*0bjZTa-37C-ZN640h+f%{V9N-TQk)Loj}O|O1?5QWB%m%klSu*tss?_o z3W+lx>LTGAv%Pxr_5%P=>%PtY zy2UTzfFsx4bv+b30jVuV>`WdWAodHeh|>FNyng#0zoA+GTaj^PT#zDOos(UWpmgh3 z7Mj_s{b(VY{~2l7^g~c|3|!ERSAz6qsEu=(h55CZmhCUb<#(@;aO&fyci^78Rs2?@ zcwR}Q0z}i3yG!g)^q{aEad9IRR8403X>1e&^u!$-LOk*WQ;;ykpBU7R-wS9=`}dF> zHb{K5LKV#=hRYiNuK9d@O{azd#tF$TPENS|f*{d|YT;T~2!+BwNPVZMus5cQkO}D5 zs0Gq-)`p)C1>CI|vP0>>bgb+9s2S2%`IF~9U;1PtyOBi-UMUX0Kn=4J>&@p^$plbK z7c*5U2>V-JtE{=q$F@aA0yE(5o8ywN!l6_v9KwgosDOm+LQ06}qyKo$9@km*1Get^ zzWd`78IGEyIA#x|hAC_Rupf(f^`lU4049XGyh-rB@$d%ocQ7+4wnOm#!~r!74XNm` zK2NNhoVk0W@UK=C>v>?X>a`22T|i(|S0MP3@v4E45t}b_>6<49?^sdST8*_QUlbU} z^rU)r6pCC6%O)M)5I)rXCt#w|3H+E~?C`FNiD0tNzJgWhb&5NEA$3?CPW3NX<(y}n zwu*YbLuwadOmC6x-sdAQ$6LmoaCujeZw78uaRx9UZ0H6QpnHKnNA!L1F9Dob+P(LO?XLo z<_iu`(4t95y$1H*d|ntA43GtEAUf8XgEP+=Dj}SN4AHQP&yub`I_EXysSjJ66brbE zIF=tJ>ek+vF}eDUf_V=u&7pPe^OO0WsEFh8!_^+Fpc9JLQ$xcYu(5g@a9U-lm1Tbt z%121@_+=W|?EY)4Ry>@IX33JhcZ=pgrJ=_#^tVFCrV_I&!kvL9Df#$=>={!Fp87(lZsMIxsaueyb9RH<`bY8 z1}?p~_MK?K!8rr?>dwQ13qASn8)rc@2=+SY1drAGs@Aa=NIF%0V!+)&g(uiJ%VNn0 z>I(0m@z3YH&B4L%{MlE^Tp+;$?JW%CFQm2OVjyfT97vDtxm)R#@yPQtw);?@85bUR zYS!8|x{ueyZnS*ssfJVKKGXSUoay^*Phz3V1vg#xAOGFYgks!-#R9m`*a~|JA5R1) zCR{2vFiw_SFr_aOgS8A=FKc3398X|^l<C<-m0_FED#v3|ftosMr(@1&&kN`)5!6G>~_Ge191Jxa<8`tZo)V2O@Z3B=#Bvl4%Vm_4K@i=WKIw}h z9}2oQj|^V@>lOmf^!X?iSY!+_US*wD9Va)GMDWbqPJG8}%~f!ue(U5q_QM7LTJawG z82Dk0=be#-By2GMvu0stmW4fE%-D^{$0jgcwD8OS4fLw_Gavq8d|@jJ4k}ye^SRWe=rpM zTu@GL@^$sCYrb50VE!EqrKVr6ntgRn_;agnO}jqX&VL;L`?y&Zqvn%PV&3usWYwgQ zuHe7T+Q4(S)YGr}S>=RdlclKVi&tr}3eVFShN-0K=eBv0H>iy37iXhm6Rp4zhMj;C zG~hWS4*Un$0WmZ@&Mn zk1w_3b3BylL@lf8Ua)zuOTOrhnz}76M5%6?DcR$_^snG~tAY-aCNOYOp+)$~a9V^Cgoc{hS6&+OkycGbn!1dP=eS znN{?FlNfV{x2N((htQAC>mI5$kb6?fBP@9dwZ^w>j1gbzr_!=rm=sed5WZtMvG$Hl zsiTC~5}ay(Hy%DqX)69E{n?+=xQs6ULPLE^G$PWDHPyMz5*WSZH+R*(dPxJYeVg`A z@=BaJ|N4;2*Kl6d$`&=F0T*kH`5F#--SNlcld2+*x$LMW#AH?6cDa_a*~^*pagWet zKI=8=UrIwb9GmX1#t1bU|A+#q&jNCZsQO{;4RO;ug$lC+g^^pb-WUahHtFab_u*( z$zON_4dBCk`-_NvMq8jf@=EL-`{upLHvKGu8Y|^@&^?vbe|n(TcT{>m2LPR~+HO&1 zNl#8nPN!XvivmA{#ku+$+cph6|6)B{IqcWYH9oK1`7PRw{~qV21+(1edZiM9`a1@! z?;_pR6JwgICs_`J#J+~NNhZa9y!-8n_`HYNI+tV97LTN1i^ovw?w5bEt9+w9)RPuB zuXlD3!9}b&9_f^CsGbL(Su%P7foV{vz*O|R;KR>(g=nS2m0fW*c+UD)_N{xW2}FH) zriIFiw|u$mr6yB}8(T#bdUv1gwlYAek6g%=ol?fyse2#EDt{z$-N9`?*`q!@sjJF( zdRwaz54vZB#eVa9QN*XHY%mG_iXSwiS9QF@yR*d6oyqcv|CdE4gX67M;Hyi+Xa&6q zt-Y6Q=S?=B%-XcadESqzMc__Q_Byp{^EXT%D{4yKg0c((JC!C}TWD=O7#`Cy)>I4) zRoJrCEUNhJEfv4G>+m4*5y&kY#$8L8`n{=HmQ|NUZ+O}hXmRF+eR|3w^_kMNPQB*N z^&Dl4q-Yw2OkwD3Nva^T3h>-fPhV2`U%}XUZ}K&N6O<6qCxgGgy>zC8!GwgDVkW`~WzzubCdrVuYP((k znQ2B=`nZfoYeSWQ@bAP!WeKb!#RAP8eJR(CXDb6=Oy5qIwRgoN@ZTPvTpMH*bfvW7 za{8A0rW}#uKHd1tuJ-BY@6T$G^K}R6elfDt@_hO8W4JF=EMatC!*suY<=m`%nM!}h zf(pj_)V3@;v*^M?_^&4hSmEu~Ewk8l6Rl& zCYGm;@eqkLZ=($ck^E$#%WAq&sP(7&D_q*IhOK!RrMO>yy}Zk^1>ghYRRtgaNSn<3 z{9#RHXHe0`5Bl?s)b`Zf2gM}Ta$B0-%$Ew$;i7ae?34c&kl2bo; z%nlLiVk6$s6}f}#5)XjuyE2W2h#DqQ-FVGD)!GkFex%c8)!g0{wG(bNE#kO)_i6hS zq*E!ey2R8kprM@bY=W~l@qB(wETiNw+FsPZvCr*E#^B@PAScQ|g@y@RqqX4|eh*zb7rUAaU)P6SJ+DH4ysp3<4tiL=%)`LenllQ4>Mwt9;2YL=YZ<+i3v3n8f zEu>F|i1R4beGbUDe5P57QCiB2i{{J7%`D5VOSEA;_Drgkz|enVZB;64OXm2vBD+}U z=_asvB#v)GYJ}T_0Dqd~RgUo&X!DG@apjX3*-g@X(C5+UUZ8c{Wk+~(6;d4>8`^)TLx57>FaVN!R3uJ!x%v=X|m z|4ISo;tGl4J1h5dj%}v7U2*f1=Z}CordJCX{r0ixVr!l_-}Em}zVoPVm1Iu``E^*| zZS08`YszV};h%hX8_d4%hlqVOyPFU?^RU?C&lF#7FYfmIqPncz-;KFNu%umj>70_9 zn3Tz&30n9=asl8%8uKTAHk6k6iP%(Jahd+S<^QV=hbW!kI=ri2vuJW-D5haL;fSYj z`6I7~v|K>>*xlQupxpU4xYX`o-Q^?SHHoQD6V|9t=qt$T$6S0%uPPJgRQZ(S8(pBa zZ-Y(MkjnSIru$<8I|(ZOi&{y8YT;5{aNF4VsqJ-<+DwzwY(O zn+`iWV?s-Z+_nM<=!h!00t=%lo}x-kGjEvC0X9u#%Kj>AYugYy(w% zy`|5;I$Q%lr8zRA6N2}sD~U~#kiB;n0=lh#)IIC1yr(fJ{?5PPCDG@+^3Kwrw$nHN zo`h2C`Cg)6IrB?no=T#k~SuDWJ zTW&G)uJhbel@t%rooG|LxSucnmdP1^fOht|50?6VR1W694+qd#T|;fyA>(U;V#A9Qv7f!S|~2X zy%cwM=Z|Z#wzwbMd+&!lyGbTHv%i_h?96TiQzmXW3O5WoJv@BH_0sG=m^h{UByC0M z*>p;F)WI5K7U_ED2#9A|BN`uLDlD^&YLaVUEwG#uALU1<42`<5)GZvqmnU#}{r2Kw z=R-lzbm1Nuif~R7oiVat=j1hwK=;gzl;r$4*pThF?>QMNm-3wjSa%q6!Dn8#&D?7z7B3q`jL|CGRadT;Z=l% zqEy_R3*Y0BTEN!b*Hijm^C`?-8c*C>3y1G_L=fC7_go zgcP7S|B+UDJk>fOCAM)W!-=2Gz@$v|z-*g-`j=y-_C72jd;%3yuJPX}+IM6;1SR;zH!@=|jk*rzlIw7naO<$iQdYqAIP6K$ph;?{FK@fxFk*FS@%yIHMZ|kOehy p$ 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 H`|f`LmCnnB delta 88413 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�K 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 delta 88438 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

    dg6##E@3NnAt2clDeGF+( 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

    S&>w<&pa$fmoM+WA>Rf*ux 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 IF2EH31yrcM!2kdN diff --git a/test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle44.hap b/test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle44.hap new file mode 100644 index 0000000000000000000000000000000000000000..f0d31b0f7c15b20eb169c09f4f926a5a26d9a2b3 GIT binary patch literal 100942 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 QfB^e@4-0F;M1& literal 0 HcmV?d00001 diff --git a/test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle45.hap b/test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle45.hap new file mode 100644 index 0000000000000000000000000000000000000000..3ff235b0601412ca8074fb38ab892df6f18c9da8 GIT binary patch literal 100862 zcmZ^pXE>bC`}VQXVv&#p(W7^wMO`&|BnXM_i|8eK-6dKC(IZ4J(Mu2{%IdxMzIrda z7Q4&Z{pa`QdH38e=D1(XF>@VreaF{- z&= z5gB{=2r4%l-?BuAL7SirAQnTJVSt~WwR2DWE!;DfFANN%pU&@_rltF|)^8lJtoF0uN|$x$44R+j-4{Wz1Za{zSPH$R{`)E{>`!=1r-Sj&oUl z&SlnF$&l?(R9=c9ydz%>(ZXkle?kQJXLbj9Q!@C+YKq<&$&v5Os$@$Y?D;sn_c!1- zQ~F|dZz{q-)fgQ?o=Vy{W-l%9U6*_G?2Yycln|eNTd=%1i+XP0<03aBwG|S)sxhwW z#i8c0+WrlNII_P(TwY)YqerA09@-2beouPvf@-$kV$aQnvj?pW4654?i-gx+hdJ8+ zh>tT@Bz&zyN(SB*Xc!|TAkZQvAb9=%C4uQ56RuAGdD=MGTiN{Q|Q%)9?aPmZ5h2nYYLfA4qNC-k&I{Cq7(QcirYo-WOo zl8>e!?NK2oAG=BvuSNO6v&ZUMDaC2H2_!fV)do9n@Lu_S6AHp#$&SnK%kSf|_vI(N zh0hQF#!IAYtM@`5Oh>Ra2E=|*i-4YgeV{U1{7NF0jgqbAv6I%3Nne>@KW zGTxc9EU-z+@V}aI;o`Eqn;2kQPWXf<{QFlR)Mf+5@IqLHobEaNK1s)D=b9YfW-tR< zous3)Ge=JRa@gYz_+|z{QtgkZ}m_6L-FYfsepl`d;2gCva(3F~!i3nZnLlVW| z&OC9rG!P2_;72<%7|>4vl`;IAH^9~Sa1Z;9+voJ)uFeJemLAV&FnxeL05sAG74=+u z7_ZpZ`3C4}w;`MvFW=WG&VVk`-3_q(Z;Q5pKG1=)A=h4D(=8APVi}vH1>n0o*=^I{ zDG1#llJ(Kf6^0gs!f1%?1{H8MA^cX<69`EBu%QE7HJX?N07UFJRDoD&fW|Akc@C2G z!Ol{KmW1#r5PiTC0Cc?b->@5X&@_qtLr8JpUo7y)B<@Z|-BZBqflfpE0KWeb&J4uf zD~{(rTiI_&{}0BoCVmn5%`kDdc*gB7$-i5PXI#_!h58|E>Iu1 z6#&w~$(u32RWL;Z%k#SE@bmvRZm9(}2N+sT$i#8Lw)k*XhmBHtbO|aAo{LI5Mqp8y zm%z5%a4YK#Y6i48$-g8x{12~=;m&4}2pKDrv6VRwcFLhx>iqF5l|j?{cq;hamFl4T zeGdQztN~e-VJoI}(mk6XWF9T%HkM@1VOOMuA7iVz5sz4hcAHvN1LOjDrn4J~F_lX{ z_}ASN5x(c7%!huG9-0G})QY4o^PG}_QTujU)%1(BzAX0+Enc@WG2rafArq{`uU+@P#Y)Btt zWH8ld*!G*x)P_hj8J_qOGve($o!EUC6$u2@JcCVNvW^mE-a9BDPN0s!$aV53?4#8q zPfmn(@lPiwvTmF^Ldocq18Hey?Rc3dO2Z)4nPiAZeoAVwlb(S(dgo4>2;Jy0Z z)TIWGDxNZ}Uz%L@Ly))Rq0+X#%76lGEqCqIjh_O6?6)dtYx;u}pLgm(GYCuaW1Atl zNl+tJu9TLZR?Evj*{{*7n52>*?F3QbGvRq_mrU zt4Vn2dL{QQFOGKdAxhW?c^8FVK`8}=1sev4H`XRrg}U=PI%F-+fGBdqB?IEKmay@~pc_!^Ls1R<>)a+AP4g~QrPXdp}CPwY~1Y3?pr zYqPB~*{rf#%PxxXzU3((g;x6h+5)vi2W42`dDcCvdx0f0e2?{6$?`rS6dzP@Z}VmM zjiM0eogwDs+|_&`$2n}sZgk}V8b*0DO$#ayz(pdS(jUA(o#Tw(@{f*{ux1@a!AXKt%6(ba=35(HCF=CX^7X^SFk4zzGAe z!R}AIPOU5;3ZXjs!Bw>I^T|PC^V@$7Yg7>ie9Cfta7#D8^4t+(VhXm(Pb`*Y=gjP{ zB?+B^$JMdMdzvt^=Mj8-WEe26`T+L&DgJF|nWC3AwpM({pIf4L2Bun=-!4*tzJA6; zdSgE#>`V>)K?KV6U>`eA=+u|K&bYvn9w5!R;V#R$x6L#c>1O#Jxj6QahF;m9 zHz~}Uq9q$@duytHL;%WuW0G~gZ9?<>LsF+m5-b$^d~$|^2BdiZ@JCbH(aHe%De;XE z%^_Y`nCJ!cTi52 zU;(_+JB;P_{#_ylM0f$0jhMyzcTnDS7;PmMu_>Thdh>D<0YUe`t_2AHo*Ozv&3F2q zZOc7Ds|`hsEE8b}GxEFNUw-D1Mp`^q9X@{qPsJ#SnBLFpphI7Qx^Ln=RX14ePfHNz zzbK|fXm%(qafE>b7Q&Mp-D}}ET!`-20ySbm_3pR_%U=pFFjJ0M;jhl)3C9@^&u{mO zf=BGI2)2L3aA_aA$iPv6g-FEC0_!`NfNa^2;UgBnVe?$_@Ce|g=hpY(RI5DZ;VZYE zmEo&xjt$nR&ct3En)Jq&Gi|>RZp!QNiq#3L(S!b-F*a~WO3rXy#|cXy20LURTHh<7 zAB%!|uK;tfnQcz6=L7mBnKFHsWENjG5M|O%)NyCxk>f09)q2ZN#@ssU(yUC;-W6`)ont8KcQ2*%u7#pwSR`JyaBfZsFkmL}} z0>?WLm?R{bb#6Be=}*gPBt!!jyK@n>v{fy>vXhlEpSJ?_^6w^E*(gFT{(f=Izq%zx zPxaJa-ElY$YQM`l-Ku#pbJ$7-O zA`ick5_9$PkHK(2$aivv(>C?fOe?c}BIv15I)0S?JM|jZ&0D}$y`lk@hnnU;id6Km zS~MgL0P>I_o<}|Si&MgQ=O*nir>WkI%s2ZpfTvGC?gq)&#d~3&g+p;6twvDc4=R7T zDzzMz^X~YSG_b0>1?NQH(bUw2sdq+s0ui`O66}_gEGv%qM%(Fu%9FTDN{nmroCryO z5rUu`Z`27jO4Pa-5Xgs&%Me^pMB(pY+(;&GmF_S6xOayMAMVkQ?hXpr&)}!V^Tk}* z+JYqcN|BP3^9`4ev{=3q-fU19YvmpTD1T7jOo3%twhP*QYcx;Sh%T4C(v5I4oz%@1 zCV}Yvl=K!Jp6b#F%QqKA6dY-H3Vv-~9TN8fI~*)xt#qSfk)L!eZwPK07!Otou@H&} z{W?k$wrUs*c~agC=iLS$+fL4F(8rEb8}y7t9Xywj57EH+4yGZ?73wE+;O(BN*vyQc zlHCwdRSTr<4_@LdSAc}I$+sCzgQVJOc37*GI;{9-pt8b|h}Z|0{+9R%L?HbRjQbfR z3?m8+&w9bz#x!5aV|P4Pt0W>Km;tx4*-6e|$F1)g;91^L+=*%HJ(;O9y(b6`@L#D z90SKB9yX0#rP}2g9L6*EH z*dr1bSI)Df^IYmv+iSLJ(wO`TXN^Cg=3|-L>%YQ zxQ5}RV3e1d$NMBV&L^*fx6Y$6jXF}`<9v?j^0}Sjvf8d2*+1=#9krjXsUa#qq2V3* zL^tOsMoFYu3W7@_UzH%o`QWXPsZo>h0kKZ20b@<1t?Z=65QX!FqX1#< zJ>+>DlnVov7&IjRVPwbd2J5M_Wd2sIKN8l_JeRR^US7A3{bN3j=LqYtOhF_Ljs7zb z4j@VzR>pZNlt$Oh za&?rN6-R!-{ubxmmcRyeOoq;NrMD72$F25NrXMvtm4n|avT6U`Xsx7`<|R^$tU{={ z41JZjkFN~Je|??m?}*C_$K{CX7ot|eIy#6jCTSv<;_2Arh}ic~qe7^`10c(L&O_M1 z4Nbi^cU~wla<>hLBRe>!J+OLXRi_ln1F7CRj9u8z#6TbSLuZt+!0N2#K$X2W~i1oX8$xfwgb4}1qDmV!KTfFP1+`02kzApBSD zQ?{-I>rH(TBjjbosiYD~A?jZ@q&=g5ZNEHj^afB`?a{%5Nm+uJX*ycG` z3MEkrRlE7y_(q16_L~1H?`5bpHrFtj?5`pxFbZ+2W=fq)tekeMu|=1WpZDDEE|_$- zlp&30SUQIFbxkeLf)bWjt7Dn^O2*YV_`sH`3P!t1(=J66bTmV9lQ-St!S*iHN4<=- zww9>ff7B>dwXg$--3oiV#j2z9Dj{uZKdL|*e9Jf}a;Da$7<(8j4>%opo2n;)hbrUt z*1zrG4cS1m8P)qrPwk?r?yLwv=z^#;$l_D^S+)d!n!(`X6B?*EVd!~kU+wo-nlrDp zU|8QJN3-n5e*$bg-E@W;P3xUOEDD+_c&ShFqSp0xR+R*Ic>N@ZTJV_fhE+m1B=%yd)qWD@5XNd4 zzy=ptVAFzWGTp=82-$>g-cldBM1j%?I9G&L!<9wSO}FPtY!2YYFl z1Y4md41CjAt2!W&wiHZT@GPcZ>u>-7UE~=#pMS>%dQXC^&Wwj(-x6E~s;Ku*q4zu< zUaSC|>%+Pyl!K*+6m*M^Gb!nh+kbH0Fakeq!CSd-D+DArncryI(+Cv=Q-}6z1FS&X~BQ7^|(Liq!dWMHI9-iu-x!l3P|sxYB2as;EB^IJw}lAVufOxXSgT$ zo4{@yReakN!K1P5dW1MY0rb%_g_WcW+w$V|mIiww&3|d9145*MyRnZA0zV|3Yunu_ z*Cv{b<29^txFu~<(6P{)>wVWG)Q7jaS5BCGu_kU7?i-~rKM{otB{@aL= zd&|CKIMs3g#!Z_-3zAJm?2)!~o~msfihVadA*+I~5UxPWy~Bn?Tm|hjPvhJ@z8~Bw zTa6apAs)aRe6P5`GlV~d>bFjxcOIPXJ+8@)RNJgQgoOf;ngAS;gq<(+$K?mv>&Fe)L z|A$_;?oPNBWpEzJg$czl-mgn3ua$OBItMgD@G(pm;!1E~23Z0hOHXuT$1_g&R>Gk| zX=BayqM~^xkI>ZLnpbo+x#4*okKDgpT$=DFh6(`tYxj{U@=LTwQ)csENr_qRne*#M zT_Gu_=l)>Yex&k{qHLwXALvIC^x7pUXW-3y`tw(Kf>6WYW&KI3VEgM5z#yKgLd#U= zFXUb%;@E{h5sYWPgt-OizZRO@x9_(sCkgdY;VH*QgDPfGXSOGQ^o;pYpj-u|!6Z&C z9F7ugKkd(d!I#5ITxYr9Ay_Sa-5SpNQgipp{@N;438MQ^2kD=x!}*!#>R7y#xH!1IeK$yS3U}cnVwe68lC5?Kd4{fk1reW}p)o1VA>V zj^Y$(x!tut+npx>?sm`wu^ozp;J5oG<%$gs1eFy6r*yvwgPfC@x{qr$sn5vSppC}C zJG=hu+wKsp>*C-&l{Q_F6OJAZBcuUMo`qj|6|h09u|HMb;Yqb_{AMu2SI2qP+TfNF z`kgCO)SZ2#00SCf7Fi85rbpV5cE+N> zQ9jv&*xg>~*npo5p;!C_*r~ysCr~7k`VxRr==9(-zkky|@#MDy^pO7`c+X`T`#tvB z_1(F)dhm(CF78z6CF?Tq=4A@tNCOE?m0?Y-%Soa;1Keq(H4~hFu7cdEhH8L|o(=R} z5$=pED6>4+YI4GToo3{wFw22*la&PUGQseU3%5*xK6R*L z$^CigZ4Jf+S=7^Izc0(Cb_;`KLWwYcV+lYcmo1t?r?ptZ?S+QeWe)v)pLIu_10`2T2uDv4|tMX#Im*+h;UW%n$WXc^o9Y+2#zL-@2rr zeZE&9vwF!2jn$2bGIUPD1u84ND9H7ybb`tnnmAKL2i+N{KJLiV+-DX`<%~{+ORK7A zIeM+RUcA})BAY%`tg+B%#|kl{@X|CF3vSYuO!avi6CL%|um1s!vdC;q#c`zi1|!jC zf!)W_y1JJSWv8#Kb82W)O?=|m5`xCqH`9HiP~^`FcIrGG|KkGMss%jDWPb92%y?B)E_qqdNAZ5<`SM^@83W1|v*f&Mp zZ5j-YIgO)}ZyE%Cd2M#y$i)y9QF}~fae~yJ8GJ?lC!!T48^aY{p-iF2{V+D}?H>zO zO_#@_qD*Jk_9n}0wvRJ-%yjfF>2L-V{6!q-5=u|;cBC&B$)arLeQ$KRCJy!XC1;FnVp(wX zLN!pQPx6Ur?)T53cAs#EMoYz7#r)()WRZmFR3QrsUONj_Y7{`k@; z?(^gydBmvUgw6oXFB3-l2aeQg&5P4A7$Xasr-YH}Dye_}sgWRwUi*U&6~|asmxx3- zNHXGt!`HAO%50_jvuQ%6>ZsepfSPK_H!-OU<>E~buC@fp^s1Qd4|QwVFC^224-94xUlZ6$NSOF6U z1BSl^42O@5|40>zi(d3*RxFVkQPC|`<+2|uQ+-anISB#%)2;brA%>e(5j1@dIONVfBoZH)OeLKM@K`-`_WOgv2dlK_zk z(Krd!H+!N&8a{PK$rc9Z?iE_P$>cyXY)qFBF{uuJAknJ$hSVp(<5X8d6n{(3h9v+c z`@(zxMvNkCN$g@KMG?28Zgdc$04=OtclXXrJWV?9$f?wTM9yRwIv78pMKNIucUfwf z3t^2=i{FNO(Rr|17!1Iq*hNDweBWH~#XD27G73)0)z_ZyH@rF%NTgY^S+dE^#a=MJ z;A!#lOyAfGYh_&pY_Qxz@wN%P3NCxkIdATNVIoKoi_mr9O4hhe`^KW-uKNn`61WA>Q zPt9ECHpmI`2NnzNA%A;-0?U!bqv;s@s}S3p{q5GT7~gsQkqcI{rKZb`8z?N)W`-I> zHMuUnhgfWEie8Hy`3sR3LmWnluo%9z%wq&OpEdF1jevbm*QOM3noh0(2dAq)#Z+I7 zNjy?Sn4L@iE?SXhLhUS0ibd4qv7!;j94$2h134Z{V#nVs8EPkT4qBe$(6$9DYsVR` z?rR_1jx|*O-BkH(lshQ4dn}+mmzzukm%P+bk5t-}v*kNJHXh_c8ppM8_apv2d zCTZhKh4o*!rPjZ-9rA7i16P)A-d?X33y~ttOzx(J69I@4C(8f8iwJpXyDy;=k>QVZ z#u;nZ6pn+mr`xL5nU{Ob?`+SC##RJdI?xfCg)YIIzczYoU(8gy7Ihk+5)Ctw5N56a$Rs2#tBzRNbiwhgE^;=vqC&<=$Z8=j#{>=xOjrryES-l!CJSaAA2Upu43ZLP}@`C8o9@3 zPvyX0oc)i_rp^T!0)p=T5JG;};L%5ZYdSX}m_Gl?fhy4w_dEN$TCM<61 z%tAzau7|ffHqp>5-7H8b#N%!1zz?6r$(@r!vw4vmMvQ)CjxQ@S6yKblV0v!xr{q9a zxpkUj+u!l|k9bV!4r<#15@NS~o!aci&-!QXclkgD1@sO%{)O~9^nvq<7`!&sR@Ng3 zmF{6s_#ew4?zkPZfXn?a*RKq5Qb0=GKBKUgK;H1<)d|Y^zuLz=EUkFhEiU9v4OK4` zJl-gNO>d=`?`~|bHq>R`GmA+Om-=acc}#!%L2Cp?#o7{T-W_hWcUopd=_*^@19(XM z18T8a_3Rc?;P3%ty5CbU#suT~n&o%tspW$QXHZq;l`Gt=>Z?wS3BAKl{8F`P^*@{S zpua&)xuDjiCEd>iJQ`Q@g514B;3HL)kU5Cd)>YYyp7faM+#88Y#9VWgNH%8Y-f@|7 z!)@E4rd%_ZV$t|cC6e^(67({t$E97E%G9$8v+4)ace`5bXjeF@uw23Q?Qm@C+}cSE z1=|g#3%Kn^=LNVdADRF`t0-LBTa#8loR5B>d4%|qO#9JOo>g&IL)2c>uK{F-b7tNUMZc5OLrW2X# zoecZkINK(F^uf(R^H<5Wy`Y_l@|t>!;A?Pu@JQzxYkaH287h%g`0!@Y8wnY1+co{c z<>XN%d|H*`BpZw&55NZWRMYjgX1Bdp2v?Hco1hxruNvHrM^ za`#3ZkNsPxa}hl`xKhgP4>h>v4Gg)uIt*QxkZ7q3G7U!#Urp)z+}e8P43!4`UV8lP z3iJEnv6nWa8C>(HWPNx@$N$Q$DY&yAoCi7#2oFj5V{bo{jBt~~F0o%9`g&&z{G7<^ z5IRQop+IYPAJ0idzJ7HI2z6U*q0ph~@N>vuS$Y`k-rn{)^n7|-^-JHrCAJfDu^q@%3Yfaccf{UYa^4uW z?yw02c1Da&bK7U^G0?>%z<%$yp4VOmOUwCMwEv>pGL3Xm0Wto*SS=vEfB6?m5-G(L zP(PvXVX^q@;AB_op~44YIfVL*luZVRxuj;LrtNmggf&!1s_Q1nj^}m={yN8y`U^^Db(@5uNAteX{pf8rPJ}wBB!&VgP#{`ltkYQXZLUYl z;p#MnT#azxzT-~wM1KcjCuzTC|Fk9;Q@Rap&I~x1AzgXrAau|c2uqw8pgd{zv|qmC zsd-`S^IPJn!G49acCE4A!gzh{$hf9u>&6vI+|+LcxxMo?V&B!rW34&Rw7-nKU5<5m zY5Kd^+3)mf)B>f>>GbR$jx!uxa}J|H>7|d0NsQ6)+&N1K`|clNorc`t<`<|Lhilf5 zn)b@uu#sR!*VF4A(&VWL_kinbLfAR_Vk3)^6i1dL!69^(|934V7IwZSA3P?PDixBn zR)+24Xf=^;l<5J15MB}Pf1s|RHWxGP!Wyf1_mB|NV}(q;j#JE1?nP6r@B5Ft&7^sG z*NaD6Os8c~4HW&Kt=pK1yV=@1@z~g7hmuhLW8Lbx$>5J6Ysw9Y9yrv*?bmPZe(<(+ zA7}^6?9>Xp#b>KF@E6+F;(!k;Zt}l6eSV2%=DZ95vTh^XhmYUcvj~n8PAQ;^v^})%C5r$a@!yx|YUmV?$?w zt6YG-{&&;zAa0MjP|^jE%+7xcD-zp(-b2*JLtWv8V>Xyp6Wm-yM(dWQ@@&aTk6b;J zAB#Ewj z^p(D18OHPL%tdRULt(7lt9=YsN}a1K8xlC*cWpMFHz8+~4Zq2tOSJ1?*u~}#bwB)e z`ys@(5`~z$IKG9&zi6`y*lOydoyUiSIDAOmx)?BqE{oj_2ke)g<8sZeEtjo^#2e|P z#@*A9Z{A&EG`^)Pq*nZy44C*n5>41}tMCo$S~SUemiS)Q!~EiS!P08+@Fq>T;qp#c zSn;(Ve1Hxm_!V}wl}vinE{1Q|4wi*rxDF&eOfH>O_g>n6bPIl@c4e;Uby2G02MjvM zsCjkeu>IH4tUey>Holb7RXwJ z`Ci^}&5MRj`IxcS08d-$>(`Y-Nzc)`tq>`6uKh3zLli!676$o7Fr z>7xS2hP&Ku=v14uY5>jHHZhq_@^0eI>h_D84dE$Kg^f0nP3mx{hB1`RajCB!=P!Qg zN3h{80ld;&74P!)fNr)vOEL-ioPX;_V4~>>BffN+)pN?acO+7ZQAqHB6ux44cF@YV zK{tIdQjS-w-d2X^#fZwsz@w_Z3T*oO&%TMxuiZjYwi3|gNxsvcVTpj3z;E?Ek2g@h zriqD;ig`uVM0!ErpX|T?Y%S2DjToN{S^osT?F`lL`TgMQKG{0KA{A~8tw=G36ehc6 z=wAOe_xM~mZlT2R?I+84sV5;@TW)Z~!HRPutuQajzykR=w`G*moM6*go& zwOcv#K$Q1WB)JPjB+jAZuNjsnxGRYn*Q;muPz0SZbDzdeU6eW~R&xef9kT@CCd!MJ zaJosUoT9)u{p-uH0UB3ZT?)f(;~=iyar&l7wS^W@?@~piyLKM_zXl zoYBvJ>+DTU5(%n9=j|s89jwdaXN&XlE{_s)(l_(pDll!(KJpO$?Y0Sfm~KsdqP=Nw zq#p*yI7SgeGED0{d}Cl%l^ENqUNY!08>rYVFy*Jqm*Y0=x^x91oYQY>Kp!;Vz18NQ z2$ET0KAdmrT;M${IB|=W82Yf~k8_u$!_Q4e0d+YushSLlQC(y(?W#3d4>J8J*+_9< zbKmd0W%b0MO&N5v_D<0|2Xj?|j?}F$6OY#PHiJgdFzS}$@>6|WOw<1EgKP1JC!?}& zNZ3AEpe;=I{&O}HB=Bz)qz*X`5L{+SPMm6Vq<(4U+fqeET?kZ~*|aDJ*SAnRp zi{G2JA&D{7u$3P;_j}ObDX;Z>oMRf}N4)~kWosnC8Tn>QX}hJKrhtg;pEZheXANX$ zLxr9_VnyX1BgS9igkTvx_sPP)V9|=d%P;%WEy<%=W^4!B2>xELJ`pOtiq%cCmX~^C zS-2-uR&6nczH@epQ^&=G!q2hsRKIjnZW8xuyLnoH6pX*O1&f4ztp6w4ulPd26LC}j zO2Mk|6BJYeC%6;k@0?pAx_l>6LHwiTp)b>Wyn@aQh!D5JYn6YR7p?bU58z()3V_o3 zTsQFX`#e7F#d?e1;K3p9hJ*?OuzO(gIV>anPNA>Qf#PF~E5n6Vb`S6I@NjNSFexu= zV{yi_@e0)^W=s)Gj*bZi>eyq>OEz_QvEsdy(f`=C>Tg(-0N=;5a0r~UttC3f%aZhN z-inw$#RK+YkaSM;D6=+rQE>S=LEAu*i6Il>58tZ3^LX*?qm9swj(-2gA6MtPEwv<0 zi~LnS!`b9JB8Z_2Q!qNV4%XBKOzPFR7Ur!*8cgf!zP-e8WR0`R%52iE9D$ zy`_)v0`l0GYSUah0oTj(oUWis39@YzUjpspK|(K+JMt3YG0w^By$;tN4&8{}uGB&% z{^mT<08^4Dpl#95fEP0sN8=%T7NqMSKHX z`(gdxd+|qC2q8Yil8wAWtOE+3xi$0Le5s*HEriHJg2NC7fSa<~ODAtG+dq5Zz z{ps;x>m~0xETh#Jd#&+C;ir>`hxPTKq^P)w0M>k*c;Om_FPk|aGsHB`+hW$HJdxDh zZv=i+*0x|<=6GC!YnX+6?`Lc)?vayi&Gc+TJ=b93;C2@VfI2(TX#pHR<3ECL&V1AH z9iaeo!kW9nyA(3m;^q~zXJ~sdCi13-O)ogBhBCtN*|1+3@=f;NvhCrci1SdOs@boy zxZrY^pMq6%ckQ}QuCp9XO1y>w!pw?7X+uJ$6KyYo*YzQ*T1d1;S|S08nF05iz(>}& zrm}E#M;#=q9Ens*m$0f7#JAc*`}DyZGUcK{^B1bDz94oAD`m*Bz5N93?#o8Hxa%iq zg$ObjF-_i#mD&uBeOb61^w~)xlnfGA-Xl^k+olb%QdvoI9J!csU>%&^49zRG|2Rut zcMZBAZj66(^*j0mK__wUnB~EGKL+hI&@LgIP`+;)Ft1CpEh8&0676td`K)_M_L^EB zptxHiC~x>7xeNWCN`B^=w9ifC%xM!nBks`Vx>dAZKOvipsSlEmm1WMgj}UE3MbIp_ zszf%pw+V8LoNK)QYvU+T^l?GW!ZP}n_~CdzLJG7~eJQ;z=b-`FHgl`r@5Xq4+DBju z&HtT0#ysUY=$~c(Y0aAlz_R!pZXTW6jDCwsD1pXQM2UO1-KiQ+m~5b&i+MV4Uoz36 zbA(20*;@BM@1yNRa~ZLELfN%D0~R~wCoH9jzq(o{h16EqH*|^U^p9n~+%)HhlDjRd zq1PF3LU0xRyMy;V*GW{hFY`#UKWzMbZ7#p?InS>17KKD$3$$O*4k7(lO?rLrqYir8 z>E7ocs`h+lOYCg|YF(&vH;b=&{k0WK_NAr648{NQt;_Ww(<<3R=v($xB9Y(O`8Q7r z(5M9M7u5W?O_{MKUCZ-n*)5)Ma1`u(Q%1iN!+iQ%!i{%E~my4j|r7%xSwDb2L-oO`0-GNht$NX#8x_HZgw^|`l1vX)Dk`&B3`_Vs7Kl+KFQQOVo_VeoZ*+so4K3Q(_Y0n~lCy5hh=m68q zUw6vXGfAbc(3ka*mwzZ7u^IPoePKw|IJ?v2nbqPW)p(QXDCx>(RMw_K>$D|kUJyRU z!Ocf5XOXJ7Z0)=2X>1tw#SqKO0^c!ZThRXk1x}14|!g|@?U%HyVF5l`i z;*+XO7yoO`cE=sJknUwn_jC4V>7ur_tFa>6pv0R)tp4(2OWHYW*&r<%b+dFE@eMX7 z5^rI!-}{8@8i_Jau_bf%Ns|5iuD>TX9A4&cfF#7&YuG*5*9raBPnnDzBxj1vEVQU%3Z5POwO@=+jixw$S-0zm*=$^7 z>T%<)k&Shf>GE%q(y&aCSyU5_=;3mB5)|I|k^@;=ZGPaR|KPpCf2wX4qPw56HQ&5A z5A++>zhP_T9dC4k|jN8we{4czTT-7osQWfZz50U;- z(nW3I`d57H#FI$1jJv#-syW?DLa#>8LGth-Lic+dP1)SWR_}Y-9fJO^TTFYO?rVir zNBtgUvRnE%-J4HiS$FqnKeI#gK^^C#w>%}f%he!h%DXy+ z3;I<}xkh=M(#`HmSJs%GpZ6=1YGcm9>8Q-ip7-~0tZ6lf(K^?0CvUmIXD0u+ zf@ieFE&`78UEa!ySDq0|rW{98&R(20qybGuYP>&&fe6dOPa`HH_3sYoo4MX)zKo+8 zu#OXgS=(f(3;gWc5R6&cQ#xa|%O#4P>^sF1rVpz95VWT4?5-?zcC*=w&VCUZ^omG?lvqm}p;Btkz~snt3z~By zzyD>_2MgV_{3U-|o=`*PuC}FKQuP$wcEq?Nv59a?ZLyYd4Eg#U;(4W&PvbSIE7esb zgyv`Gm8)y^dEcq#Xj5(;t4Etj-nMM*qs-mGZ^D%zHS@(lr=W*K;GM5Q$r2Nj-dpu! zpm4^buFKbv57bSQFVsjWD}Mgle3_pbu%`XWn7vHMr~ns6~^f${QWZ|)+@6MGg9`Hka<1`cxfY0w4Cz}Ak3?u?c&WChrXj^ z|HW7KlJ^WmDy9nDA4((TwVXD1NRN#t$w`^dDqd-S(KDD;B`KDH>5A!&Cb`<3v< zBZ8C7&NJr6-IlMzzNqtL>S|%#jogwgU!^E2CHs_4Ie5Scr(P9g6c~w^r4ee$%ceKX zN3QgS85PWa9Ghbj8Vt`v6k5_awpA>P060IVzQ``5=wq3=U0Rz@mhmh_r=}j7?w*05g_YAO`PH8^3xpPoQD&z3`4PU@Tr-AQ1 zKyh63ll!yJxJr(iWR#lwMc+Q+cOP#yT6M*ATTKxzGe#JsSxg?QojqO!#wIWFUJ46_ z<*pSg+4rlkCf2`S!59UIiX?k@t^(KV6-9Vq$VY>&oTm z0(M~#VES!S@qT8stzzZvr3*d~{re)Iu3jc?%(}wB;5CI#RcAinEs{i*sE-N9`6lVV z0=AuRx=$v|=m9!3;XrGe+?)nna})5<&q#X#r8OE)Ct*IZfSG3G zSa|BZ+JycFsra1nhw61t;}!6M78yl+h!{NmdE7P=uafuIM{bebBFmY)61hGZ!@h#HA4B^+g>+W_ddG!T+c3dPB|e<@la|`=9xy%1NRDAJ`;{o zbKo>agi2aq_c!VjO`b*NT$irIg<*jusbv|7y8e7H&wcf6_npbh1lG)&_3*F))KIV|2U3PgOZSxF9g9nGHCu))5~*I}3-^`dI-)#D=X z7p_#0q3E~A@O+*PhSs!e))I!roBDmt`DWJsU`P4E|~Ola8y-w4=VT$+&u#`lxa- z?+Y;(8)ZZCl04arsxe0m`3{|BH2+%q|X3|kI9*gK!L-mXvV1^s^(ctwXVlz)xRHwfr-$-n|D=(Q98WOUtAHBa5&#@E3}q6Y_tB8 zlPz6^AH&V|{&>MVYFr@wQNm@p8DDg%`~wMHB`H$RNd5WmI^+HTvLF5qOc$5or=(Np z@8ir@xy3j>(j_xy_`(7~xxi25wZ)V_y6%~yv_8y2^7J@ikHc9^B9WIpk?7rX{VwKvn+{Pn=lBPHQ>%6+>#x-@sm38M@x1`uM#g?gVeIRZcVI@S1-VH;fI{3Wt=D zKRMody6ey^^UJV^VngFENkEWR2W|D!e{R~`xY#;LmQr}1@y|-XZJLvSl#)*CrdhUX zM#(1~tIml|+LVJllJz7`ZQpDGru#syIes3cr+SpryvI+rGozDwCtN*E4iRjI{omv$ zWHQn-0bM*ztzw9}tm0RmPnL$Yf%Erm_4soQ{tu@>Sihr=V!Ag$ucyZLGR`mw#3nar zdC_{k0~B+Z&wQvnffmFsD1n37Zo%y-y`jLxIrL`UNSvO9MaEJLtIfm-B4-xfQq`5_ z>J=Q8;_+4qtzKV>c3Qow!p_m9Ic{){prr8#HQ~m>;*4!9G1zGVAQ;-Az3Dko`kW*^ zG8+r3Zvg6aytGJnOOntEkM$}rTTOayvfE%0kh1+W5@Jvi9kkf!}3F7pdpXrOc8A z0z2Q`xw+LhchYp#s|Kd={@e(jp-kb=Q2N4&O7|Q!pgR>_(HKLKPdwH(;}bEK=A<|j z=nd2JjDbA9x;;ATe^kj+Rz4`XO_`(`6jWr5)>rFDE~JRp-^jt^KpE8DiM~K3c|R-{ zDAf(0m^3_%MHrP(X_(#Z z;Pj^KZ|*!w}m#+_l|w6&=^hRXzYS?t1C(?JLn|F zYO|r!gqu!Kd})>VC_c3Zp>}s>X(0(%2cd#q_Q9eutr-TVYc!}eKKII^;YXIsAzo z&4PwjV3QlnVX+jBEb-D?(DrgaW%KpJxlv;Gz3r9?t6QPJZMPe`DEjz*Tr6_E?@-=(6G}(Hg$bXnZl| zCZ8diNPa`L9OO=CZ8B`E6)sPKwri`MZ-Q{R7N0pvg*6#jNJT9akUdQ5Ic;Q`4Z6;= z^;>I&)YdjZF$y%%{6sYtIb^wl-eI)aD`2J@EWn946H1EW+0cAthWS{djQmKd&_?U^ z`DU5bB3F-bV=~NCFY{W1J2&D4Lzf6E$)A0-K`@Wjk3X z06XAKCc08xG)_;x(ed&|M^S@_gQxdu+8}+mFo?~i;5!&iQ-!#q=2z$qRuo=E7KDG; z?Ez$|?3*AdX=0@!M)CcC7AEF6v&M_nOXF>>XuOzdVu5Dk^tGp(4EpOHiJu7;9IkT+3xfm z8yl@F_aS1?lB*URO+~tR9|US(#@yhQ(qb?dzV<${DPXcG@SP3cOdr`enQWYXvx(CB z$i~cMWA>X(Y_yMT%9(7+y=Nm1PrR=g7+fF6N)+UyJ|-p~llOciQu9@z;6^J}qDo&G z1vg%?lHtHtM!}6(tTYpRWfa_)#mOd(ubhJF?Rar|>9P%8wJBlBXBYTVwQzlR`ig`J zpIz=<597;(B2huN+Vp%S%{D6$wt7H3D@ARC*WQU>y7H&Gl=`VbsSlPzU$ybW|ASnu zz1NIpU+OnDySB?t5IZH_Tge`6E?!qec*7x@|4bIahG??z)s7meHa(V;;ms!>T=+3rY9>R6MM z8h@K3<{Q{pG1sKr>NU4!iLqpU?*kVQm(3(UXT%$afv@QWe38fYOxd4cdp0Y?`dA^0SQFv9`V)#Psv>+pIM)H78&gHaoMtu4}GHT%l zXs+2fDFqGL^1Yg9x>LYMa1KoZwbc8(PQ#{1;J4{;KS6P=F_*7Qmd$2~u5vY2ii;8M zf||WX#wD3d_~xLr2FUJ%l`tXf+#KaioOr27dbyeUZxf%?F%glb9f3qr%%c0(0PV1XbGuW8||v-ZX2k=W1)3T@YuG zrSmok(jo|@_-m?{6Gz@o?)(S+r98qcjaW_d(%*&H3{(@T-DL1F} zIN_wVVsVa_W8H`-QDw!h%`&QJzqMOPe4r!awNQpa=(wSb%uWNY+u#ekS!SmjCxD>w zTZqdhfYQ;zJXZlQEchR|6`q{QqK5_OI+6lKA}>WhUOGx3i;Wi|X>u7iQ|<e4sm~fn}woiizCB!N#kmj~nJiREZNW8AxXmOjkT*#LHgbY+Pm9v;j z%&yucLv4Jz_2!mjEGn^?cry}YKS?Q*XQ2Hm*IdGl!)G?+x*po}a&TkOeME>mmQ^EsWu<(eklh#Z zPl#2p{Sq024UOZ^w94v2ui$z|*H#N%*%54{#$Tk@3pSBbM|i*O5-GLaJ3^Fj?%RXo z?S>9RZeH`j8J}Z!IlRm`1-C)ateH!b=iZNQmy^$(RRB_Rp;V1GqPk8|^c;8r6b-u1^%FWcN zT!F!DaV3fAWB6aXVm~M#8}P*`IB!*~Y!6nk_akn?E4aF1zekNreIM&XyRyq~w4cOy z^02~hw2#E2=#f{QE}uQVnyY8OY0Zz1ZaB>GwES#@{N`!833(RWgglFGLZ0TEkZ18t z$kTZf@^syVJj-uFo)xv1C*BpsoW0C`O&Z=*r_902*<4JP;`8tE+*pJIkG%%P7AJMe8^Yfv*s~p<)-`}{o;XhZC>1O0w zP;fJHHJfinuEoVSBUh*MX5{K}-Hcqz%Wp=m6&1CVt2U*GGfv7ZD8SQnJh|deqVjhR8Fj&grOhE9xj>g^G)PJpGUbB25K;YNOcuB_+IB?&IQ1 zK64H+-|Mx3X#S&!y=~N;8s;saGH4 z711sEs*jy$mCqH)aFwSMs=TR^o$vdKVAWf8;5j+`0GyX)Q+9o@)X(j~Qa@MNsuE#B z&Lp$l$1+Tf&3>c>h3!xb(*{iC<$j^U;3$T9$=&ntky5Z4EYm~0#N!qsl}CJ`#0+Lu zO)ogO+{wA7(-#uwu|AMQ`t*eqM{A_G)8e_qudng@6FS)$jd;DDzUE#WOd-KP z${Ab<24z}9Abc-Rb9i2m&##JZQlgszWnZAgF9?KRq{J@@gl|^jn*-q&EAfj1;X9T1 z&OrDsCB7>Vez_9AJP>|`62GDfzQ_Dq#T+U(0Mq%PqmS*$UR}b2Mbh9(*V zOgUVM!Cqu@aMAb?JAd&Y!Mgm#j|Ou06Caa;*K+(I#0ooE{xI^ac>clr1s{Pt@RVh>~u1b8h?@U#Vf%l{Ums!oMB#b z#1l`WglCOvaMriN|9x^zq!mByT%l(-vAp0$m+@r7mqcIa#zQIm1E>6jF~wnKZM0r* zcf0ghCxa0mes|)hY^_Gl*KM3^FDGKf1IBUsEPO>v!4#N&!c#I%PB@`s!m5f_`wBUi z-E1OG;cSkR<9|UQ|5g+a@b~2KhaJl0f4CeKm<9ja&CfgjCm-hRKBGn}z6;D>vn=(2 zG}`8vlx`J5d?7^%2h1>^5$+NnShX@ayx+`>^iiZzv{F<#GP9I(;0IYnrBke!UT?xd z7xrWE;vIABhuLexC(U*Ab#TRfZx~s8#Xz6WE5Q7_T>-M<&0?BJ{&}7PP#0XfOnimy z#`BcD_)~)%vjbLBcr7ltNedY%o{{7`JJ^24`_%@MiEoPDs1R!v7o?+$ZDy+vA(Nu8 z`D^s-qiE6wuS7QTQ@Z@VE@)5b)|+v$NXosI4(dYovR&Wk978Ep{c>$-CfO&sYvVL6 ze+Nf6V47TkxyyEmGi;)Mib^40bnTTKi_H>DPSC8{I^iro5N^zg0ZPediuCm4%^0hA z>@uNIe3#Wyv#Pd=DN;5{wN#}1@)Unt0S)r}+n_gx%(Yr&*Nv#fbMJn-PbgMSw6fs#_`4-id6Mjt_(9?Xcp+IOr}-8BBN-haI;X>ROwqUC?3B_xEX=Xm20Ii55SKBRqIIM1ONCO5bU&dG&5iwfuc9C))G598pH$ zHS{bhy$gB}m1aQ2DbW>YN%t0Fg$UvNL`AL*1%J7MT8_im2z!k!j2Haff=^ZvqX~3ne#9Lg@!Yq6# zO+2Tfz(`1UX1lFcG16liqJu^34x`KBdEUg}ayj&L=#_!^(IRDtlXD4g2l3xKsuIV4 zECMZzo*4f7U$Q5JECrxCy6g_K%>e?o^rh}Rm)YXfX!-B$3^Cvro*f#k@PiMNTihwK z@Zs!Kj-Tsx3s;VJBy@J0#ezE({LWQyX(+aqPa9ks%GKo66^`2~o1hCSuRObnH+J24 zUa>SQa}CqS;X-B2lfSCu2RRG6%k!{&AY^`m1(~z*BksP@v_YXMCYv9$;0k5GvgqK9 zZimxc%IUp-=Aa6OmoFYv!C{{UW1^XN4}E@!4amUf?DF?BDMOzU1V0 z$%qw~43Yo%?o=JgpTaq8gu@v~-yPG45U?uYm%`rUm19Jvnw=6D7G>{PJdcfU>;X5P=ihta{{RG)wk@##$-}wFYHD(&uIwW?NUMG_ zJ|rEA^mc$s>-zweBEy7K8~-B%iuHfr7yH0_2jI~}cU9gYM8;)Wy)#%LI)1ppZ1u`| zXuSV{Ddh*od&-<5x65QJv+BIZ``;whdefq`RkbMZS!-)6>tWuhjlWo(PN}V0_vGYR z>C#I1BUn{N8821E;Ad<3XpNSia7Fx698TOHEK1KXYdqh*mCv%F!mgjMt9@}bx!U(% zSGn{?Ye*|o?V9NLJ8Nd27bAz%LhsdH-Ku@V@IM;I+PQW4UlCo6?`!@?6*O9OndTd; z+YQs)O&QV~p9!@!b~juTW{?MSC5FLD2oPAcpyZwNEKTWjMW5!iX;es7Ou*mCpvpDl1v>4fk(9BjmW+Nrm zRs9ZHFqV_zYPZghIi)x!UNWZ?`!J`(2e~m2?`>ls-v7qH|B1HwGZn>qb{B%FeC^Pm z@J%kiO-u3Gv;=)R!~{25Dc(jarMjc_f2G0xhA<`gAuRS=2W?<_(gv!G*1PGEE)CUx z8sR^Z3U0h+H@xQgGZEaB^+p%iu)~LBx?MrpkF+(nA8Bi>qj)ov&{s5Kyu6~35a6kn zl$vWKH(Zk%N?kQAw>D+a8n^uhCC-|bD?Rt}-<65yg7GA5Y(B_@Z%Hz8d*vsw0lA%x^}LVTJjjW$-k@h!yRqpqBB zlJL@u{2!NO5nmjA4Ek2{QLW^j;_{k^*3LZSB?NFMof4duxdQmJdC~?CLcErlGS}J@sS*xK)N%VmVUx*3AJ^fatB;1Os z8mRRWs6606!!%yP=vS$76`_jzEV3Z+lT2Pp@*XFAL*8U@R+M-?ZKE%cf9b|-!~Mk) zAQn>MMw;P2Gp@KdBTTs1?9mzc@MUD46@9P!h9Zte!12BZNRi?L<&qFE3mA@kA2Gr^ zOiJm8#_33b(`c~b=U7WUzY5BvFwajsXy?QW15W;1?k2OfOvAa}Y?#b=~gww5jA+Xe;Ad0sh^dv zcp#(b-*E^1Wj7RZdRjeNw`c(!{#y47A-96xmHIuXpK+JqXHkD5^-a`Y*kAA$Q~xRI zucdyE0fOI~`We*EqJA#*$54Mf^(Ru_M14E;UDTgV{dv@1LH!NX-$ec0)Za(_52=5Q z`b!7W^wi%#{bSTWMg8;C?>|WJ6RB^f{xs@WQhyWmw@`l{_4iZ1bt3H_>i4F8f9fYv z|0(M4rv7p2pQip<>XRhF52bzt^?Or4lKQ#Sw@}|s{l(N@Mg6C!zmNJ|lWBda-<$f8 z)Q_fqJoWoiKau*W)E`3q4C-f5KbQJrs6U?i6RB^aei8NU)Sm}*sICL!ihf-f2lVSf zJJ1h<`T`xQ>q9-!Zvf+n;SHg^=r@9KLccK~w_$t}$QS*lP+#=Jp}y!hgLa^Q3ydG) zH-~;kxCM+0!YzR=5pG3DIl@q}73jAnsQ{Vq@*`dwlC(eDQRjriSR-XVND&@uWwfd0_$3H^%k zy$Csk@EwGFiGFWFcA(z}#u@#-Fn)-4C-gu1ksNwh5kT7!qFc@NDK56Aso{s zL$>IrKz)HPsZ*hz2-k@IqbcB8(j4%2{ z&|jF&4D^6-F_eq`BtpV4+yeB9ehJV$hFgK25eCkG9AP_*5Bif~ywG<59is09`b6Ia z^4&|d=eM!ZL$Us6Iy%T>@XNGDG~xdR3N>>$D4kKs>3 zx`Bd!dXV6U1K(Fa1@#^%_+bdIf$<$E_^lCs8qyCG{7{6Sfqot+_#_p|-3a}S{tGZ} z=x+u*^k0Ph(BA^>#`?Vk9P_zPMJmysr6Oyw{CSWL z;}@w&5z^aY6*-Ij`7orT{+AfP6!0+JN)_3S@Z(Tl?9bIIl7;22fp#LiRz=33zfMIG z(ccLD!_$e1?8EdsRb)0le$Z~rf47QU#CpE2A}cU{zlywq{xKC<$d8|j48im#Rpctx z_gfeb%=bGL3B&jwRHOyw^AofO!>>TO2ww#s)BOqkgLu~fAIrTC`J(?X^aJ9xWK0^PD;7InU*s z=R9XJnUW5qN3mok)*sE1dh92GC7IZ63`-W{bt6m4u%EFkabbBfOPp9f5$YkINi5ML znpjeYd{SAGhI}%h+(PjPmfygVwb;(Wk~@&jVMz<(JeC~9^7$Y?(u-N*M*Jm9Y{=(V zpa;^0EZK$n-OrMXXjcdDL%I~?N4b`u#3Vk?&fT z9K(8#Lw%%w$C4n{dy*x!NI%VzY4Uht$w_SYJWCd#9X7FKFV@=%cEoxwv&3MbxCQA~ zfyV2NEIEgIZD&b4()+;P$md;_@JJtI$$YGT2=qYO1AfE$Ei5^W_#R6Hy#78*h=rmT z+y99r+wl6Ip&rV24D?p;oPsA2kApr6UR2P8?Ez!3zyE@AL@!H@VtG5*1@RR45$$ps zXuN&~{D=Mhoh9oLzW{&W^-i!8(gCmww(9~K%X`63Sl$PS<^KdbBYp$p5c#P&QjfHT zBgLp+7)OF~{>Kq3mg_k(A2Es}TaZr-M;h^ZEJyY#D9PiPBMtKSdg91f0rrC>6a12$p(r5x#y<0eP;qnu?NS%c*j z99fU`oS+Z(zXJFxxCP4r&tW?kM+Br-bHs$#ALIycq4*V+|Ar%r5ou# zU@x>sE%3qe^-vG#Cplt9`uE@mj+Y$ShUE<$*@*2MK|j=IJIIUWJAg0ZPOuB& z9?%={5J!$;{lm}>>5ssVh#zyrC68Z@*l@fY2Y)NLS010h7yE4mzNpU$jyUD<3H_p6 zpMjr{{wqgn5l@2Mk>6?P5AApc>;buGQ_~K&gc!coebh>^DTiXcNU?4%MVpP*H{??K zq=I$xXnE!>l$I0>&Zn4vD@A?*MX!SOkh|`l9p|pS2irHgHzK|f?ry&qk#l$bf|mFH zg7Oz22W@&i#=Q-4&!*kPJq>ctrd?|HSBSf3xEl)by2{;HM9Z5>Xg^(uJHp*-Am?n_ zN!*Jd*KFd~x_^b()Z|{Q(8UT}sL*8&+J0LprFWGo`YfeA@1Vb=T=bt&s9=;Os}Tx?TD|l zZsSVYK5Zp!pS6-+H?E>|+$u^}ucC5PKS24NMBJU~zUV?^-N_Hq^0kP&t!hU)#*Zzw-=4PvA_i1@n39selp*M_)*bCb2SUHoHI{xTWgaEp%vHZtyC zJx=SdeVq35+2honZ`NY@E_dDU6g}3_>$U4>d)E`xPWttze zkEnBhwTarTVGFhQu`RT{`31B~vfJn_r{!9j{S(qe4rsQ9o>JRP<@2 z^pWlKdIwyUAzH{OYI!FmtHU1 zi~2C`nfnxb?4$LL?W6VL-=gFBk+-Nkjc?KNlL{Sti?;jzE!r;aZQ9=*Z&QEy-d5tm zetLb?eoDWn&`0;vdie)vKf=4{PnBCbi25+@qlf5q+hNN0;ls4Qw+>T2=M~!b9*|5X`}f2DN%NlFVRDc!Enrxm*HZ**Nb`8l=6meX{eC!fLcFt_dRSiajG z=~LQ&N&OZ774|>TUHcE}Pv1YNUrb+9e=Yu+ju)pwH-1g8f2Pp-v-G+RaR=kxc$SXG zqcU>t_zqe>tAp~d_G5nzUnI-&4N6?24E?IMuxv_TaMp5O?d{$J7iR zU$7TPzcj%f9Q&z-y|=tR!QLC=!f8a1r&7nr{q5J$dZ!UV&r=HBrO-0M`rHss>Bex% zuQrm_^G4EsZBbZH=ayvT-TR|y{fp7Go^d22>v41>Z9g-H%99pLudhJ_eO+-39Y>=8 zcWK?l@l@Wl(Ny0>h~Qs)0_Fd30&Txpp*3SDJ%0@4=azAoJH|-cCm3nHG=*Mdr1iHL zsa!1zeNL$-Bdph^af-dhQNF5c=yi%a+=~%moO%&qeNYLsd<`P3L-UiV9I6S7yzU*G zMB95OQMHuIp+0#_3e9Q`6~n!wpDByEkSs z@;HvUk+zS&kzQ|5=)E`6e#i`lyfK?`FPcgDxMwQ%pQ+TFN##2|leYg-Deq8d!_Bna z`kN`e?Pl7qbC%-oS@imjS(I;wLf6iwe7&=2`Lry`*Oo=wMQ79Ux@<}x0c5}rX%<@U zvQRrT%%Sbl=TUm?EtD?LQ?3KT{@m?VXjMKV=N*glDg8`7<$nwj@{hd>8M196Y{MN? zzW7o)pZ1ngy|yi7NF7}N@;CIlHIeAVB~nZb_Z?e+d=EC*-878cG7;L-=OrGH>mw~0W$dg&_0TW9FD|& z0QnxGhmd$gSksM&u%-)$?=d79aWg|qh># z<2hnNoWYVbL|B8(h+i{g8sfL$f5aDAG86HCSdxVZG1ZDVnI$&F@LL6YpV#M!RVn@7|BgKdeM;wUV3@Jl&!u&`4HAkuuU*L!f@g|O}K|H|{H{!Dl zS&O)uCAElu1OFo~;7FaU2TL}}?ZE$tds(st@n)7ZAU@2IZHVU>(kScCkzI(_v7`yH zhar0rcY*&APc!5o;*$(%K|ITnBZ%WzauhL*BgYVv7~+-n0sqVPfccLIIm2nh@eJ`H z&SlA0h_|z(0}Y7^10bq6vJr8Bkb1;EnE!~dCuu-z0{3Vg4h|2md4Hfd3Ky0rMXba;6|61 zNBk4ae?-WY42ZWfBnI&u%zwlM;D1EOp#;R+!T*SNfd3IY7?OtgHA~Eh>tOyPeh2d( zF@hsA5vOt_3$YsfkNDroFguS#K@g?v-VgvXe z@i6!w@dV6&L@&&LMA##_5MPG)k2nS9KjN<-{v*Bs{zt5Y`H%P&_#bg8%zs%{ExU2{Es-6 zA;%E!0skXrbEF+{B1cXl-V6Sh?EwBqEQ0ut$ie(aTnzq~`LRSo^l{{zEI0UH)))Mb zXb1n#1B5-g3K90+Jfa@_kC@LA1LA$)e?-{p#UmDh{}GG9|A(0{R&^k)Lx#a~#_%Prgojpt; zpA{=FWl~*IxxBO-pR|`BJENty7L-Gs%G*mSSCtl(P(Bvu<^IZwmF2~h7Aq=CLg_gb z%a<3(1U@!2%{*NwuMkS`M>w;9zTRv`dO0YI1wc;$x>~4O>2y|9R?kx88!9hd?kp== z4$WsN{H9E$<>jSV1pLi#z6zho7YZuxUx`(#X3>7=YX*giqN0_Rg8Y2xAbY$%O~79; z{P1<;3q~m~C=0nJ_m2I$K%VEO%Wr60O3OE_ytFT7R-It(!$ zv>$z8^{gM_^FT>ebwxR~$8}iWiQcTLDwPWdpnWg!M2j|9nJn6jTX?B_-to*vIKCfiY5sFa29h%u}XbH|_fA zH)P&eP*_x4vcyFmAjK8J;7eJk@4;LGjdh=o>wQ@2f?j(2DYV2L}u3A0JAD`ZI=DlmT1i+Hm26D@o|z2NZG#y;!(3 z4L<~Yx1mr0<7i1)#RKVBguf06WsoKmD}P((61JkO2?|sq|Gg!_DgT)cVenPsX+rt% zAI%eP7Ovnpc_n`u&m_vE3RG6YUPya z^xZ4}A%6c+X8#E;_~WVnl$Sy{U&0sV8y+y1Hv*Gn%8{$Oa?13fxgeL8R?Qf$TBRs@ zNg=e)C@)xEGBv&0RZUN)$fv&;Zf6=kO&K1o#lIBj&!h0g($^N@e898e3d#(_w`-Hj zrtC_gxS}NV`p@a@vW0oZjEZvk1#2Wv!GDX%aCQ(f_gp1Kg8cg*LZb%6^=eqfhN1^G za^ez2-^$WeUb8rm&g z?uj$R2=X~CmdE38p(#Yg6s5`#Q<9#Z0sk+-gsA|3gqJb=n~@9{1yEX9oKX!6dIltW z6)Ry*W)v>3s#*=p(sC?T61EHlZ?7!MkXK$DY&goMWmG|t^U|T0UgUKC`{TaCDGz&q z%j_!uMs1kYjG+`me&vNwQ7O+ltTfzEb|C&#M*cY*WUghUFo^N@DwrqYZ%2hC&`^H8 zrhu>4OcPdCl?e0|zjEkNUiKBrv#`1V26{npaV2I4kj!8&!$0PPr5V;>CBR{5!zGzU zy~5Q(F*vIPBJ%@|Qs@D$6cv=qf)|$1g}nT7z3ET+@Gnw9W>c~%gX%&q`RydR^hc7H zv!FlngZy(amhFXu&Hpnq#cammk&d5|1I<&ctMGB|0L6o=?TE_n;-AWKL(FA0u{prP$Tr{l1& z^!IIY)*8B^7n8YAKo@hxo64H5P?xOV#s97!LiUXRCWnw+X2{5s6RRaK$NuF!`-(KX zteD^$Ea1n=DrBX&g~;!YFOfF|!-Y$VLn-A z77nd8xLKy&MoW6cp4kxSPfl2HVax

    XV8NSu89gO5 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 ti6z9y#MIgjx|nO^0A2C$fN-+ +#include +#include "ability_connect_callback_stub.h" +#include "ability_connect_callback_proxy.h" +#include "ability_loader.h" +#include "common_event.h" +#include "common_event_manager.h" + +#include "form_provider_info.h" + +namespace OHOS { +namespace AppExecFwk { +using AbilityConnectionStub = OHOS::AAFwk::AbilityConnectionStub; +using AbilityConnectionProxy = OHOS::AAFwk::AbilityConnectionProxy; +const std::string APP_A1_RESP_EVENT_NAME = "resp_com_ohos_formst_service_app_a1"; +const std::string APP_A1_REQ_EVENT_NAME = "req_com_ohos_formst_service_app_a1"; + +class FormStServiceAbilityA1 : public Ability { +public: + ~FormStServiceAbilityA1(); + +protected: + virtual void OnStart(const Want &want) override; + virtual void OnStop() override; + virtual void OnActive() override; + virtual void OnInactive() override; + virtual void OnBackground() override; + virtual void OnNewWant(const Want &want) override; + virtual void OnCommand(const AAFwk::Want &want, bool restart, int startId) override; + virtual sptr OnConnect(const Want &want) override; + virtual void OnDisconnect(const Want &want) override; + virtual FormProviderInfo OnCreateForm(const Want &want) override; + +private: + void Clear(); + void GetWantInfo(const Want &want); + std::vector Split(std::string str, const std::string &token); + bool SubscribeEvent(); + static bool PublishEvent(const std::string &eventName, const int &code, const std::string &data); + void StartOtherAbility(); + void ConnectOtherAbility(); + void DisConnectOtherAbility(); + void StopSelfAbility(); + + std::string shouldReturn_ = {}; + std::string targetBundle_ = {}; + std::string targetAbility_ = {}; + std::string nextTargetBundle_ = {}; + std::string nextTargetAbility_ = {}; + std::string targetBundleConn_ = {}; + std::string targetAbilityConn_ = {}; + std::string nextTargetBundleConn_ = {}; + std::string nextTargetAbilityConn_ = {}; + std::string zombie_ = {}; + + typedef void (FormStServiceAbilityA1::*func)(); + static std::map funcMap_; + class AbilityConnectCallback; + sptr stub_ = {}; + sptr connCallback_ = {}; + class AppEventSubscriber; + std::shared_ptr subscriber_ = {}; + + class AbilityConnectCallback : public AbilityConnectionStub { + public: + sptr AsObject() override + { + return nullptr; + } + /** + * OnAbilityConnectDone, AbilityMs notify caller ability the result of connect. + * + * @param element,.service ability's ElementName. + * @param remoteObject,.the session proxy of service ability. + * @param resultCode, ERR_OK on success, others on failure. + */ + void OnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) override + { + if (resultCode == 0) { + onAbilityConnectDoneCount++; + PublishEvent(APP_A1_RESP_EVENT_NAME, onAbilityConnectDoneCount, "OnAbilityConnectDone"); + } + } + + /** + * OnAbilityDisconnectDone, AbilityMs notify caller ability the result of disconnect. + * + * @param element,.service ability's ElementName. + * @param resultCode, ERR_OK on success, others on failure. + */ + void OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode) override + { + if (resultCode == 0) { + onAbilityConnectDoneCount--; + PublishEvent(APP_A1_RESP_EVENT_NAME, onAbilityConnectDoneCount, "OnAbilityDisconnectDone"); + } + } + + static int onAbilityConnectDoneCount; + }; + class AppEventSubscriber : public EventFwk::CommonEventSubscriber { + public: + AppEventSubscriber(const EventFwk::CommonEventSubscribeInfo &sp) : CommonEventSubscriber(sp){}; + ~AppEventSubscriber() = default; + virtual void OnReceiveEvent(const EventFwk::CommonEventData &data) override; + + FormStServiceAbilityA1 *mainAbility_ = nullptr; + }; +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FORM_ST_SERVICE_ABILITY_A1_ diff --git a/test/resource/formsystemtestability/formSystemTestServiceA/src/form_st_service_ability_a1.cpp b/test/resource/formsystemtestability/formSystemTestServiceA/src/form_st_service_ability_a1.cpp new file mode 100644 index 0000000000..dfe34180b5 --- /dev/null +++ b/test/resource/formsystemtestability/formSystemTestServiceA/src/form_st_service_ability_a1.cpp @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2021 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 "form_st_service_ability_a1.h" +#include "app_log_wrapper.h" +#include "common_event.h" +#include "common_event_manager.h" +#include "form_provider_client.h" + +using namespace OHOS::EventFwk; + +namespace OHOS { +namespace AppExecFwk { +using AbilityConnectionProxy = OHOS::AAFwk::AbilityConnectionProxy; + +int FormStServiceAbilityA1::AbilityConnectCallback::onAbilityConnectDoneCount = 0; +std::map FormStServiceAbilityA1::funcMap_ = { + {"StartOtherAbility", &FormStServiceAbilityA1::StartOtherAbility}, + {"ConnectOtherAbility", &FormStServiceAbilityA1::ConnectOtherAbility}, + {"DisConnectOtherAbility", &FormStServiceAbilityA1::DisConnectOtherAbility}, + {"StopSelfAbility", &FormStServiceAbilityA1::StopSelfAbility}, +}; + +FormStServiceAbilityA1::~FormStServiceAbilityA1() +{ + CommonEventManager::UnSubscribeCommonEvent(subscriber_); +} + +std::vector FormStServiceAbilityA1::Split(std::string str, const std::string &token) +{ + APP_LOGI("FormStServiceAbilityA1::Split"); + + std::vector splitString; + while (str.size()) { + size_t index = str.find(token); + if (index != std::string::npos) { + splitString.push_back(str.substr(0, index)); + str = str.substr(index + token.size()); + if (str.size() == 0) { + splitString.push_back(str); + } + } else { + splitString.push_back(str); + str = ""; + } + } + return splitString; +} +void FormStServiceAbilityA1::StartOtherAbility() +{ + APP_LOGI("FormStServiceAbilityA1::StartOtherAbility begin targetBundle=%{public}s, targetAbility=%{public}s", + targetBundle_.c_str(), + targetAbility_.c_str()); + APP_LOGI("FormStServiceAbilityA1::StartOtherAbility begin nextTargetBundleConn=%{public}s, " + "nextTargetAbilityConn=%{public}s", + nextTargetBundleConn_.c_str(), + nextTargetAbilityConn_.c_str()); + + if (!targetBundle_.empty() && !targetAbility_.empty()) { + std::vector strtargetBundles = Split(targetBundle_, ","); + std::vector strTargetAbilitys = Split(targetAbility_, ","); + for (size_t i = 0; i < strtargetBundles.size() && i < strTargetAbilitys.size(); i++) { + Want want; + want.SetElementName(strtargetBundles[i], strTargetAbilitys[i]); + want.SetParam("shouldReturn", shouldReturn_); + want.SetParam("targetBundle", nextTargetBundle_); + want.SetParam("targetAbility", nextTargetAbility_); + want.SetParam("targetBundleConn", nextTargetBundleConn_); + want.SetParam("targetAbilityConn", nextTargetAbilityConn_); + StartAbility(want); + sleep(1); + } + } +} +void FormStServiceAbilityA1::ConnectOtherAbility() +{ + APP_LOGI( + "FormStServiceAbilityA1::ConnectOtherAbility begin targetBundleConn=%{public}s, targetAbilityConn=%{public}s", + targetBundleConn_.c_str(), + targetAbilityConn_.c_str()); + APP_LOGI("FormStServiceAbilityA1::ConnectOtherAbility begin nextTargetBundleConn=%{public}s, " + "nextTargetAbilityConn=%{public}s", + nextTargetBundleConn_.c_str(), + nextTargetAbilityConn_.c_str()); + + // connect service ability + if (!targetBundleConn_.empty() && !targetAbilityConn_.empty()) { + std::vector strtargetBundles = Split(targetBundleConn_, ","); + std::vector strTargetAbilitys = Split(targetAbilityConn_, ","); + for (size_t i = 0; i < strtargetBundles.size() && i < strTargetAbilitys.size(); i++) { + Want want; + want.SetElementName(strtargetBundles[i], strTargetAbilitys[i]); + want.SetParam("shouldReturn", shouldReturn_); + want.SetParam("targetBundle", nextTargetBundle_); + want.SetParam("targetAbility", nextTargetAbility_); + want.SetParam("targetBundleConn", nextTargetBundleConn_); + want.SetParam("targetAbilityConn", nextTargetAbilityConn_); + stub_ = new (std::nothrow) AbilityConnectCallback(); + connCallback_ = new (std::nothrow) AbilityConnectionProxy(stub_); + APP_LOGI("FormStServiceAbilityA1::ConnectOtherAbility->ConnectAbility"); + bool ret = ConnectAbility(want, connCallback_); + sleep(1); + if (!ret) { + APP_LOGE("FormStServiceAbilityA1::ConnectAbility failed!"); + } + } + } +} +void FormStServiceAbilityA1::DisConnectOtherAbility() +{ + APP_LOGI("FormStServiceAbilityA1::DisConnectOtherAbility begin"); + if (connCallback_ != nullptr) { + DisconnectAbility(connCallback_); + sleep(1); + } + APP_LOGI("FormStServiceAbilityA1::DisConnectOtherAbility end"); +} + +void FormStServiceAbilityA1::StopSelfAbility() +{ + APP_LOGI("FormStServiceAbilityA1::StopSelfAbility"); + + TerminateAbility(); +} + +void FormStServiceAbilityA1::OnStart(const Want &want) +{ + APP_LOGI("FormStServiceAbilityA1::OnStart"); + + GetWantInfo(want); + Ability::OnStart(want); + PublishEvent(APP_A1_RESP_EVENT_NAME, AbilityLifecycleExecutor::LifecycleState::INACTIVE, "OnStart"); + SubscribeEvent(); + + // make exception for test + if (!zombie_.empty()) { + std::unique_ptr pWant = nullptr; + pWant->GetScheme(); + } +} +void FormStServiceAbilityA1::OnCommand(const AAFwk::Want &want, bool restart, int startId) +{ + APP_LOGI("FormStServiceAbilityA1::OnCommand"); + + GetWantInfo(want); + Ability::OnCommand(want, restart, startId); + PublishEvent(APP_A1_RESP_EVENT_NAME, AbilityLifecycleExecutor::LifecycleState::ACTIVE, "OnCommand"); +} +void FormStServiceAbilityA1::OnNewWant(const Want &want) +{ + APP_LOGI("FormStServiceAbilityA1::OnNewWant"); + + GetWantInfo(want); + Ability::OnNewWant(want); +} +void FormStServiceAbilityA1::OnStop() +{ + APP_LOGI("FormStServiceAbilityA1::OnStop"); + + Ability::OnStop(); + PublishEvent(APP_A1_RESP_EVENT_NAME, AbilityLifecycleExecutor::LifecycleState::INITIAL, "OnStop"); +} +void FormStServiceAbilityA1::OnActive() +{ + APP_LOGI("FormStServiceAbilityA1::OnActive"); + + Ability::OnActive(); + PublishEvent(APP_A1_RESP_EVENT_NAME, AbilityLifecycleExecutor::LifecycleState::ACTIVE, "OnActive"); +} +void FormStServiceAbilityA1::OnInactive() +{ + APP_LOGI("FormStServiceAbilityA1::OnInactive"); + + Ability::OnInactive(); + PublishEvent(APP_A1_RESP_EVENT_NAME, AbilityLifecycleExecutor::LifecycleState::INACTIVE, "OnInactive"); +} +void FormStServiceAbilityA1::OnBackground() +{ + APP_LOGI("FormStServiceAbilityA1::OnBackground"); + + Ability::OnBackground(); + PublishEvent(APP_A1_RESP_EVENT_NAME, AbilityLifecycleExecutor::LifecycleState::BACKGROUND, "OnBackground"); +} + +void FormStServiceAbilityA1::Clear() +{ + shouldReturn_ = ""; + targetBundle_ = ""; + targetAbility_ = ""; + targetBundleConn_ = ""; + targetAbilityConn_ = ""; + nextTargetBundle_ = ""; + nextTargetAbility_ = ""; + nextTargetBundleConn_ = ""; + nextTargetAbilityConn_ = ""; +} +void FormStServiceAbilityA1::GetWantInfo(const Want &want) +{ + Want mWant(want); + shouldReturn_ = mWant.GetStringParam("shouldReturn"); + targetBundle_ = mWant.GetStringParam("targetBundle"); + targetAbility_ = mWant.GetStringParam("targetAbility"); + targetBundleConn_ = mWant.GetStringParam("targetBundleConn"); + targetAbilityConn_ = mWant.GetStringParam("targetAbilityConn"); + nextTargetBundle_ = mWant.GetStringParam("nextTargetBundle"); + nextTargetAbility_ = mWant.GetStringParam("nextTargetAbility"); + nextTargetBundleConn_ = mWant.GetStringParam("nextTargetBundleConn"); + nextTargetAbilityConn_ = mWant.GetStringParam("nextTargetAbilityConn"); + zombie_ = mWant.GetStringParam("zombie"); + FormStServiceAbilityA1::AbilityConnectCallback::onAbilityConnectDoneCount = 0; +} +bool FormStServiceAbilityA1::PublishEvent(const std::string &eventName, const int &code, const std::string &data) +{ + APP_LOGI("FormStServiceAbilityA1::PublishEvent eventName = %{public}s, code = %{public}d, data = %{public}s", + eventName.c_str(), + code, + data.c_str()); + + Want want; + want.SetAction(eventName); + CommonEventData commonData; + commonData.SetWant(want); + commonData.SetCode(code); + commonData.SetData(data); + return CommonEventManager::PublishCommonEvent(commonData); +} +sptr FormStServiceAbilityA1::OnConnect(const Want &want) +{ + APP_LOGI("FormStServiceAbilityA1::OnConnect"); + + sptr formProviderClient = new (std::nothrow) FormProviderClient(); + formProviderClient->SetOwner(std::make_shared(*this)); + std::shared_ptr thisAbility = this->shared_from_this(); + formProviderClient->SetOwner(thisAbility); + + return formProviderClient; +} +void FormStServiceAbilityA1::OnDisconnect(const Want &want) +{ + APP_LOGI("FormStServiceAbilityA1::OnDisconnect"); + + Ability::OnDisconnect(want); + PublishEvent(APP_A1_RESP_EVENT_NAME, AbilityLifecycleExecutor::LifecycleState::BACKGROUND, "OnDisconnect"); +} +bool FormStServiceAbilityA1::SubscribeEvent() +{ + MatchingSkills matchingSkills; + matchingSkills.AddEvent(APP_A1_REQ_EVENT_NAME); + CommonEventSubscribeInfo subscribeInfo(matchingSkills); + subscribeInfo.SetPriority(1); + subscriber_ = std::make_shared(subscribeInfo); + subscriber_->mainAbility_ = this; + return CommonEventManager::SubscribeCommonEvent(subscriber_); +} +void FormStServiceAbilityA1::AppEventSubscriber::OnReceiveEvent(const CommonEventData &data) +{ + auto eventName = data.GetWant().GetAction(); + auto dataContent = data.GetData(); + APP_LOGI("FormStServiceAbilityA1::OnReceiveEvent eventName = %{public}s, code = %{public}d, data = %{public}s", + eventName.c_str(), + data.GetCode(), + dataContent.c_str()); + if (APP_A1_REQ_EVENT_NAME.compare(eventName) == 0) { + if (funcMap_.find(dataContent) == funcMap_.end()) { + APP_LOGI( + "FormStServiceAbilityA1::OnReceiveEvent eventName = %{public}s, code = %{public}d, data = %{public}s", + eventName.c_str(), + data.GetCode(), + dataContent.c_str()); + } else { + if (mainAbility_ != nullptr) { + (mainAbility_->*funcMap_[dataContent])(); + } + } + } +} + +FormProviderInfo FormStServiceAbilityA1::OnCreateForm(const Want &want) +{ + APP_LOGI("%{public}s start", __func__); + FormProviderInfo formProviderInfo; + if (!want.HasParameter(Constants::PARAM_FORM_IDENTITY_KEY)) { + APP_LOGE("%{public}s, formId not exist", __func__); + return formProviderInfo; + } + std::string formId = want.GetStringParam(Constants::PARAM_FORM_IDENTITY_KEY); + formProviderInfo.SetFormData(FormProviderData(std::string("{\"city\": \"beijingA\", \"formId\": " + formId + "}"))); + APP_LOGI("%{public}s end, formId: %{public}s", __func__, formId.c_str()); + return formProviderInfo; +} + +REGISTER_AA(FormStServiceAbilityA1); +} // namespace AppExecFwk +} // namespace OHOS diff --git a/test/resource/tools/bm/pageAbilityBundleForInstallNoSignature.hap b/test/resource/tools/bm/pageAbilityBundleForInstallNoSignature.hap new file mode 100644 index 0000000000000000000000000000000000000000..acd820c6bddb09ccb3bc08ed9faa8edb9865f4cf GIT binary patch literal 17670 zcmb_^1yEhtvNrDS?(XgZ4({&m8Y~=Kg1ZNI4X(l6-GY0tU{@C?^HnC!X)01_zu&0}}m!)*Dnw78-`u0N<(e$tBO;_*MzlP0|pFmiCOTRG?_{!SE1^5(9w&ouH6iTMg{)dK%J_Vb3+5#ZY zF#mcUzcPUNw+t|Kuy+O;+XMgq<1_s(KJaOW{{Mxq!2toG`z?6ur}Z;A+FSmU=Rs?5 z6!*iG6eJPh@Zg@@jwmf9_Izr+dj7ybJ$=Wn2m644;J8VP0o2@AjX>Uc7MH>5(mCn!j8)9((L+I3{9s)SkuJMPt-<`9)Ccbm zHwImc58tjn-59_p<{R=L-SaE?eZuaRh2AoP&IJJ-PUs>h$i)Sqv%u%@z8my-Lp28> zpK-Imv8@tG7EOZ4LqlOi9!Dd_Jqc4~HCgk~5iu*fa5v?#C-f`&Md8bVkH$jikRWyuS@%+YtS`KM)UxHFzWj{neU;~*$G@f2- z>r6cv2!P-f>Z}PljoV?@Vxj9d27?8D0YPR@TD>I@9tG8X)jRsWv!nk&o_~4O>dAbU}vOkHAebvHUA6r6tj*sCbT)qog19?L2JwenuHQWcRwN^rK$e&iz7FSOLXNfA39 zV`~)=PA=}r7RfB=zI>=Aum?2I*ersm(a;7G<;B_<{_(4dKjhDbLxc`<>{iGI#G~>A1It4 zl`BQY$$(k*SniH%Asxs06kmhEACtb50EWfAx3rSn%bg`Ck~*tI z5&_Y+qHn4PE9-P}E5J;skOt2d^feli4}7H4RDqib+1AA>yo>Q;Ox8&D*#R6_Etqi* zM?ZYtrq$%0)&iSGa+1VgG(*Da=*(}!$T!r8wMWcO`-H{NL+8M)Y zae{JHH?ZW!F|z(UG<#wJ1k?LdZ3ZaEL}@jHSS3ik&4-GB!VPx2 z4SOlfrk2m&>0HR@BAuYA$HU;{ceTS4)(!~SHW4gj7YLE&$9SHiUwMf z!gGu5vN24hJ;ZlE0ApoDIc9b(HVc{3?(=G3F9GYP)!@^D+fe@vOL}oS)OdIbWr%pt zt40;A#@=|PGl)){U0l#$5Wb5D9qL`j$zJ43u#wvCB&D1=FDLQ6#O+rE!6=&jHcE5F`*Ivcs zv&%R>Lgb8Ci%WvW>}@JxzubUtTg?*$bt%p6iHk$EgUnzt5!Uko=x*ebqLKw8(I1bC zN`hL%2FgwbhFe=n0V?5#E~dA{U-BN*STk$oDawne>>vrSP@>TAXw;;p!bOn_tFmny zZS=%P4Av_GMjj!S%^Wr~XN~f8s(JbQ_7*U*vXaw=K7``R3r<+aBJ$gkI@Q5ZPJh_X zgmlw~!o@ zI<&{c7fQ=MNoIdH&c0qMoD{y=mKGES%rEDlJ*Tb|?q>J`i)gZACzdPWeh_-x9dD>N zD%dqEA+`A0BKtft7OxkOc5@wSoTQNHhTT(0jA{Aw`*>BXiam0JEMC&0f^PPVTRWa& zI*xgGCT5jHd3J;0sXETfJ$xN1It#_pY5>jtuzVp_$b-8mOfD|$Wgwi}eDJbolzuCn zH;%w4kj(s$wb2ZZAq^_0lfbtFQ{w@3V+FpDhgU}nFdB2Ir}uW1Qcc7Gs`-*Qn4#ni zjZL|Qez;Z`Wb=cH`=kBsaGNK*lcUs%;|}lH=k+t@#lv`y3Y1gdM1ZUsh>)81q0SO8 z#n-ZKJnr~gkbU2U+b1sN-1e}ryjq=EE+th?(!u0KAMTzG&Fn{dM$jAP(9)gFu53nF zJodbSKpQ3U4y|a#0r*G6+sIe_c$#H({ca4hyRwEw~&V zFrj;VK(S?wS$HtaSs!xuxrgW{lg=BNb&2yp2HX%Vy>Jhd!BWve{Og_~#}D&K0H+bT zl(v*sow!F5!qGsl>flvu^^oMdss%er;--%CGIbd>Oo+q2D2v+-`J{Q~8$HsNmw@r^ zM-t?eiE6!2y51Z68M~^PlKOIXvLp@O9n~a<_nImGatx;k)VXg(Go;qQe^LpD|+)Dw&@>m5)vUTZceV4GWHO4rfXVafn? zC3FWALE;W{xW&arbRfLFK?is#I4%RVrq%TKIOlsg-}&pozTow#ENyJ9XUK%vR|sUG zz69bX-Gr-suEpCGyo=b2imzp3LOrhv*Y=*xhlOJ^7`|lXQY{-7pfy?^2Wz{&n;Sfd zk;6)!0LGCitLxaHJI+=RxK3K?i5T~vq7f}nlTj@|a4g<}SH&JPh9VO1lj;fZ%8ogu zT({e0vZ2t%vW|pp`H38yr!?7Bu%<7aHRq#@8s`;F$ewwY_cgB&NZd2k)?ssfJUC;# zMo7pua`T)y2<}8P^Om**;1whInaP>BL!>Fd)OpDA*X~@I^06`$8p%p?LHncOd}%X# zI2I4^CgJ!1eFnZNQ9zGWnKBT7@^%WQ;~ode@z|g~;&z2acww>J1@t5Dthke^r(>t4 z+Tv3321ZOsUb2FrOYR)Y{3UOCdHZTnegKe>C(*xAz>>iolwepbeHPQ#M<0yqG;k3) zrzK#`7sp@~nvFF8QromI!>;Db_eni~U>kOw-6kKoRvZ}4n;=7n{px}}y=8RHiVY|V z`YLVuJKta=V{dzCfzFHZH#TD1n$<<-do{EtZXn7RqAk^XF>MP4GEZb1%xk&Gfk{I6me<6!DLHL^urv!6TOWN zR%ER7?sFv;-C=BGj;dA%?QD~7!i=;pc2$rfC>@Q&IRi>r7upgdmgF2irHN28Aqy4q z&XutxSJCysh(Ta{0+9o%7w&$Be#Ao1vQ)6ilfY8F@!V};FMp3&uklAK1Oh8)!do5Q z_Kc15+b_-$yl=XtFXfowc;Z}Gw%l&`2!?O5q-ARzZG5}yQTff01rhm0oYqn(7=r0B z@<7Q6@($oAjUikVf{Gw$q0a@^zS1|FhHuMiYJ}t|Hqvl)6-gC&B}$t0?KNFGEKZgp zY*gDR-QV*DAJZJ!dP&5Ah(LZ-N@yfE?V~2e81fFMBsmrX*C0am1`t9YL94zge#3Sq zC;P3R#n-UB^(GVAum!Fvn-e&`<_fcM!@lIkax&AQrhY+j`;b**v^~A0*9G5sjv>&& zsZrdqKR_yl>wY0@lKZu>k1IVYl+T=Ga?#zBU#|<=UJ(04fEY_Y;LubtI?cC4t4r4D z#-Rwyq}8Fo_5+}KYyXUxySHvxX(uxsZrx4q>>TuVdF)JRwda#asORdXc2h?_EjWU_ z(>GOJBc1eR0}xw-08ZxK+b=aQu^2Lxb941<^!@D+?e|V!K;6Y+F4gGP?hBVWkYbS{ zdLi{q2nCk!^-?oko*|ml_rb)NZ3#oqX%X4#LNM1ir}t<`58+Y`4YAmLzRV|io6iVd z&fRzIL$r#-6Nf#Rv7}los@jU|va-KhfcrRyKfPjLbY~!`Ye5y+fbv!`vcw63qP(fy zeILFKgP}4TZ#JNnbvmt=$FyZlj09qsLaqX{J_@`#N(Z>3GVfyF?o0qy;207;j56F4 z&m_L@1U%@YterLff%Q%s2Ayw4;cx*P~v6lk_?_E0|k zDEYOm#y2%Ag}7!PjEAAEE`gEAH|WO z=e#9g=+y7iYb3AO%VU&OE?lCn9UviCz#i+gfP^Kl8$U$jfX{SgCyV)fFb;q8X$R`# zWo_QokssDHvVHy~LRt1z)^rzQktQ?{|M8M_{jL3!dQ$9Sjd|KuT-~_i@Cl0ytTK^} z%3027wO#^kH{!)+M9bMFK3oE8E#!dL9;|(;CU5(VKH>%57J94*S8)pWz$AsNhqA;F zbBHL?pxa%C>bMHjAe9Ifw*;Sg_hlle?v_@>jl$F>2Wo3BfZl0S$0Nr(vJyA%6ECt@TUf&K0%4gFH_@nD{UDelG*m=7BN>~xME_{$ zS&8J2MHAW^R&KoM@1n^kEMqRLq(a)8xr4ELv8#je_cbN=A$Zyw7XeYRcj~$x^L+}? z_L-+OPB|0Y*$~{N4azey%~mEzzG($PcZ+L~XH?$SQ!5kcd zfhi={P&XJelN1^X9>PD2DOUaYT(tK~?-|RfRHNo6GjBVbO?UqY2gSrBHYJ$g zjR3YNTTEJjB_JL?GAXni+KZou*4)Tp=nUqS12l@XUio;UzsS>R9Z9_p<&zV*eaw`R zb|pB8GbOdoPjl@CYan1{S{i3F$HbuDv!G41uMp|DT}Je%Rq~Ev#oC}_WCkANjVk1x zoXY28AkXVplL9jY;-L=lbr{%+Q`?BbO$a-IInek0fI6AOIOti+BmJz}wuXjQ@?1`E zTU`>MjFrn}!-AZPwMQkU!8&;F{9rQbsf@c8&>6~R)9bjhQktBz<@0BRsiwCF!&-yO zTI?C#`Q4@ypJ16POc0wV?jV>ODS!v!w7V|yff-Y!M2w%@;0@N3f?yrj>lLz>)Fnp! zpk*x&6aDR=6Tk<_qzP~?caE|U7FBT8iG|36^Of)vwO+Eto>!0$Z!4vrhhT*R*v)eH0OvA|LJ}T%pA#c?R83_k@FoK=a5f z`Fq@E)vew#>a9FYdeO1btJX@2QiaU?Y4SQg^X~-fHR`X!)F)AT-Esoke9KFm=Qlxn z%Pc2bKXKPwN9U~@>NEhFYDd#_vc;4Mhmwx0mqv#+Ma#FO77shv)Xu&(oGBvr#Osa3 z2T|2GPbY;kKMGEzAMulHd%i(r6g?9silml5SvzS@KqHEVgg0B3yLHT%4si& z{Ynpg4tjt3>Ffl0OIOj#7WguMoGwuYJL2i!Tg(nB5}G?5PqAhNVgT`(e3hEQA?6kF zQGm-deB~$J_5M2UpHRFnHP0UQw?yHulwU_uUuAttMXpaV8}rr2dby5tNo3eA4lMJQ z$PvTMrPpG4YkzcQ77hKTFkTb5ZX=(46wX`@oiBTik!B?OOC@5FGeIFOoW$V zmnm&7rhP~B!N>OXRDao7@cLP=>qHoQanIGeSM?s!dbGp0)I<H5R%7< z=nd(a#MbcQGa7}N!_7EiB6KfNh1gRm(-tHz?3W=87A$Sc!97Z`uLmvy(Bf=9-(gm% z@yvi|ma-CtZWm|4R5#xpgSdR#ZHpf0lZc$ZFM1TTwGmsvETj^%uvUUgXcU3t@cFnD zCbEUKI{*D^eC72_c#8&SDg|bgljtO24l}(ui8Z~RtkXzhMGJ0~(Myr{YAK6QVJ!GM zoc2MKxo-*d4p<)H@h99U!g9G#^DsE5p2}rPTJRK(BxBt{T5!`hr08z|UF|4g8h52l zvy4=d7oBbr*sCjO1QRQR3K#G21gPFVrJR+lZmQyr;?5!1$cu4b3e!kl@D$T3MprJ? z37JR9!Ze%6gjgcIorvu@GkTv$U`(;(%3>WN3z!MlT1hnTdt{rOJlovfV>r$hAKL;w z`V6B(k-#lKNAYoTrwIH81HsQ`6Rp@^Hj}JM)wnmenZiMa?3$cslqO0Jg@Dqe3qr>~ zMS_>jWQ#Iao$L$By+l=}r-Hpl{Q8-Hy{ptDlW^OJL_{bS|5?|Rxx}T;R7Dj<$ zgX~2R5asa|L?37P2`I`6Um=5Xqs1LvQ{D0jbKwuysX(3Qb;pW%u)^da zfqp(O^4KCphRd7ggd6R~gpD4%2=;(UFOD<`GR8eti4#34h#nI#fBJvLG6{&K-I|u- zrZtG0>sR#>({XSgUc34j%PZB}V9Lor*JCrl`M1orPex0vpoX@6uFKqeGXpAlk$eIn zf#zRZiXz+nzT(N}Ao7QPqS~w8s(b-oI7wvyUXuhVl$hu$q|j}nC3x5XQ@(C^NJ2<> zU6kVksWndy%NHy7)jnvXq~k<8FZj4{H)daTKTwt0ZzX)8)X&}uuOih#D^w$(*V-#3 zM&)?>l!nXRi1o4Mz)CvYBnHZYAeQ>=WQ&)Kb4u``qS8J$y-aBbDMeyDG_+Sr1#uHD zD2G-U_vEfl(iqz%V=YuO8HQgAe*LOhK@lvxHq|GW8$3m3Y+@(%REx=_c#H~Hy)Q16 zsCmb!yl^6^y0U+DP2q1@rIQqdr<)WiE36tl^~o;0POW^0rne-@b>NE(;)q|CB$|2Y z!it!fZt*~N?TMS~MnbcYak-#%1FrM=fJnTT+Zk`?z^c3VkVt$z1}?s-%eD@j?w~bP zV+#pmp6F+Oa_fpgLTy1NS`MZ~4fo!A4mU}<2{2W?FSOvvx$T~ra4#|JqrWk@or9Rl zm^mj{v!g)xZGtjr(5S8AdH^@iS~pjMjDr23q2S3=LSC54mvJ@By{ZhA4AyR-9PE=y zCet$Qb>7K^S*>%0lU<9MuvBt*kdv(2toDFp(sQ)sjNuO2!`>|c@kxOi-jc>9 zy;`&eDHxoC+)9K6enb!A4T>BD9_n1a6u316l2KkwiM^A*j7V6R{t_JVfyi_)S>Ps2 zfT&1Vpw?#y*E}o8YtpmO{GIPYbv_j;!|i)yPm>4`X>kRyDiNcA=ULJGiTqN-(>UaL zB=YyOBKqGNme@O({U7I4&({5Q#0U3pY@44(zW;Gf`zt+Yf6`-SZei^568OIy;EmHh zjdFge&)CtC$;SDg#zn_Eb`GnJSdV(&;Uu`jKK3N9@X#!ZHB%>uL*Sd>Ek`1 z?A)&U=J%w+?qRwer6p31EWE6@A)b7kd|k4DL#~sA2RGSFJyN!&Z)iwIob|pEdyiEM z`^k5~V?rjMpx0kp2x~TT{7e8(ivp!cE_u5-cha0?fO!sI8dW}8Yk*^hV?s?`~`?6 z&Y^9x_5p=e?f57eZxcN&hB?;&NM_L;8l|taNJ}S215whnD!r) zL$|d&0!WFh23|91#lY8YB)LbjFlsi3S>h6vqp0XaRpw;?EGZ8vBB9C-F`Npd-~zvWlG!UD*t>0XfogeWe@b>SGlY#^p$sB$ZKGZ!wrV(K4yPVdq^kll)W+ zb?3X_Gkw6mVe>A#dEF`ri`XVG+<4&^rgDo_+j^%b(*)g=BiX>JGo40$ylbvlh|(F@gOH?xt*n>e`X!UbpSLmW0&w$6 z!NeKy=C0W3X}UCz08Rq4O5W9It)0XaFO!A>#-$|s@zzml#S-7guTza{G*bJP;&;)b zgEh6;bE~hM#G>iEv*Vw?k*_?rQ?HCVBOJdxzo;yy1X`_)03xSp&ZvmB+PT404Rt}k zVBR!&8D+R#&UFZw1>o2u8L=$|n2!ssDdA6+*{$w??s*CqA53EjagUymm$h_;$m!q6 zq_t<7Q>2M-Fc#0gINHmt+HW|kVE>M)BQ>nAT+!r1$#F86xJPA2wL)i-fmR3S0YGUL z@@VgNaACXej&N)J0G9+u%ADYciH>J*J}st)v+v+u;Qw?%`EHP+9B~aZtA_`?2 zdicYhOZ|pKC%O|= z?=;9g7~o5jx8c|!=iO*mm$gX2-(`-+8x}a@s~o6&avt24fmKtT+yDTK9rP`+?2fQr zLRHbSdl9d}u3y9Dd2-fd^;ob}qz8GT94_6TaWUweY`LNAdLDE)zSe%J*Cz#(B|oN_`Gi& zkL_XAXEnRBLPpPWVu^j>&YL%vZtTewOR+t6h65`}jbsPGF_{2f;x{2S;d2Izd<)oU zrrLZZco1MiV&a!%?k6#_w#N66Q5^Ci;hHRYpF!ufE5-fns1%guEP~Sy06z z#pz5k%Van>rNETMx!oVzpYcBXUBSoeR`24B z?1+&GSoPg_vv!xCNVn&;B0F{BO~1)0!<%uQGHa#oVsx31ipb6>Ydb4_0g#{bAIEzuu`|d7T#JlN?;i*K{Tv);&KgYHSg?RY;QmJ`f$7x)(+SrVINC!6_@Nrbnq)iUuVTWAogwk^hK;LxH?Ij{UCGh%+BmQYqdw z2@ta+bN40KsXE*%3y`9BqjgSp6Ad6g!uU!zmCXvVLML?)_vtg&c>%kmx3^NFs6bTe z+KadZze>e@d^QuKjY$4jv;I=+Ku1OOLmx0IVmzFQtU=Bi`k7 z{c-cFe+q-@3n&Q4a{&F;O}w8%%bJzP{(qScvpnV7q`ypu|4?df YlodPJ|5MPG zYtS*#j*iPRYt*TfXpBltjEq3nB?@#S5Eh-^=VxNX3G<{X>%#xBR`wtsTbd`}XYgNd zBewr+mZue?sKWojtZdFo_f}waLX3)sud)K1)b2=(^;GdS&HMt`9|j(_XD2_K@cj9; zf%i{;A^xS`?2PTLEzF&Pzh$0!Ob=XuFiMCaWk^hNH6Lw!T4Sx);{7XqdabAJ0p{Wavr`(Xxwb<9A_Wm2D_Kv*|t-lpW*G?hjRnv zbxqvzuyS;zTR8AIMK~eE&oU{Q(;T(?`0bbvh}^|M{kl1Bbd$s95AVEkE^4lQTK}^T z{ytQHU1T{LTblo0NUsa0w|H+*2LU4Wec z=@2%%j9U1?8bBV;vSL`%ECqWr%?JlpPw@spQuDQ`oMZe>1^N=MqS578CW(A38Noz2 zyJxg>q7sv1dctkNUijqu<8KudHs_-wr{W3dW=T#opXoV>@UsR(JO#M;x?=xTBxdl2 zS1GYIe4`?mv$cAlNW124Aksd;X7bAQNkCWLtv9yd?4jny9fK5dF0SO}9D~JzFcuq` zu~{7AkkBSo0uxeWq1b~mnaW}WaIsIim5@4B(`F;Y6B5ip&5)*VC%*ZnYdV0^uE}0F zpEOhG#!W%jO{F{_87Z5?fafl5Y}1IK+`AN-C;fciLJ& zTo=d=!k5OPry@~{+AgXf8E1`(lxj8zje}eyu00Bo!<;vL$GhiX6wE7h8Yd{Zv^)wS z0vm-n{cbQn7}9rcFl^q^E5r8TjmX+!#P{@fQM)D$v|q4Lbr_^#sA+M_o{B_-$~;>K zTdJjWY(%vk)-60W2;p_)%y!63Dgu)v)Ub`I@`0eDgM)j5E4Z?v!56?+CKBE~f{_Aw z@0i`Mp?j>^;*|7v>Om4cSIRb+98b`u%cl={D~iCmmh6Lh>$Ke?s>5DULvw^{Tf69J zVL)W%?u#-?olrKfX>J2rqA8Cr41}*Kzaj(`(T>)$!Yb4DpS{D)IoE(<4jnebl<&$! zha2w>aEEkuJ-k1nw|YV9>@Ba9u9u{HLKsi6CZ!^x&PO$2Rk!3W(R8tZs2e^1pg-aB zaejQYu+EJ6#m`0Jx5|gU>U^_Mh?Zg%?XuL=S^xLN;^_;R_WDjfqo34{<7LgKd-?SW z^B1$Z!0A$4p!bbV8F{793>x!U-~$8eF&u++v}>_d;7B5_hx@^s#o29i#Ygg^J! z?p=OzmJ?fgl1|6!HSpE;g3yzXr0D%|c>RczKZl~T8^O1da^03)P;3lMN((p8XEbtNE{wwTNdA4P03a0s z2G|l^qUdme;KlUsB?})#pGXAYhDEVwa6^FCUywj8H;_9Yu};?2l0-5D>tDLd@{(Zk ztc1m$@1H^%BW?xwD``i(QvwbOi`v{micQaf1&e+m@8%)8mS;9fBh>Cdt#HPgSO(cnobQn3I#u zpkkg%P{LV4&ahDT*L%Hn^W*ob=wM(Yr8_L>f+_ant$n&ac{Inn>88C(WLP0sbu1Ma zh<&m|AsX{6KpmG*x-6)nMHi#gu6iigMRZZ zwN^C(7`*gJV%W6uGRvhnX`|^bB}>bGQ};mKq_N*q^az++sFp*0Jr-Drl5!(IZa9Q6I9BfBE(fsO{ znkV4l5}nk;%X5a(jKMO7*Xv~1Y)H;yOU%D*<@>~2aI{S%F`8lF@$O|6*_}zY<9Dsg z2{)*G>x^HX6uXqFUcTPUk;vy0?r`}!tmrP3-S;B2)U@gK7mY6V z_G7F}673=Je6NMWwf7wJl}s3I;OZWHcB+KSP9{>4`tQ

    )u?ZQ?h!xzU`#P%>Y$> zIizKz+gGN7eAHWKVR89FK1enA2)hnz9(|Nf)z#2mqbLq?rWu;A6#WiszJgDOH+rGC z=<`F(O`^t!YD0X)v{!I3WWBs<%^GC)fvwN{X)JAc+(U#0j=MNY_l0bChfI)(eIB|o^9Pe=lyYV zW+{~kZ8Xh(!{{_7yHIcr>$C;(O3`R5exP7ngJ8rD>1gBT$T$R!PUcv+6NW89O z^zvza1ya3ihWe@^fSk$_rC&C4Rv(ot)~Q>T@DP}yh0BCKe_^F{cQ8RPn`Zwo9~3|; zhp5>XL`u;j3DP5<|+ z)lla)z#V+%1M+jRy@N>`2!I6vc}~rKorGgPu`_-mgZxwx{hSc~NZNj<^zKkwwO?gH zc)&Jwpe$p+Z{+g9p`pcQwr&Fw>KH8rZkL1~*)kSsvwZ#_xjeGn2v|ToxECgR6Us-C zbs*_jEo*zuaM14Gy%)(g!*$?|nCz)iLUY10xDY3QzNW2NM&@VXxnexl9+ft`pzonn zk~SDF9i@A9&Ng15D%}g*8^wHQ-mhZL=4!jF_Mt?4o37KGD&y$1;YDWgNTjXU!ecD2 zAc5rRMpyH6C1NKauC)HqUG*b|HQx@Jyx>&tI1gBLW^qv&jT{%bg(I7U7#o=4uxn25 ze){@+Eb_Vkme#t^KfT&!Y}%AJM662k&n1d zTF>k9@@;7#qAuoLW>BN|^lqk5>7!k4?9z?Z84oE@rqfrq`8&j0*jV=lP^5j1me8C> zrMZ_SzV(iJce|Xuv?f}wojp%sa|w~TPhW{ekCNt{>2%`=82~0(KYJXNn8@Ied1BGU zhUgpeozoNEc)rX}LV|&S zJcrn?gD>idrv?91F+9#^1@;5DZ1z(-@kWs2H;~iQ6hqwNfqbg z28fdA3S>kxz$RqQ@!WQ$d~@8vhXdA%pT~Pse1HvVsQK==E%YF^KXPE^YEe(7R30}m zg~_8vBk-7N2kb_Ksttq-aC`xE?X6AcF3uPoY0Qo@_1<+xWy_8AEdi7EkT7ACa%W@y z(5GaK;IC9$CsA#Sf-prS3oEbUYrCt!^kt5Z;I*0y`ZbTvGTuubp{s2x%h4se@rye+ zqD!1v?IsRx8LJwKOfAg9mau;_7{t<)pVd3*)YvqXDn*kZd<=NUy6AfiI^@YBccA2d z0QPPo>|RikAyjI?E#@VHeFi5c&HMb7Z&hXev@zeD#H3Af#&00+y;4qfD~KTuw}anZ zmsTOi0K15B6Bk*997u!bu|`!q6d-O-#Gz}Q0u);DHJlvX7=z!$6~|E1s)f81YH{}1`F|H(7Y9MT_h3}^=ZZ_oT|5&w<-{{sYqQGEV>epnfKUK66fgNTL7GZ{hvV7^puU-j6W( z8U2}X`a=r+rJgpyfAZ_UR{KAqpZ+KCXSV4NDfA!yUGU%Lp8gg4=X({;*~Jej^p||< z&HnSkf0uarSKOZ+{(NiWhZOn)34aIox9@QL0DcDe)s>AOz{h~Ie*-@ySAVpCpK0)a zdx7Kc_sjDYjvsOi;34|&1^tw?{jUBW5&H8q=DFMWLkj)FeyRWWE_nR#&JUEI8}mP( zFNOa5RKHrq@6UODAU)gt*XQu(<5J{l-t=FA_mjVVv+e)qL*?h*`*Y*}hZOp!{5{C; zj{$zH>4*1z?xg=2j*0GX*Yx}C{lCKf+?sxF&;O7@|EXWX{g0aUKfs=q{`GnN9Dm1v zWBOmM?RR_Mf4_^KyWcVE#^N_gCDXQ@ZCo{)ZI$zvp>+A;#}#^-8jk&ube) Pg7WkRfz3bOG4lTa1WCqz literal 0 HcmV?d00001 diff --git a/test/systemtest/common/ams/BUILD.gn b/test/systemtest/common/ams/BUILD.gn index b8671e39ca..af5964d107 100755 --- a/test/systemtest/common/ams/BUILD.gn +++ b/test/systemtest/common/ams/BUILD.gn @@ -32,10 +32,14 @@ group("systemtest") { deps = [ "ams_aa_command_test:systemtest", "ams_ability_append_test:systemtest", + "ams_ability_visible_test:systemtest", "ams_app_process_manage_test:systemtest", + + #"ams_configuration_updated_test:ams_configuration_updated_test", "ams_data_ability_test:systemtest", "ams_dfx_test:systemtest", "ams_kit_test:systemtest", + "ams_missionstack_test:ams_missionstack_test", "ams_page_ability_test:systemtest", "ams_power_test:systemtest", "ams_service_ability_test:systemtest", diff --git a/test/systemtest/common/ams/ams_aa_command_test/BUILD.gn b/test/systemtest/common/ams/ams_aa_command_test/BUILD.gn old mode 100644 new mode 100755 index 684690e173..8a75f96226 --- a/test/systemtest/common/ams/ams_aa_command_test/BUILD.gn +++ b/test/systemtest/common/ams/ams_aa_command_test/BUILD.gn @@ -23,6 +23,7 @@ ohos_systemtest("ams_aa_command_test") { "//foundation/aafwk/standard/tools/aa/include", "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/include", "//foundation/distributedschedule/safwk/services/safwk/include", + "//third_party/jsoncpp/include", ] sources = [ @@ -49,6 +50,7 @@ ohos_systemtest("ams_aa_command_test") { "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler:libeventhandler", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", "//utils/native/base:utils", ] diff --git a/test/systemtest/common/ams/ams_ability_append_test/BUILD.gn b/test/systemtest/common/ams/ams_ability_append_test/BUILD.gn old mode 100644 new mode 100755 index 24e24e6068..1f6c172363 --- a/test/systemtest/common/ams/ams_ability_append_test/BUILD.gn +++ b/test/systemtest/common/ams/ams_ability_append_test/BUILD.gn @@ -21,6 +21,7 @@ ohos_systemtest("ams_ability_append_test") { "${appexecfwk_path}/test/resource/amssystemtestability/abilitySrc/common/", "//foundation/distributedschedule/safwk/services/safwk/include", "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/include", + "//third_party/jsoncpp/include", ] sources = [ @@ -47,6 +48,7 @@ ohos_systemtest("ams_ability_append_test") { "${appexecfwk_path}/interfaces/innerkits/libeventhandler:libeventhandler", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", "//utils/native/base:utils", ] diff --git a/test/systemtest/common/ams/ams_ability_visible_test/BUILD.gn b/test/systemtest/common/ams/ams_ability_visible_test/BUILD.gn new file mode 100755 index 0000000000..3b4a98c804 --- /dev/null +++ b/test/systemtest/common/ams/ams_ability_visible_test/BUILD.gn @@ -0,0 +1,67 @@ +# Copyright (c) 2021 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/appexecfwk/standard/appexecfwk.gni") +module_output_path = "appexecfwk_standard/ams" + +ohos_systemtest("ams_ability_visible_test") { + module_out_path = module_output_path + + include_dirs = [ + "//foundation/distributedschedule/safwk/services/safwk/include", + "${appexecfwk_path}/test/resource/amssystemtestability/abilitySrc/common", + "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/include", + "//third_party/jsoncpp/include", + ] + + sources = [ + "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/src/event.cpp", + "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/src/module_test_dump_util.cpp", + "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/src/stoperator.cpp", + "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/src/system_test_ability_util.cpp", + "ams_ability_visible_test.cpp", + ] + + configs = [ + "${aafwk_path}/services/abilitymgr:abilityms_config", + "${appexecfwk_path}/services/appmgr:appmgr_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${aafwk_path}/interfaces/innerkits/want:want", + "${aafwk_path}/services/abilitymgr:abilityms", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${appexecfwk_path}/interfaces/innerkits/libeventhandler:libeventhandler", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", + "//utils/native/base:utils", + ] + + external_deps = [ + "ces_standard:cesfwk_core", + "ces_standard:cesfwk_innerkits", + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("systemtest") { + testonly = true + + deps = [ ":ams_ability_visible_test" ] +} diff --git a/test/systemtest/common/ams/ams_ability_visible_test/ams_ability_visible_test.cpp b/test/systemtest/common/ams/ams_ability_visible_test/ams_ability_visible_test.cpp new file mode 100644 index 0000000000..0932a783d2 --- /dev/null +++ b/test/systemtest/common/ams/ams_ability_visible_test/ams_ability_visible_test.cpp @@ -0,0 +1,1266 @@ +/* + * Copyright (c) 2021 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 +#include +#include +#include "hilog_wrapper.h" +#include "ability_connect_callback_proxy.h" +#include "ability_connect_callback_stub.h" +#include "ability_manager_service.h" +#include "ability_manager_errors.h" +#include "app_mgr_service.h" +#include "module_test_dump_util.h" +#include "system_test_ability_util.h" +#include "module_test_dump_util.h" +#include "sa_mgr_client.h" +#include "system_ability_definition.h" +#include "common_event.h" +#include "common_event_manager.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AAFwk; +using namespace OHOS::AppExecFwk; +using namespace OHOS::MTUtil; +using namespace OHOS::STABUtil; +using namespace OHOS::EventFwk; + +namespace { +using MAP_STR_STR = std::map; +std::vector bundleNameSuffix = {"PageA", "ServiceB"}; +static const std::string bundleNameBase = "com.ohos.amsst.appAbilityVisible"; +static const std::string hapNameBase = "amsAbilityVisibleTest"; +static const std::string abilityNameBase = "AmsAbilityVisibleTest"; +static const std::string launcherBundle = "com.ix.launcher"; +static const std::string launcherAbility = "LauncherAbility"; +static const std::string systemUiBundle = "com.ohos.systemui"; +static const std::string terminateAbility = "requ_page_ability_terminate"; +static const std::string terminateAbilityCaller = "requ_page_ability_terminate_caller"; +static const std::string disconnectService = "requ_disconnect_service"; +static const std::string terminateAbilityResult = "requ_page_ability_terminate_result"; + +static const std::string DUMP_STACK_LIST = "--stack-list"; +static const std::string DUMP_SERVICE = "--serv"; +static const std::string DUMP_DATA = "--data"; +static const std::string DUMP_STACK = "--stack"; +static const std::string DUMP_MISSION = "--mission"; +static const std::string DUMP_TOP = "--top"; +static const std::string DUMP_ALL = "-a"; +static const std::string abilityStateInit = ":Init"; +static const std::string abilityStateOnStart = ":OnStart"; +static const std::string abilityStateOnStop = ":OnStop"; +static const std::string abilityStateOnActive = ":OnActive"; +static const std::string abilityStateOnInactive = ":OnInactive"; +static const std::string abilityStateOnBackground = ":OnBackground"; +static const std::string abilityStateOnForeground = ":OnForeground"; +static const std::string abilityStateOnNewWant = ":OnNewWant"; +static const std::string abilityStateOnCommand = ":OnCommand"; +static const std::string abilityStateOnConnect = ":OnConnect"; +static const std::string abilityStateOnDisconnect = ":OnDisconnect"; +static const std::string abilityStateInsert = ":Insert"; +static const std::string abilityStateDelete = ":Delete"; +static const std::string abilityStateUpdate = ":Update"; +static const std::string abilityStateQuery = ":Query"; +static const std::string abilityStateGetFileTypes = ":GetFileTypes"; +static const std::string abilityStateOpenFile = ":OpenFile"; +static const std::string getWantAgentState = ":GetWantAgentFail"; +static const std::string triggerWantAgentState = ":TriggerWantAgentSuccess"; +static const int abilityStateCountOne = 1; +static const int abilityStateCountTwo = 2; +enum AbilityState_Test { + INITIAL = 0, + INACTIVE, + ACTIVE, + BACKGROUND, + SUSPENDED, + INACTIVATING, + ACTIVATING, + MOVING_BACKGROUND, + TERMINATING, + ALLSUM, +}; +static const std::vector abilityStateVec = { + "INITIAL", + "INACTIVE", + "ACTIVE", + "BACKGROUND", + "SUSPENDED", + "INACTIVATING", + "ACTIVATING", + "MOVING_BACKGROUND", + "TERMINATING", +}; +} // namespace +class AppEventSubscriber; + +class AmsAbilityVisibleTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + + static std::vector GetBundleNames( + const std::string &strBase, const std::vector &strSuffixs); + static bool SubscribeEvent(); + void ShowDump(); + static void CheckAbilityStateByName(const std::string &abilityName, const std::vector &info, + const std::string &state, const std::string &midState); + void ExpectAbilityCurrentState(const std::string &abilityName, const AbilityState_Test ¤tState, + const AbilityState_Test &midState = AbilityState_Test::ALLSUM, const std::string &args = (DUMP_STACK + " 1")); + void ExpectAbilityNumInStack(const std::string &abilityName, int abilityNum, const std::string &type = "-a"); + void ExpectServiceAbilityNumInStack(const std::string &abilityName, int abilityNum); + class AppEventSubscriber : public CommonEventSubscriber { + public: + explicit AppEventSubscriber(const CommonEventSubscribeInfo &sp) : CommonEventSubscriber(sp) + {} + virtual ~AppEventSubscriber() + {} + virtual void OnReceiveEvent(const CommonEventData &data) override; + }; + + class AbilityConnectCallback : public AbilityConnectionStub { + public: + /** + * OnAbilityConnectDone, AbilityMs notify caller ability the result of connect. + * + * @param element,.service ability's ElementName. + * @param remoteObject,.the session proxy of service ability. + * @param resultCode, ERR_OK on success, others on failure. + */ + void OnAbilityConnectDone( + const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) override + { + GTEST_LOG_(INFO) << "AbilityConnectCallback::OnAbilityConnectDone:resultCode = " << resultCode; + if (resultCode == 0) { + onAbilityConnectDoneCount++; + } + resultConnectCode = resultCode; + } + + /** + * OnAbilityDisconnectDone, AbilityMs notify caller ability the result of disconnect. + * + * @param element,.service ability's ElementName. + * @param resultCode, ERR_OK on success, others on failure. + */ + void OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode) override + { + GTEST_LOG_(INFO) << "AbilityConnectCallback::OnAbilityDisconnectDone:resultCode = " << resultCode; + if (resultCode == 0) { + onAbilityConnectDoneCount--; + } + resultConnectCode = resultCode; + } + + static size_t onAbilityConnectDoneCount; + static int resultConnectCode; + }; + static sptr appMs_; + static sptr abilityMs_; + static STtools::Event event_; + static std::shared_ptr subscriber_; + static int *memTestValue_; +}; + +sptr AmsAbilityVisibleTest::appMs_ = nullptr; +sptr AmsAbilityVisibleTest::abilityMs_ = nullptr; +STtools::Event AmsAbilityVisibleTest::event_ = STtools::Event(); +int *AmsAbilityVisibleTest::memTestValue_ = nullptr; +std::shared_ptr AmsAbilityVisibleTest::subscriber_ = nullptr; +size_t AmsAbilityVisibleTest::AbilityConnectCallback::onAbilityConnectDoneCount = 0; +int AmsAbilityVisibleTest::AbilityConnectCallback::resultConnectCode = 0; + +void AmsAbilityVisibleTest::SetUpTestCase(void) +{ + GTEST_LOG_(INFO) << "void AmsAbilityVisibleTest::SetUpTestCase(void)"; + + SubscribeEvent(); + appMs_ = STAbilityUtil::GetAppMgrService(); + abilityMs_ = STAbilityUtil::GetAbilityManagerService(); + if (appMs_) { + appMs_->SetAppFreezingTime(60); + int time = 0; + appMs_->GetAppFreezingTime(time); + std::cout << "appMs_->GetAppFreezingTime();" << time << std::endl; + } +} + +void AmsAbilityVisibleTest::TearDownTestCase(void) +{ + GTEST_LOG_(INFO) << "void AmsAbilityVisibleTest::TearDownTestCase(void)"; + CommonEventManager::UnSubscribeCommonEvent(subscriber_); +} + +void AmsAbilityVisibleTest::SetUp(void) +{ + GTEST_LOG_(INFO) << "void AmsAbilityVisibleTest::SetUp(void)"; + std::vector hapNames = GetBundleNames(hapNameBase, bundleNameSuffix); + STAbilityUtil::InstallHaps(hapNames); +} + +void AmsAbilityVisibleTest::TearDown(void) +{ + GTEST_LOG_(INFO) << "void AmsAbilityVisibleTest::TearDown(void)"; + if (memTestValue_) { + delete[] memTestValue_; + } + + std::vector bundleNames = GetBundleNames(bundleNameBase, bundleNameSuffix); + STAbilityUtil::UninstallBundle(bundleNames); + + STAbilityUtil::CleanMsg(event_); +} + +std::vector AmsAbilityVisibleTest::GetBundleNames( + const std::string &strBase, const std::vector &strSuffixs) +{ + std::vector bundleNames; + for (auto strSuffix : strSuffixs) { + bundleNames.push_back(strBase + strSuffix); + } + return bundleNames; +} + +bool AmsAbilityVisibleTest::SubscribeEvent() +{ + std::vector eventList = {"resp_st_page_ability_callback"}; + MatchingSkills matchingSkills; + for (const auto &e : eventList) { + matchingSkills.AddEvent(e); + } + CommonEventSubscribeInfo subscribeInfo(matchingSkills); + subscribeInfo.SetPriority(1); + subscriber_ = std::make_shared(subscribeInfo); + return CommonEventManager::SubscribeCommonEvent(subscriber_); +} + +void AmsAbilityVisibleTest::ShowDump() +{ + if (abilityMs_) { + std::vector dumpInfo; + abilityMs_->DumpState("-a", dumpInfo); + for (const auto &info : dumpInfo) { + std::cout << info << std::endl; + } + dumpInfo.clear(); + abilityMs_->DumpState(DUMP_SERVICE, dumpInfo); + for (const auto &info : dumpInfo) { + std::cout << info << std::endl; + } + dumpInfo.clear(); + abilityMs_->DumpState(DUMP_DATA, dumpInfo); + for (const auto &info : dumpInfo) { + std::cout << info << std::endl; + } + } +} + +void AmsAbilityVisibleTest::CheckAbilityStateByName(const std::string &abilityName, + const std::vector &info, const std::string &state, const std::string &midState) +{ + std::vector result; + MTDumpUtil::GetInstance()->GetAll("AbilityName", info, result); + auto pos = MTDumpUtil::GetInstance()->GetSpecific(abilityName, result, result.begin()); + // ability exist + EXPECT_NE(pos, result.end()); + MTDumpUtil::GetInstance()->GetAll("State", info, result); + EXPECT_TRUE(pos < result.end()); + if (pos == result.end()) { + HILOG_ERROR("pos == result.end()"); + return; + } + // ability state + if (midState != "") { + bool compareResult = ((*pos == state) || (*pos == midState)); + EXPECT_EQ(1, compareResult); + } else { + EXPECT_EQ(*pos, state); + } +} + +void AmsAbilityVisibleTest::ExpectAbilityCurrentState(const std::string &abilityName, + const AbilityState_Test ¤tState, const AbilityState_Test &midState, const std::string &args) +{ + std::string strCurrentState = abilityStateVec.at(currentState); + std::string strMidState = ""; + if (midState != AbilityState_Test::ALLSUM) { + strMidState = abilityStateVec.at(midState); + } + std::vector dumpInfo; + if (abilityMs_ != nullptr) { + abilityMs_->DumpState(args, dumpInfo); + CheckAbilityStateByName(abilityName, dumpInfo, strCurrentState, strMidState); + } else { + HILOG_ERROR("ability manager service(abilityMs_) is nullptr"); + } +} + +void AmsAbilityVisibleTest::ExpectAbilityNumInStack( + const std::string &abilityName, int abilityNum, const std::string &type) +{ + std::vector dumpInfo; + if (abilityMs_ != nullptr) { + abilityMs_->DumpState(type, dumpInfo); + std::vector result; + MTDumpUtil::GetInstance()->GetAll("AbilityName", dumpInfo, result); + // only one record in stack + EXPECT_EQ(abilityNum, std::count(result.begin(), result.end(), abilityName)); + } else { + HILOG_ERROR("ability manager service(abilityMs_) is nullptr"); + } +} + +void AmsAbilityVisibleTest::ExpectServiceAbilityNumInStack(const std::string &abilityName, int abilityNum) +{ + std::vector dumpInfo; + if (abilityMs_ != nullptr) { + abilityMs_->DumpState(DUMP_SERVICE, dumpInfo); + std::vector result; + MTDumpUtil::GetInstance()->GetAll("AbilityName", dumpInfo, result); + // only one record in stack + EXPECT_EQ(abilityNum, std::count(result.begin(), result.end(), abilityName)); + } else { + HILOG_ERROR("ability manager service(abilityMs_) is nullptr"); + } +} + +void AmsAbilityVisibleTest::AppEventSubscriber::OnReceiveEvent(const CommonEventData &data) +{ + GTEST_LOG_(INFO) << "OnReceiveEvent: event=" << data.GetWant().GetAction(); + GTEST_LOG_(INFO) << "OnReceiveEvent: data=" << data.GetData(); + GTEST_LOG_(INFO) << "OnReceiveEvent: code=" << data.GetCode(); + + std::string eventName = data.GetWant().GetAction(); + if (eventName == "resp_st_page_ability_callback") { + std::string target = data.GetData(); + STAbilityUtil::Completed(event_, target, data.GetCode()); + } +} + +/* + * @tc.number : AMS_ABILITY_VISIBLE_0100 + * @tc.name : Visible attribute impact on startAbility + * @tc.desc : The test process starts an ability whose visible attribute is false + */ +HWTEST_F(AmsAbilityVisibleTest, AMS_ABILITY_VISIBLE_0100, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_0100 start"; + std::string bundleName = bundleNameBase + "PageA"; + std::string abilityName = abilityNameBase + "PageA1"; + + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); + ErrCode result = STAbilityUtil::StartAbility(want, abilityMs_); + EXPECT_EQ(result, ABILITY_VISIBLE_FALSE_DENY_REQUEST); + + ExpectAbilityNumInStack(abilityName, 0); + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_0100 end"; +} + +/* + * @tc.number : AMS_ABILITY_VISIBLE_0200 + * @tc.name : Visible attribute impact on startAbility + * @tc.desc : The test process starts an ability, + * and the visible attribute of the ability is the default value. + */ +HWTEST_F(AmsAbilityVisibleTest, AMS_ABILITY_VISIBLE_0200, TestSize.Level2) +{ + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_0200 start"; + std::string bundleName = bundleNameBase + "PageA"; + std::string abilityName = abilityNameBase + "PageA4"; + + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); + ErrCode result = STAbilityUtil::StartAbility(want, abilityMs_); + EXPECT_EQ(result, ABILITY_VISIBLE_FALSE_DENY_REQUEST); + + ExpectAbilityNumInStack(abilityName, 0); + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_0200 end"; +} + +/* + * @tc.number : AMS_ABILITY_VISIBLE_0300 + * @tc.name : Visible attribute impact on startAbility + * @tc.desc : The test process starts an ability whose visible attribute is true + */ +HWTEST_F(AmsAbilityVisibleTest, AMS_ABILITY_VISIBLE_0300, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_0300 start"; + std::string bundleName = bundleNameBase + "PageA"; + std::string abilityName = abilityNameBase + "PageA2"; + + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); + STAbilityUtil::StartAbility(want, abilityMs_); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountOne), 0); + + ExpectAbilityNumInStack(abilityName, 1); + ExpectAbilityCurrentState(abilityName, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_0300 end"; +} + +/* + * @tc.number : AMS_ABILITY_VISIBLE_0400 + * @tc.name : Visible attribute impact on startAbility + * @tc.desc : 1.The test process starts an ability(PageA2) whose visible attribute is true + * 2.The ability(PageA2) starts an ability(PageA1) whose visible attribute is false + * 3.PageA2 has the same bundleName as PageA1 + */ +HWTEST_F(AmsAbilityVisibleTest, AMS_ABILITY_VISIBLE_0400, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_0400 start"; + std::string bundleName = bundleNameBase + "PageA"; + std::string abilityName = abilityNameBase + "PageA2"; + std::string abilityName2 = abilityNameBase + "PageA1"; + + MAP_STR_STR params; + params["targetBundle"] = bundleName; + params["targetAbility"] = abilityName2; + params["type"] = "Page"; + + Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); + STAbilityUtil::StartAbility(want, abilityMs_); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnActive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnInactive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnBackground, abilityStateCountOne), 0); + + ExpectAbilityNumInStack(abilityName, 1); + ExpectAbilityCurrentState(abilityName, AbilityState_Test::BACKGROUND, AbilityState_Test::MOVING_BACKGROUND); + ExpectAbilityCurrentState(abilityName2, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_0400 end"; +} + +/* + * @tc.number : AMS_ABILITY_VISIBLE_0500 + * @tc.name : Visible attribute impact on startAbility + * @tc.desc : 1.The test process starts an ability(PageA2) whose visible attribute is true + * 2.The ability(PageA2) starts an ability(PageA3,type:singleton) whose visible attribute is false + * 3.PageA2 has the same bundleName as PageA3 + */ +HWTEST_F(AmsAbilityVisibleTest, AMS_ABILITY_VISIBLE_0500, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_0500 start"; + std::string bundleName = bundleNameBase + "PageA"; + std::string abilityName = abilityNameBase + "PageA2"; + std::string abilityName2 = abilityNameBase + "PageA3"; + + MAP_STR_STR params; + params["targetBundle"] = bundleName; + params["targetAbility"] = abilityName2; + params["type"] = "Page"; + + Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); + STAbilityUtil::StartAbility(want, abilityMs_); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnActive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnInactive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnBackground, abilityStateCountOne), 0); + + ExpectAbilityNumInStack(abilityName, 1); + ExpectAbilityNumInStack(abilityName2, 1); + ExpectAbilityCurrentState(abilityName, AbilityState_Test::BACKGROUND, AbilityState_Test::MOVING_BACKGROUND); + ExpectAbilityCurrentState(abilityName2, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_0500 end"; +} + +/* + * @tc.number : AMS_ABILITY_VISIBLE_0600 + * @tc.name : Visible attribute impact on startAbility + * @tc.desc : 1.The test process starts an ability(PageA2) whose visible attribute is true + * 2.The ability(PageA2) starts an ability(PageB1) whose visible attribute is false + * 3.PageA2 has the different bundleName as PageB1 + */ +HWTEST_F(AmsAbilityVisibleTest, AMS_ABILITY_VISIBLE_0600, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_0600 start"; + std::string bundleName = bundleNameBase + "PageA"; + std::string abilityName = abilityNameBase + "PageA2"; + std::string bundleName2 = bundleNameBase + "ServiceB"; + std::string abilityName2 = abilityNameBase + "PageB1"; + + MAP_STR_STR params; + params["targetBundle"] = bundleName2; + params["targetAbility"] = abilityName2; + params["type"] = "Page"; + + Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); + STAbilityUtil::StartAbility(want, abilityMs_); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountOne), 0); + + ExpectAbilityNumInStack(abilityName, 1); + ExpectAbilityNumInStack(abilityName2, 0); + ExpectAbilityCurrentState(abilityName, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_0600 end"; +} + +/* + * @tc.number : AMS_ABILITY_VISIBLE_0700 + * @tc.name : Visible attribute impact on startAbility + * @tc.desc : 1.The test process starts an ability(PageA2) whose visible attribute is true + * 2.The ability(PageA2) starts an ability(PageB2) whose visible attribute is true + * 3.PageA2 has the different bundleName as PageB2 + */ +HWTEST_F(AmsAbilityVisibleTest, AMS_ABILITY_VISIBLE_0700, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_0700 start"; + std::string bundleName = bundleNameBase + "PageA"; + std::string abilityName = abilityNameBase + "PageA2"; + std::string bundleName2 = bundleNameBase + "ServiceB"; + std::string abilityName2 = abilityNameBase + "PageB2"; + + MAP_STR_STR params; + params["targetBundle"] = bundleName2; + params["targetAbility"] = abilityName2; + params["type"] = "Page"; + + Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); + STAbilityUtil::StartAbility(want, abilityMs_); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnActive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnInactive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnBackground, abilityStateCountOne), 0); + + ExpectAbilityNumInStack(abilityName, 1); + ExpectAbilityNumInStack(abilityName2, 1); + ExpectAbilityCurrentState(abilityName, AbilityState_Test::BACKGROUND, AbilityState_Test::MOVING_BACKGROUND); + ExpectAbilityCurrentState(abilityName2, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_0700 end"; +} + +/* + * @tc.number : AMS_ABILITY_VISIBLE_0800 + * @tc.name : Visible attribute impact on startAbility + * @tc.desc : 1.The test process starts an ability(PageA2) whose visible attribute is true + * 2.The ability(PageA2) starts a Service ability(Service) whose visible attribute is false + * 3.PageA2 has the different bundleName as Service + */ +HWTEST_F(AmsAbilityVisibleTest, AMS_ABILITY_VISIBLE_0800, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_0800 start"; + std::string bundleName = bundleNameBase + "PageA"; + std::string abilityName = abilityNameBase + "PageA2"; + std::string bundleName2 = bundleNameBase + "ServiceB"; + std::string abilityName2 = abilityNameBase + "Service"; + + MAP_STR_STR params; + params["targetBundle"] = bundleName2; + params["targetAbility"] = abilityName2; + params["type"] = "Page"; + + Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); + STAbilityUtil::StartAbility(want, abilityMs_); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountOne), 0); + + ExpectAbilityNumInStack(abilityName, 1); + ExpectAbilityNumInStack(abilityName2, 0, DUMP_SERVICE); + ExpectAbilityCurrentState(abilityName, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_0800 end"; +} + +/* + * @tc.number : AMS_ABILITY_VISIBLE_0900 + * @tc.name : Visible attribute impact on startAbility + * @tc.desc : 1.The test process starts an ability(PageB2) whose visible attribute is true + * 2.The ability(PageB2) starts a Service ability(Service) whose visible attribute is false + * 3.PageB2 has the same bundleName as Service + */ +HWTEST_F(AmsAbilityVisibleTest, AMS_ABILITY_VISIBLE_0900, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_0900 start"; + std::string bundleName = bundleNameBase + "ServiceB"; + std::string abilityName = abilityNameBase + "PageB2"; + std::string bundleName2 = bundleNameBase + "ServiceB"; + std::string abilityName2 = abilityNameBase + "Service"; + + MAP_STR_STR params; + params["targetBundle"] = bundleName2; + params["targetAbility"] = abilityName2; + params["type"] = "Page"; + + Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); + STAbilityUtil::StartAbility(want, abilityMs_); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnCommand, abilityStateCountOne), 0); + + ExpectAbilityNumInStack(abilityName, 1); + ExpectAbilityNumInStack(abilityName2, 1, DUMP_SERVICE); + ExpectAbilityCurrentState(abilityName, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_0900 end"; +} + +/* + * @tc.number : AMS_ABILITY_VISIBLE_1000 + * @tc.name : Visible attribute impact on ConnectAbility + * @tc.desc : 1.The test process starts an ability(PageA2) whose visible attribute is true + * 2.The ability(PageA2) Connect a Service ability(Service) whose visible attribute is false + * 3.PageA2 has the different bundleName as Service + */ +HWTEST_F(AmsAbilityVisibleTest, AMS_ABILITY_VISIBLE_1000, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_1000 start"; + std::string bundleName = bundleNameBase + "PageA"; + std::string abilityName = abilityNameBase + "PageA2"; + std::string bundleName2 = bundleNameBase + "ServiceB"; + std::string abilityName2 = abilityNameBase + "Service"; + + MAP_STR_STR params; + params["targetBundle"] = bundleName2; + params["targetAbility"] = abilityName2; + params["type"] = "Service"; + + Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); + STAbilityUtil::StartAbility(want, abilityMs_); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountOne), 0); + + ExpectAbilityNumInStack(abilityName, 1); + ExpectAbilityNumInStack(abilityName2, 0, DUMP_SERVICE); + ExpectAbilityCurrentState(abilityName, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_1000 end"; +} + +/* + * @tc.number : AMS_ABILITY_VISIBLE_1100 + * @tc.name : Visible attribute impact on ConnectAbility + * @tc.desc : 1.The test process starts an ability(PageB2) whose visible attribute is true + * 2.The ability(PageB2) Connect a Service ability(Service) whose visible attribute is false + * 3.PageB2 has the same bundleName as Service + */ +HWTEST_F(AmsAbilityVisibleTest, AMS_ABILITY_VISIBLE_1100, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_1100 start"; + std::string bundleName = bundleNameBase + "ServiceB"; + std::string abilityName = abilityNameBase + "PageB2"; + std::string bundleName2 = bundleNameBase + "ServiceB"; + std::string abilityName2 = abilityNameBase + "Service"; + + MAP_STR_STR params; + params["targetBundle"] = bundleName2; + params["targetAbility"] = abilityName2; + params["type"] = "Service"; + + Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); + STAbilityUtil::StartAbility(want, abilityMs_); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnConnect, abilityStateCountOne), 0); + + ExpectAbilityNumInStack(abilityName, 1); + ExpectAbilityNumInStack(abilityName2, 1, DUMP_SERVICE); + ExpectAbilityCurrentState(abilityName, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_1100 end"; +} + +/* + * @tc.number : AMS_ABILITY_VISIBLE_1200 + * @tc.name : Visible attribute impact on start dataAbility + * @tc.desc : 1.The test process starts an ability(PageA2) whose visible attribute is true + * 2.The ability(PageA2) start a Data ability(Data) whose visible attribute is false + * 3.PageA2 has the different bundleName as Data + */ +HWTEST_F(AmsAbilityVisibleTest, AMS_ABILITY_VISIBLE_1200, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_1200 start"; + std::string bundleName = bundleNameBase + "PageA"; + std::string abilityName = abilityNameBase + "PageA2"; + std::string bundleName2 = bundleNameBase + "ServiceB"; + std::string abilityName2 = abilityNameBase + "Data"; + + MAP_STR_STR params; + params["targetBundle"] = bundleName2; + params["targetAbility"] = abilityName2; + params["type"] = "Data"; + + Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); + STAbilityUtil::StartAbility(want, abilityMs_); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountOne), 0); + + ExpectAbilityNumInStack(abilityName, 1); + ExpectAbilityNumInStack(abilityName2, 0, DUMP_DATA); + ExpectAbilityCurrentState(abilityName, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_1200 end"; +} + +/* + * @tc.number : AMS_ABILITY_VISIBLE_1300 + * @tc.name : Visible attribute impact on start dataAbility + * @tc.desc : 1.The test process starts an ability(PageB2) whose visible attribute is true + * 2.The ability(PageB2) start a Data ability(Data) whose visible attribute is false + * 3.PageB2 has the same bundleName as Data + */ +HWTEST_F(AmsAbilityVisibleTest, AMS_ABILITY_VISIBLE_1300, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_1300 start"; + std::string bundleName = bundleNameBase + "ServiceB"; + std::string abilityName = abilityNameBase + "PageB2"; + std::string bundleName2 = bundleNameBase + "ServiceB"; + std::string abilityName2 = abilityNameBase + "Data"; + + MAP_STR_STR params; + params["targetBundle"] = bundleName2; + params["targetAbility"] = abilityName2; + params["type"] = "Data"; + + Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); + STAbilityUtil::StartAbility(want, abilityMs_); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateInsert, abilityStateCountOne), 0); + + ExpectAbilityNumInStack(abilityName, 1); + ExpectAbilityNumInStack(abilityName2, 1, DUMP_DATA); + ExpectAbilityCurrentState(abilityName, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_1300 end"; +} + +/* + * @tc.number : AMS_ABILITY_VISIBLE_1400 + * @tc.name : Visible attribute impact on terminateAbility + * @tc.desc : 1.The test process starts an ability(PageA2) whose visible attribute is true + * 2.The ability(PageA2) starts an ability(PageA3,type:singleton) whose visible attribute is false + * 3.PageA2 has the same bundleName as PageA3 + * 4.terminate PageA3 + */ +HWTEST_F(AmsAbilityVisibleTest, AMS_ABILITY_VISIBLE_1400, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_1400 start"; + std::string bundleName = bundleNameBase + "PageA"; + std::string abilityName = abilityNameBase + "PageA2"; + std::string abilityName2 = abilityNameBase + "PageA3"; + + MAP_STR_STR params; + params["targetBundle"] = bundleName; + params["targetAbility"] = abilityName2; + params["type"] = "Page"; + + Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); + STAbilityUtil::StartAbility(want, abilityMs_); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnActive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnInactive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnBackground, abilityStateCountOne), 0); + + ExpectAbilityNumInStack(abilityName, 1); + ExpectAbilityNumInStack(abilityName2, 1); + ExpectAbilityCurrentState(abilityName, AbilityState_Test::BACKGROUND, AbilityState_Test::MOVING_BACKGROUND); + ExpectAbilityCurrentState(abilityName2, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); + int eventCode = -1; + STAbilityUtil::PublishEvent(terminateAbility, eventCode, abilityName2); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnInactive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnBackground, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStop, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountTwo), 0); + + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_1400 end"; +} + +/* + * @tc.number : AMS_ABILITY_VISIBLE_1500 + * @tc.name : Visible attribute impact on terminateAbilityCaller + * @tc.desc : 1.The test process starts an ability(PageA2) whose visible attribute is true + * 2.The ability(PageA2) starts an ability(PageA3,type:singleton) whose visible attribute is false + * 3.PageA2 has the same bundleName as PageA3 + * 4.terminateCaller PageA2 + */ +HWTEST_F(AmsAbilityVisibleTest, AMS_ABILITY_VISIBLE_1500, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_1500 start"; + std::string bundleName = bundleNameBase + "PageA"; + std::string abilityName = abilityNameBase + "PageA2"; + std::string abilityName2 = abilityNameBase + "PageA3"; + + MAP_STR_STR params; + params["targetBundle"] = bundleName; + params["targetAbility"] = abilityName2; + params["type"] = "Page"; + + Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); + STAbilityUtil::StartAbility(want, abilityMs_); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnActive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnInactive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnBackground, abilityStateCountOne), 0); + + ExpectAbilityNumInStack(abilityName, 1); + ExpectAbilityNumInStack(abilityName2, 1); + ExpectAbilityCurrentState(abilityName, AbilityState_Test::BACKGROUND, AbilityState_Test::MOVING_BACKGROUND); + ExpectAbilityCurrentState(abilityName2, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); + + int eventCode = -1; + STAbilityUtil::PublishEvent(terminateAbilityCaller, eventCode, abilityName); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnInactive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnBackground, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStop, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountTwo), 0); + ExpectAbilityNumInStack(abilityName, 1); + ExpectAbilityNumInStack(abilityName2, 0); + ExpectAbilityCurrentState(abilityName, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); + + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_1500 end"; +} + +/* + * @tc.number : AMS_ABILITY_VISIBLE_1600 + * @tc.name : Visible attribute impact on terminateAbility + * @tc.desc : 1.The test process starts an ability(PageB2) whose visible attribute is true + * 2.The ability(PageB2) start a Service ability(Service) whose visible attribute is false + * 3.PageB2 has the same bundleName as Service + * 4.terminate Service and PageB2 + */ +HWTEST_F(AmsAbilityVisibleTest, AMS_ABILITY_VISIBLE_1600, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_1600 start"; + std::string bundleName = bundleNameBase + "ServiceB"; + std::string abilityName = abilityNameBase + "PageB2"; + std::string bundleName2 = bundleNameBase + "ServiceB"; + std::string abilityName2 = abilityNameBase + "Service"; + + MAP_STR_STR params; + params["targetBundle"] = bundleName2; + params["targetAbility"] = abilityName2; + params["type"] = "Page"; + + Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); + STAbilityUtil::StartAbility(want, abilityMs_); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnCommand, abilityStateCountOne), 0); + + ExpectAbilityNumInStack(abilityName, 1); + ExpectAbilityNumInStack(abilityName2, 1, DUMP_SERVICE); + ExpectAbilityCurrentState(abilityName, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); + + int eventCode = -1; + STAbilityUtil::PublishEvent(terminateAbility, eventCode, abilityName2); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnBackground, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStop, abilityStateCountOne), 0); + + STAbilityUtil::PublishEvent(terminateAbility, eventCode, abilityName); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnInactive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnBackground, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStop, abilityStateCountOne), 0); + ExpectAbilityNumInStack(abilityName, 0); + + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_1600 end"; +} + +/* + * @tc.number : AMS_ABILITY_VISIBLE_1700 + * @tc.name : Visible attribute impact on terminateAbilityCaller + * @tc.desc : 1.The test process starts an ability(PageB2) whose visible attribute is true + * 2.The ability(PageB2) Connect a Service ability(Service) whose visible attribute is false + * 3.The ability(Service) start a Service ability(ServiceA1) whose visible attribute is false + * 3.PageB2 has the same bundleName as Service and ServiceA1 + * 4.terminateCaller Service + */ +HWTEST_F(AmsAbilityVisibleTest, AMS_ABILITY_VISIBLE_1700, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_1700 start"; + std::string bundleName = bundleNameBase + "ServiceB"; + std::string abilityName = abilityNameBase + "PageB2"; + std::string bundleName2 = bundleNameBase + "ServiceB"; + std::string abilityName2 = abilityNameBase + "Service"; + std::string abilityName3 = abilityNameBase + "ServiceA1"; + + MAP_STR_STR params; + params["targetBundle"] = bundleName2 + "," + bundleName2; + params["targetAbility"] = abilityName2 + "," + abilityName3; + params["type"] = "Service,Page"; + + Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); + STAbilityUtil::StartAbility(want, abilityMs_); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnConnect, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName3 + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName3 + abilityStateOnCommand, abilityStateCountOne), 0); + + ExpectAbilityNumInStack(abilityName, 1); + ExpectAbilityNumInStack(abilityName2, 1, DUMP_SERVICE); + ExpectAbilityNumInStack(abilityName3, 1, DUMP_SERVICE); + ExpectAbilityCurrentState(abilityName, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); + + int eventCode = -1; + STAbilityUtil::PublishEvent(terminateAbilityCaller, eventCode, abilityName2); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName3 + abilityStateOnBackground, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName3 + abilityStateOnStop, abilityStateCountOne), 0); + + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_1700 end"; +} + +/* + * @tc.number : AMS_ABILITY_VISIBLE_1800 + * @tc.name : Visible attribute impact on terminateAbilityResult + * @tc.desc : 1.The test process starts an ability(PageB2) whose visible attribute is true + * 2.The ability(PageB2) start a Service ability(Service) whose visible attribute is false + * 3.PageB2 has the same bundleName as Service + * 4.terminateAbilityResult Service and terminateAbility PageB2 + */ +HWTEST_F(AmsAbilityVisibleTest, AMS_ABILITY_VISIBLE_1800, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_1800 start"; + std::string bundleName = bundleNameBase + "ServiceB"; + std::string abilityName = abilityNameBase + "PageB2"; + std::string bundleName2 = bundleNameBase + "ServiceB"; + std::string abilityName2 = abilityNameBase + "Service"; + + MAP_STR_STR params; + params["targetBundle"] = bundleName2; + params["targetAbility"] = abilityName2; + params["type"] = "Page"; + + Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); + STAbilityUtil::StartAbility(want, abilityMs_); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnCommand, abilityStateCountOne), 0); + + ExpectAbilityNumInStack(abilityName, 1); + ExpectAbilityNumInStack(abilityName2, 1, DUMP_SERVICE); + ExpectAbilityCurrentState(abilityName, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); + + int eventCode = 1; + STAbilityUtil::PublishEvent(terminateAbilityResult, eventCode, abilityName2); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnBackground, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStop, abilityStateCountOne), 0); + + STAbilityUtil::PublishEvent(terminateAbility, eventCode, abilityName); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnInactive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnBackground, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStop, abilityStateCountOne), 0); + ExpectAbilityNumInStack(abilityName, 0); + + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_1800 end"; +} + +/* + * @tc.number : AMS_ABILITY_VISIBLE_1900 + * @tc.name : Visible attribute impact on disconnectService + * @tc.desc : 1.The test process starts an ability(PageB2) whose visible attribute is true + * 2.The ability(PageB2) Connect a Service ability(Service) whose visible attribute is false + * 3.PageB2 has the same bundleName as Service + * 4.disconnectService Service + */ +HWTEST_F(AmsAbilityVisibleTest, AMS_ABILITY_VISIBLE_1900, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_1900 start"; + std::string bundleName = bundleNameBase + "ServiceB"; + std::string abilityName = abilityNameBase + "PageB2"; + std::string bundleName2 = bundleNameBase + "ServiceB"; + std::string abilityName2 = abilityNameBase + "Service"; + + MAP_STR_STR params; + params["targetBundle"] = bundleName2; + params["targetAbility"] = abilityName2; + params["type"] = "Service"; + + Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); + STAbilityUtil::StartAbility(want, abilityMs_); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnConnect, abilityStateCountOne), 0); + + ExpectAbilityNumInStack(abilityName, 1); + ExpectAbilityNumInStack(abilityName2, 1, DUMP_SERVICE); + ExpectAbilityCurrentState(abilityName, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); + + int eventCode = 0; + STAbilityUtil::PublishEvent(disconnectService, eventCode, abilityName); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnDisconnect, abilityStateCountOne), 0); + + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_1900 end"; +} + +/* + * @tc.number : AMS_ABILITY_VISIBLE_2000 + * @tc.name : Visible attribute impact on data Release + * @tc.desc : 1.The test process starts an ability(PageB2) whose visible attribute is true + * 2.The ability(PageB2) start a data ability(Data) whose visible attribute is false + * 3.PageB2 has the same bundleName as Data + * 4.Release Data + */ +HWTEST_F(AmsAbilityVisibleTest, AMS_ABILITY_VISIBLE_2000, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_2000 start"; + std::string bundleName = bundleNameBase + "ServiceB"; + std::string abilityName = abilityNameBase + "PageB2"; + std::string bundleName2 = bundleNameBase + "ServiceB"; + std::string abilityName2 = abilityNameBase + "Data"; + + MAP_STR_STR params; + params["targetBundle"] = bundleName2; + params["targetAbility"] = abilityName2; + params["type"] = "DataRelease"; + + Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); + STAbilityUtil::StartAbility(want, abilityMs_); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateInsert, abilityStateCountOne), 0); + + ExpectAbilityNumInStack(abilityName, 1); + ExpectAbilityNumInStack(abilityName2, 1, DUMP_DATA); + ExpectAbilityCurrentState(abilityName, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); + + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_2000 end"; +} + +/* + * @tc.number : AMS_ABILITY_VISIBLE_2100 + * @tc.name : Visible attribute impact on terminateAbilityCaller + * @tc.desc : 1.The test process starts an ability(PageB2) whose visible attribute is true + * 2.The ability(PageB2) Connect a Service ability(Service) whose visible attribute is false + * 3.PageB2 has the same bundleName as Service + * 4.terminateCaller Service + */ +HWTEST_F(AmsAbilityVisibleTest, AMS_ABILITY_VISIBLE_2100, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_2100 start"; + std::string bundleName = bundleNameBase + "ServiceB"; + std::string abilityName = abilityNameBase + "PageB2"; + std::string bundleName2 = bundleNameBase + "ServiceB"; + std::string abilityName2 = abilityNameBase + "Service"; + + MAP_STR_STR params; + params["targetBundle"] = bundleName2; + params["targetAbility"] = abilityName2; + params["type"] = "Page"; + + Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); + STAbilityUtil::StartAbility(want, abilityMs_); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnCommand, abilityStateCountOne), 0); + + ExpectAbilityNumInStack(abilityName, 1); + ExpectAbilityNumInStack(abilityName2, 1, DUMP_SERVICE); + ExpectAbilityCurrentState(abilityName, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); + + int eventCode = -1; + STAbilityUtil::PublishEvent(terminateAbilityCaller, eventCode, abilityName); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnBackground, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStop, abilityStateCountOne), 0); + + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_2100 end"; +} + +/* + * @tc.number : AMS_ABILITY_VISIBLE_2200 + * @tc.name : Visible attribute impact on wantagent + * @tc.desc : 1.The test process starts an ability(PageA2) whose visible attribute is true + * 2.The ability(PageA2) get the wantagent to starts an ability(PageA1) whose visible attribute is false + * 3.PageA2 has the same bundleName as PageA1 + * 4.trigger wantagent + */ +HWTEST_F(AmsAbilityVisibleTest, AMS_ABILITY_VISIBLE_2200, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_2200 start"; + std::string bundleName = bundleNameBase + "PageA"; + std::string abilityName = abilityNameBase + "PageA2"; + std::string abilityName2 = abilityNameBase + "PageA1"; + + MAP_STR_STR params; + params["targetBundle"] = bundleName; + params["targetAbility"] = abilityName2; + params["type"] = "TriggerWantAgentPageAbility"; + + Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); + STAbilityUtil::StartAbility(want, abilityMs_); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStart, abilityStateCountOne), 0); + int eventCode = 0; + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, triggerWantAgentState, eventCode), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnActive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnInactive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnBackground, abilityStateCountOne), 0); + + ExpectAbilityNumInStack(abilityName, 1); + ExpectAbilityCurrentState(abilityName, AbilityState_Test::BACKGROUND, AbilityState_Test::MOVING_BACKGROUND); + ExpectAbilityCurrentState(abilityName2, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); + + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_2200 end"; +} + +/* + * @tc.number : AMS_ABILITY_VISIBLE_2300 + * @tc.name : Visible attribute impact on wantagent + * @tc.desc : 1.The test process starts an ability(PageA2) whose visible attribute is true + * 2.The ability(PageA2) get the wantagent to starts an ability(PageB1) whose visible attribute is false + * 3.PageA2 has the different bundleName as PageB1 + * 4.trigger wantagent + */ +HWTEST_F(AmsAbilityVisibleTest, AMS_ABILITY_VISIBLE_2300, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_2300 start"; + std::string bundleName = bundleNameBase + "PageA"; + std::string abilityName = abilityNameBase + "PageA2"; + std::string bundleName2 = bundleNameBase + "ServiceB"; + std::string abilityName2 = abilityNameBase + "PageB1"; + + MAP_STR_STR params; + params["targetBundle"] = bundleName2; + params["targetAbility"] = abilityName2; + params["type"] = "TriggerWantAgentPageAbility"; + + Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); + STAbilityUtil::StartAbility(want, abilityMs_); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); + int eventCode = 0; + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, triggerWantAgentState, eventCode), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountOne), 0); + + ExpectAbilityNumInStack(abilityName, 1); + ExpectAbilityNumInStack(abilityName2, 0); + ExpectAbilityCurrentState(abilityName, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); + + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_2300 end"; +} + +/* + * @tc.number : AMS_ABILITY_VISIBLE_2400 + * @tc.name : Visible attribute impact on wantagent + * @tc.desc : 1.The test process starts an ability(PageA2) whose visible attribute is true + * 2.The ability(PageA2) get the wantagent to starts an ability(PageB2) whose visible attribute is true + * 3.PageA2 has the different bundleName as PageB2 + * 4.trigger wantagent + */ +HWTEST_F(AmsAbilityVisibleTest, AMS_ABILITY_VISIBLE_2400, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_2400 start"; + std::string bundleName = bundleNameBase + "PageA"; + std::string abilityName = abilityNameBase + "PageA2"; + std::string bundleName2 = bundleNameBase + "ServiceB"; + std::string abilityName2 = abilityNameBase + "PageB2"; + + MAP_STR_STR params; + params["targetBundle"] = bundleName2; + params["targetAbility"] = abilityName2; + params["type"] = "TriggerWantAgentPageAbility"; + + Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); + STAbilityUtil::StartAbility(want, abilityMs_); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); + int eventCode = 0; + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, triggerWantAgentState, eventCode), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnActive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnBackground, abilityStateCountOne), 0); + + ShowDump(); + ExpectAbilityNumInStack(abilityName, 1); + ExpectAbilityNumInStack(abilityName2, 1); + ExpectAbilityCurrentState(abilityName2, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_2400 end"; +} + +/* + * @tc.number : AMS_ABILITY_VISIBLE_2500 + * @tc.name : Visible attribute impact on wantagent + * @tc.desc : 1.The test process starts an ability(PageA2) whose visible attribute is true + * 2.The ability(PageA2) get the wantagent to starts an ability whose visible attribute is false + * 3.PageA2 has the different bundleName as Service + * 4.trigger wantagent + */ +HWTEST_F(AmsAbilityVisibleTest, AMS_ABILITY_VISIBLE_2500, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_2500 start"; + std::string bundleName = bundleNameBase + "PageA"; + std::string abilityName = abilityNameBase + "PageA2"; + std::string bundleName2 = bundleNameBase + "ServiceB"; + std::string abilityName2 = abilityNameBase + "Service"; + + MAP_STR_STR params; + params["targetBundle"] = bundleName2; + params["targetAbility"] = abilityName2; + params["type"] = "TriggerWantAgentServiceAbility"; + + Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); + STAbilityUtil::StartAbility(want, abilityMs_); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); + int eventCode = 0; + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, triggerWantAgentState, eventCode), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountOne), 0); + + ExpectAbilityNumInStack(abilityName, 1); + ExpectAbilityNumInStack(abilityName2, 0, DUMP_SERVICE); + ExpectAbilityCurrentState(abilityName, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_2500 end"; +} + +/* + * @tc.number : AMS_ABILITY_VISIBLE_2600 + * @tc.name : Visible attribute impact on wantagent + * @tc.desc : 1.The test process starts an ability(PageB2) whose visible attribute is true + * 2.The ability(PageB2) get the wantagent to starts an ability whose visible attribute is false + * 3.PageB2 has the same bundleName as Service + * 4.trigger wantagent + */ +HWTEST_F(AmsAbilityVisibleTest, AMS_ABILITY_VISIBLE_2600, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_2600 start"; + std::string bundleName = bundleNameBase + "ServiceB"; + std::string abilityName = abilityNameBase + "PageB2"; + std::string bundleName2 = bundleNameBase + "ServiceB"; + std::string abilityName2 = abilityNameBase + "Service"; + + MAP_STR_STR params; + params["targetBundle"] = bundleName2; + params["targetAbility"] = abilityName2; + params["type"] = "TriggerWantAgentServiceAbility"; + + Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); + STAbilityUtil::StartAbility(want, abilityMs_); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); + int eventCode = 0; + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, triggerWantAgentState, eventCode), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStart, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnCommand, abilityStateCountOne), 0); + + ExpectAbilityNumInStack(abilityName, 1); + ExpectAbilityNumInStack(abilityName2, 1, DUMP_SERVICE); + ExpectAbilityCurrentState(abilityName, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); + GTEST_LOG_(INFO) << "AmsAbilityVisibleTest AMS_ABILITY_VISIBLE_2600 end"; +} \ No newline at end of file diff --git a/test/systemtest/common/ams/ams_app_process_manage_test/BUILD.gn b/test/systemtest/common/ams/ams_app_process_manage_test/BUILD.gn old mode 100644 new mode 100755 index a305d3cc51..658d8d9153 --- a/test/systemtest/common/ams/ams_app_process_manage_test/BUILD.gn +++ b/test/systemtest/common/ams/ams_app_process_manage_test/BUILD.gn @@ -21,6 +21,7 @@ ohos_systemtest("ams_app_process_manage_test") { "//foundation/distributedschedule/safwk/services/safwk/include", "${appexecfwk_path}/test/resource/amssystemtestability/abilitySrc/common", "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/include", + "//third_party/jsoncpp/include", ] sources = [ @@ -47,6 +48,7 @@ ohos_systemtest("ams_app_process_manage_test") { "${appexecfwk_path}/interfaces/innerkits/libeventhandler:libeventhandler", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", "//utils/native/base:utils", ] diff --git a/test/systemtest/common/ams/ams_configuration_updated_test/BUILD.gn b/test/systemtest/common/ams/ams_configuration_updated_test/BUILD.gn new file mode 100755 index 0000000000..173f0d0fed --- /dev/null +++ b/test/systemtest/common/ams/ams_configuration_updated_test/BUILD.gn @@ -0,0 +1,67 @@ +# Copyright (c) 2021 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/appexecfwk/standard/appexecfwk.gni") +module_output_path = "appexecfwk_standard/ams" + +ohos_systemtest("ams_configuration_updated_test") { + module_out_path = module_output_path + + include_dirs = [ + "//foundation/distributedschedule/safwk/services/safwk/include", + "${appexecfwk_path}/test/resource/amssystemtestability/abilitySrc/common", + "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/include", + "//third_party/jsoncpp/include", + ] + + sources = [ + "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/src/event.cpp", + "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/src/module_test_dump_util.cpp", + "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/src/stoperator.cpp", + "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/src/system_test_ability_util.cpp", + "ams_configuration_updated_test.cpp", + ] + + configs = [ + "${aafwk_path}/services/abilitymgr:abilityms_config", + "${appexecfwk_path}/services/appmgr:appmgr_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${aafwk_path}/interfaces/innerkits/want:want", + "${aafwk_path}/services/abilitymgr:abilityms", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${appexecfwk_path}/interfaces/innerkits/libeventhandler:libeventhandler", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", + "//utils/native/base:utils", + ] + + external_deps = [ + "ces_standard:cesfwk_core", + "ces_standard:cesfwk_innerkits", + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("systemtest") { + testonly = true + + deps = [ ":ams_configuration_updated_test" ] +} diff --git a/test/systemtest/common/ams/ams_configuration_updated_test/ams_configuration_updated_test.cpp b/test/systemtest/common/ams/ams_configuration_updated_test/ams_configuration_updated_test.cpp new file mode 100644 index 0000000000..785b81dd6f --- /dev/null +++ b/test/systemtest/common/ams/ams_configuration_updated_test/ams_configuration_updated_test.cpp @@ -0,0 +1,613 @@ +/* + * Copyright (c) 2021 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 +// #include +#include +#include +#include +// #include +// #include +// #include +// #include + +#include "ability_append_test_info.h" +// #include "ability_lifecycle.h" +// #include "ability_lifecycle_executor.h" +// #include "ability_manager_errors.h" +// #include "ability_manager_service.h" +// #include "app_mgr_service.h" +#include "common_event.h" +#include "common_event_manager.h" +// #include "event.h" +#include "hilog_wrapper.h" +// #include "module_test_dump_util.h" +// #include "sa_mgr_client.h" +// #include "semaphore_ex.h" +// #include "skills.h" +#include "stoperator.h" +// #include "system_ability_definition.h" +#include "system_test_ability_util.h" +// #include "uri.h" +namespace { +using namespace OHOS; +using namespace OHOS::AAFwk; +using namespace OHOS::AppExecFwk; +using namespace OHOS::EventFwk; +// using namespace OHOS::MTUtil; +using namespace OHOS::STtools; +using namespace OHOS::STABUtil; +using namespace testing::ext; + +using MAP_STR_STR = std::map; +static const string KIT_BUNDLE_NAME = "com.ohos.amsst.ConfigurationUpdated"; +static const string KIT_HAP_NAME = "amsConfigurationUpdatedTest"; +static const string MAIN_ABILITY = "MainAbility"; +static const string SECOND_ABILITY = "SecondAbility"; +static const string THIRD_ABILITY = "ThirdAbility"; +static const string FOURTH_ABILITY = "FourthAbility"; +static const string FIFTH_ABILITY = "FifthAbility"; +static const string SIXTH_ABILITY = "SixthAbility"; +static constexpr int WAIT_TIME = 1; +static constexpr int WAIT_LAUNCHER_TIME = 5; +static constexpr int WAIT_SETUP_TIME = 1; +static constexpr int WAIT_TEARDOWN_TIME = 1; +static string g_eventMessage = ""; +static string g_tempDataStr = ""; + +std::vector eventList = { + g_EVENT_RESP_MAIN_LIFECYCLE, + g_EVENT_RESP_SECOND_LIFECYCLE, + g_EVENT_RESP_THIRD_LIFECYCLE, + g_EVENT_RESP_FOURTH_LIFECYCLE, + g_EVENT_RESP_FIFTH_LIFECYCLE, + g_EVENT_RESP_SIXTH_LIFECYCLE, +}; + +class AmsConfigurationUpdatedTest : public testing::Test { + public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + + // static void Reinstall(const std::string &hapName, const std::string &bundleName); + // void ResetSystem() const; + static bool SubscribeEvent(); + static int TestWaitCompleted(Event &event, const std::string &eventName, const int code, const int timeout = 10); + static void TestCompleted(Event &event, const std::string &eventName, const int code); + + class AppEventSubscriber : public CommonEventSubscriber { + public: + explicit AppEventSubscriber(const CommonEventSubscribeInfo &sp) : CommonEventSubscriber(sp){}; + virtual void OnReceiveEvent(const CommonEventData &data) override; + ~AppEventSubscriber(){}; + }; + + static sptr g_abilityMs; + static Event event; + static std::shared_ptr subscriber_; + }; + + Event AmsConfigurationUpdatedTest::event = Event(); + sptr AmsConfigurationUpdatedTest::g_abilityMs = nullptr; + std::shared_ptr AmsConfigurationUpdatedTest::subscriber_ = nullptr; + + void AmsConfigurationUpdatedTest::AppEventSubscriber::OnReceiveEvent(const CommonEventData &data) + { + GTEST_LOG_(INFO) << "\nOnReceiveEvent: event====>" << data.GetWant().GetAction(); + GTEST_LOG_(INFO) << "\nOnReceiveEvent: data=====>" << data.GetData(); + GTEST_LOG_(INFO) << "\nOnReceiveEvent: code=====>" << data.GetCode(); + if (find(eventList.begin(), eventList.end(), data.GetWant().GetAction()) != eventList.end()) { + TestCompleted(event, data.GetData(), data.GetCode()); + } + } + + int AmsConfigurationUpdatedTest::TestWaitCompleted( + Event &event, const std::string &eventName, const int code, const int timeout) + { + GTEST_LOG_(INFO) << "---------->\n\nTestWaitCompleted ====>: " << eventName << " " << code; + return STAbilityUtil::WaitCompleted(event, eventName, code, timeout); + } + + void AmsConfigurationUpdatedTest::TestCompleted(Event &event, const std::string &eventName, const int code) + { + GTEST_LOG_(INFO) << "----------<\nTestCompleted ====>: " << eventName << " " << code << "\n" ; + return STAbilityUtil::Completed(event, eventName, code); + } + + void AmsConfigurationUpdatedTest::SetUpTestCase(void) + { + if (!SubscribeEvent()) { + GTEST_LOG_(INFO) << "\nSubscribeEvent error====<"; + } + } + + void AmsConfigurationUpdatedTest::TearDownTestCase(void) + { + CommonEventManager::UnSubscribeCommonEvent(subscriber_); + } + + void AmsConfigurationUpdatedTest::SetUp(void) + { + STAbilityUtil::Install(KIT_HAP_NAME); + sleep(WAIT_SETUP_TIME); + STAbilityUtil::CleanMsg(event); + } + + void AmsConfigurationUpdatedTest::TearDown(void) + { + STAbilityUtil::Uninstall(KIT_BUNDLE_NAME); + sleep(WAIT_TEARDOWN_TIME); + STAbilityUtil::CleanMsg(event); + } + + bool AmsConfigurationUpdatedTest::SubscribeEvent() + { + MatchingSkills matchingSkills; + for (const auto &e : eventList) { + matchingSkills.AddEvent(e); + } + CommonEventSubscribeInfo subscribeInfo(matchingSkills); + subscribeInfo.SetPriority(1); + subscriber_ = std::make_shared(subscribeInfo); + return CommonEventManager::SubscribeCommonEvent(subscriber_); + } + + /** + * @tc.number : 0100 + * @tc.name : AMS_UpdateConfiguration_0100 + * @tc.desc : Verify whether the results of the orientation function of the system configuration concerned by capability are correct. + */ + + HWTEST_F(AmsConfigurationUpdatedTest, AMS_UpdateConfiguration_0100, Function | MediumTest | Level1) + { + GTEST_LOG_(INFO) << "==========>\nAmsConfigurationUpdatedTest AMS_UpdateConfiguration_0100 start"; + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", MAIN_ABILITY, KIT_BUNDLE_NAME, params); + // start first ability + ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << "\nStartAbility ====>> " << eCode; + + g_tempDataStr = "OnStartOnActive"; + EXPECT_EQ(TestWaitCompleted(event, "OnStartOnActive", MAIN_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + DummyConfiguration mDummyConfiguration("orientation"); + g_abilityMs->UpdateConfiguration(mDummyConfiguration); + g_abilityMs->UpdateConfiguration(mDummyConfiguration); + + g_tempDataStr = "UpdatedUpdated"; + EXPECT_EQ(TestWaitCompleted(event, "UpdatedUpdated", MAIN_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + GTEST_LOG_(INFO) << "\nAmsConfigurationUpdatedTest AMS_UpdateConfiguration_0100 end=========<"; + } + + /** + * @tc.number : 0200 + * @tc.name : AMS_UpdateConfiguration_0200 + * @tc.desc : Verify whether the results of the orientation, locale function of the system configuration concerned by capability are correct. + */ + + HWTEST_F(AmsConfigurationUpdatedTest, AMS_UpdateConfiguration_0200, Function | MediumTest | Level1) + { + GTEST_LOG_(INFO) << "==========>\nAmsConfigurationUpdatedTest AMS_UpdateConfiguration_0200 start"; + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", SECOND_ABILITY, KIT_BUNDLE_NAME, params); + // start first ability + ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << "\nStartAbility ====>> " << eCode; + + g_tempDataStr = "OnStartOnActive"; + EXPECT_EQ(TestWaitCompleted(event, "OnStartOnActive", SECOND_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + DummyConfiguration mDummyConfiguration("locale"); + g_abilityMs->UpdateConfiguration(mDummyConfiguration); + g_abilityMs->UpdateConfiguration(mDummyConfiguration); + + g_tempDataStr = "UpdatedUpdated"; + EXPECT_EQ(TestWaitCompleted(event, "UpdatedUpdated", SECOND_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + GTEST_LOG_(INFO) << "\nAmsConfigurationUpdatedTest AMS_UpdateConfiguration_0200 end=========<"; + } + + /** + * @tc.number : 0300 + * @tc.name : AMS_UpdateConfiguration_0300 + * @tc.desc : Verify whether the results of the orientation, locale, layout function of the system configuration concerned by capability are correct. + */ + + HWTEST_F(AmsConfigurationUpdatedTest, AMS_UpdateConfiguration_0300, Function | MediumTest | Level1) + { + GTEST_LOG_(INFO) << "==========>\nAmsConfigurationUpdatedTest AMS_UpdateConfiguration_0300 start"; + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", THIRD_ABILITY, KIT_BUNDLE_NAME, params); + // start first ability + g_abilityMs = nullptr; + ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << "\nStartAbility ====>> " << eCode; + + g_tempDataStr = "OnStartOnActive"; + EXPECT_EQ(TestWaitCompleted(event, "OnStartOnActive", THIRD_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + DummyConfiguration mDummyConfiguration("layout"); + g_abilityMs->UpdateConfiguration(mDummyConfiguration); + g_abilityMs->UpdateConfiguration(mDummyConfiguration); + + g_tempDataStr = "UpdatedUpdated"; + EXPECT_EQ(TestWaitCompleted(event, "UpdatedUpdated", THIRD_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + GTEST_LOG_(INFO) << "\nAmsConfigurationUpdatedTest AMS_UpdateConfiguration_0300 end=========<"; + } + + /** + * @tc.number : 0400 + * @tc.name : AMS_UpdateConfiguration_0400 + * @tc.desc : Verify whether the results of the orientation, locale, layout,fontSize function of the system configuration concerned by capability are correct. + */ + + HWTEST_F(AmsConfigurationUpdatedTest, AMS_UpdateConfiguration_0400, Function | MediumTest | Level1) + { + GTEST_LOG_(INFO) << "==========>\nAmsConfigurationUpdatedTest AMS_UpdateConfiguration_0400 start"; + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", FOURTH_ABILITY, KIT_BUNDLE_NAME, params); + // start first ability + ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << "\nStartAbility ====>> " << eCode; + + g_tempDataStr = "OnStartOnActive"; + EXPECT_EQ(TestWaitCompleted(event, "OnStartOnActive", FOURTH_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + DummyConfiguration mDummyConfiguration("density#fontSize#"); + g_abilityMs->UpdateConfiguration(mDummyConfiguration); + g_abilityMs->UpdateConfiguration(mDummyConfiguration); + + g_tempDataStr = "UpdatedUpdated"; + EXPECT_EQ(TestWaitCompleted(event, "UpdatedUpdated", FOURTH_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + GTEST_LOG_(INFO) << "\nAmsConfigurationUpdatedTest AMS_UpdateConfiguration_0400 end=========<"; + } + + /** + * @tc.number : 0500 + * @tc.name : AMS_UpdateConfiguration_0500 + * @tc.desc : Verify whether the results of the orientation, locale, layout,fontSize,density function of the system configuration concerned by capability are correct. + */ + + HWTEST_F(AmsConfigurationUpdatedTest, AMS_UpdateConfiguration_0500, Function | MediumTest | Level1) + { + GTEST_LOG_(INFO) << "==========>\nAmsConfigurationUpdatedTest AMS_UpdateConfiguration_0500 start"; + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", FIFTH_ABILITY, KIT_BUNDLE_NAME, params); + // start first ability + ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << "\nStartAbility ====>> " << eCode; + + g_tempDataStr = "OnStartOnActive"; + EXPECT_EQ(TestWaitCompleted(event, "OnStartOnActive", FIFTH_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + DummyConfiguration mDummyConfiguration("fontSize#density"); + g_abilityMs->UpdateConfiguration(mDummyConfiguration); + g_abilityMs->UpdateConfiguration(mDummyConfiguration); + + g_tempDataStr = "UpdatedUpdated"; + EXPECT_EQ(TestWaitCompleted(event, "UpdatedUpdated", FIFTH_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + GTEST_LOG_(INFO) << "\nAmsConfigurationUpdatedTest AMS_UpdateConfiguration_0500 end=========<"; + } + + + /** + * @tc.number : 0600 + * @tc.name : AMS_UpdateConfiguration_0600 + * @tc.desc : Verify whether the results of the orientation function of the system configuration concerned by capability are correct. + */ + + HWTEST_F(AmsConfigurationUpdatedTest, AMS_UpdateConfiguration_0600, Function | MediumTest | Level1) + { + GTEST_LOG_(INFO) << "==========>\nAmsConfigurationUpdatedTest AMS_UpdateConfiguration_0600 start"; + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", MAIN_ABILITY, KIT_BUNDLE_NAME, params); + // start first ability + ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << "\nStartAbility ====>> " << eCode; + + g_tempDataStr = "OnStartOnActive"; + EXPECT_EQ(TestWaitCompleted(event, "OnStartOnActive", MAIN_ABILITY_CODE, WAIT_LAUNCHER_TIME), 0); + + DummyConfiguration mDummyConfiguration("locale#layout#fontSize#density"); + g_abilityMs->UpdateConfiguration(mDummyConfiguration); + g_abilityMs->UpdateConfiguration(mDummyConfiguration); + + g_tempDataStr = "OnInactiveOnBackgroundOnStop"; + EXPECT_EQ(TestWaitCompleted(event, "OnInactiveOnBackgroundOnStop", MAIN_ABILITY_CODE, WAIT_LAUNCHER_TIME), 0); + g_tempDataStr = "OnStartOnActive"; + EXPECT_EQ(TestWaitCompleted(event, "OnStartOnActive", MAIN_ABILITY_CODE, WAIT_LAUNCHER_TIME), 0); + + g_tempDataStr = "UpdatedUpdated"; + EXPECT_NE(TestWaitCompleted(event, "UpdatedUpdated", MAIN_ABILITY_CODE, WAIT_LAUNCHER_TIME), 0); + + + GTEST_LOG_(INFO) << "\nAmsConfigurationUpdatedTest AMS_UpdateConfiguration_0600 end=========<"; + } + + /** + * @tc.number : 0700 + * @tc.name : AMS_UpdateConfiguration_0700 + * @tc.desc : Verify whether the results of the orientation, locale function of the system configuration concerned by capability are correct. + */ + + HWTEST_F(AmsConfigurationUpdatedTest, AMS_UpdateConfiguration_0700, Function | MediumTest | Level1) + { + GTEST_LOG_(INFO) << "==========>\nAmsConfigurationUpdatedTest AMS_UpdateConfiguration_0700 start"; + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", SECOND_ABILITY, KIT_BUNDLE_NAME, params); + // start first ability + ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << "\nStartAbility ====>> " << eCode; + + g_tempDataStr = "OnStartOnActive"; + EXPECT_EQ(TestWaitCompleted(event, "OnStartOnActive", SECOND_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + DummyConfiguration mDummyConfiguration("layout#fontSize#density"); + g_abilityMs->UpdateConfiguration(mDummyConfiguration); + g_abilityMs->UpdateConfiguration(mDummyConfiguration); + + g_tempDataStr = "OnInactiveOnBackgroundOnStop"; + EXPECT_EQ(TestWaitCompleted(event, "OnInactiveOnBackgroundOnStop", SECOND_ABILITY_CODE, WAIT_LAUNCHER_TIME), 0); + g_tempDataStr = "OnStartOnActive"; + EXPECT_EQ(TestWaitCompleted(event, "OnStartOnActive", SECOND_ABILITY_CODE, WAIT_LAUNCHER_TIME), 0); + + g_tempDataStr = "UpdatedUpdated"; + EXPECT_NE(TestWaitCompleted(event, "UpdatedUpdated", SECOND_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + GTEST_LOG_(INFO) << "\nAmsConfigurationUpdatedTest AMS_UpdateConfiguration_0700 end=========<"; + } + + /** + * @tc.number : 0800 + * @tc.name : AMS_UpdateConfiguration_0800 + * @tc.desc : Verify whether the results of the function of the system configuration concerned by capability are correct. + */ + + HWTEST_F(AmsConfigurationUpdatedTest, AMS_UpdateConfiguration_0800, Function | MediumTest | Level1) + { + GTEST_LOG_(INFO) << "==========>\nAmsConfigurationUpdatedTest AMS_UpdateConfiguration_0800 start"; + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", SIXTH_ABILITY, KIT_BUNDLE_NAME, params); + // start first ability + ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << "\nStartAbility ====>> " << eCode; + + g_tempDataStr = "OnStartOnActive"; + EXPECT_EQ(TestWaitCompleted(event, "OnStartOnActive", SIXTH_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + DummyConfiguration mDummyConfiguration("orientation"); + g_abilityMs->UpdateConfiguration(mDummyConfiguration); + + g_tempDataStr = "OnInactiveOnBackgroundOnStop"; + EXPECT_EQ(TestWaitCompleted(event, "OnInactiveOnBackgroundOnStop", SIXTH_ABILITY_CODE, WAIT_LAUNCHER_TIME), 0); + g_tempDataStr = "OnStartOnActive"; + EXPECT_EQ(TestWaitCompleted(event, "OnStartOnActive", SIXTH_ABILITY_CODE, WAIT_LAUNCHER_TIME), 0); + + g_tempDataStr = "OnConfigurationUpdated"; + EXPECT_NE(TestWaitCompleted(event, "OnConfigurationUpdated", SIXTH_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + GTEST_LOG_(INFO) << "\nAmsConfigurationUpdatedTest AMS_UpdateConfiguration_0800 end=========<"; + } + + + /** + * @tc.number : 0900 + * @tc.name : AMS_UpdateConfiguration_0900 + * @tc.desc : Verify whether the results of the function of the system configuration concerned by capability are correct. + */ + + HWTEST_F(AmsConfigurationUpdatedTest, AMS_UpdateConfiguration_0900, Function | MediumTest | Level1) + { + GTEST_LOG_(INFO) << "==========>\nAmsConfigurationUpdatedTest AMS_UpdateConfiguration_0900 start"; + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", SIXTH_ABILITY, KIT_BUNDLE_NAME, params); + // start first ability + ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << "\nStartAbility ====>> " << eCode; + + g_tempDataStr = "OnStartOnActive"; + EXPECT_EQ(TestWaitCompleted(event, "OnStartOnActive", SIXTH_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + DummyConfiguration mDummyConfiguration("orientation#locale"); + g_abilityMs->UpdateConfiguration(mDummyConfiguration); + + g_tempDataStr = "OnInactiveOnBackgroundOnStop"; + EXPECT_EQ(TestWaitCompleted(event, "OnInactiveOnBackgroundOnStop", SIXTH_ABILITY_CODE, WAIT_LAUNCHER_TIME), 0); + g_tempDataStr = "OnStartOnActive"; + EXPECT_EQ(TestWaitCompleted(event, "OnStartOnActive", SIXTH_ABILITY_CODE, WAIT_LAUNCHER_TIME), 0); + + g_tempDataStr = "OnConfigurationUpdated"; + EXPECT_NE(TestWaitCompleted(event, "OnConfigurationUpdated", SIXTH_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + + GTEST_LOG_(INFO) << "\nAmsConfigurationUpdatedTest AMS_UpdateConfiguration_0900 end=========<"; + } + + + /** + * @tc.number : 1000 + * @tc.name : AMS_UpdateConfiguration_1000 + * @tc.desc : Verify whether the results of the function of the system configuration concerned by capability are correct. + */ + + HWTEST_F(AmsConfigurationUpdatedTest, AMS_UpdateConfiguration_1000, Function | MediumTest | Level1) + { + GTEST_LOG_(INFO) << "==========>\nAmsConfigurationUpdatedTest AMS_UpdateConfiguration_1000 start"; + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", SIXTH_ABILITY, KIT_BUNDLE_NAME, params); + // start first ability + ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << "\nStartAbility ====>> " << eCode; + + g_tempDataStr = "OnStartOnActive"; + EXPECT_EQ(TestWaitCompleted(event, "OnStartOnActive", SIXTH_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + DummyConfiguration mDummyConfiguration("orientation#locale#layout"); + g_abilityMs->UpdateConfiguration(mDummyConfiguration); + + g_tempDataStr = "OnInactiveOnBackgroundOnStop"; + EXPECT_EQ(TestWaitCompleted(event, "OnInactiveOnBackgroundOnStop", SIXTH_ABILITY_CODE, WAIT_LAUNCHER_TIME), 0); + g_tempDataStr = "OnStartOnActive"; + EXPECT_EQ(TestWaitCompleted(event, "OnStartOnActive", SIXTH_ABILITY_CODE, WAIT_LAUNCHER_TIME), 0); + + g_tempDataStr = "OnConfigurationUpdated"; + EXPECT_NE(TestWaitCompleted(event, "OnConfigurationUpdated", SIXTH_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + + GTEST_LOG_(INFO) << "\nAmsConfigurationUpdatedTest AMS_UpdateConfiguration_1000 end=========<"; + } + + /** + * @tc.number : 1100 + * @tc.name : AMS_UpdateConfiguration_1100 + * @tc.desc : Verify whether the results of the function of the system configuration concerned by capability are correct. + */ + + HWTEST_F(AmsConfigurationUpdatedTest, AMS_UpdateConfiguration_1100, Function | MediumTest | Level1) + { + GTEST_LOG_(INFO) << "==========>\nAmsConfigurationUpdatedTest AMS_UpdateConfiguration_1100 start"; + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", SIXTH_ABILITY, KIT_BUNDLE_NAME, params); + // start first ability + ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << "\nStartAbility ====>> " << eCode; + + g_tempDataStr = "OnStartOnActive"; + EXPECT_EQ(TestWaitCompleted(event, "OnStartOnActive", SIXTH_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + DummyConfiguration mDummyConfiguration("orientation#locale#layout#fontSize"); + g_abilityMs->UpdateConfiguration(mDummyConfiguration); + + g_tempDataStr = "OnInactiveOnBackgroundOnStop"; + EXPECT_EQ(TestWaitCompleted(event, "OnInactiveOnBackgroundOnStop", SIXTH_ABILITY_CODE, WAIT_LAUNCHER_TIME), 0); + g_tempDataStr = "OnStartOnActive"; + EXPECT_EQ(TestWaitCompleted(event, "OnStartOnActive", SIXTH_ABILITY_CODE, WAIT_LAUNCHER_TIME), 0); + + g_tempDataStr = "OnConfigurationUpdated"; + EXPECT_NE(TestWaitCompleted(event, "OnConfigurationUpdated", SIXTH_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + GTEST_LOG_(INFO) << "\nAmsConfigurationUpdatedTest AMS_UpdateConfiguration_1100 end=========<"; + } + + /** + * @tc.number : 1200 + * @tc.name : AMS_UpdateConfiguration_1200 + * @tc.desc : Verify whether the results of the function of the system configuration concerned by capability are correct. + */ + + HWTEST_F(AmsConfigurationUpdatedTest, AMS_UpdateConfiguration_1200, Function | MediumTest | Level1) + { + GTEST_LOG_(INFO) << "==========>\nAmsConfigurationUpdatedTest AMS_UpdateConfiguration_1200 start"; + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", SIXTH_ABILITY, KIT_BUNDLE_NAME, params); + // start first ability + ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << "\nStartAbility ====>> " << eCode; + + g_tempDataStr = "OnStartOnActive"; + EXPECT_EQ(TestWaitCompleted(event, "OnStartOnActive", SIXTH_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + DummyConfiguration mDummyConfiguration("orientation#locale#layout#fontSize#density"); + g_abilityMs->UpdateConfiguration(mDummyConfiguration); + + g_tempDataStr = "OnInactiveOnBackgroundOnStop"; + EXPECT_EQ(TestWaitCompleted(event, "OnInactiveOnBackgroundOnStop", SIXTH_ABILITY_CODE, WAIT_LAUNCHER_TIME), 0); + g_tempDataStr = "OnStartOnActive"; + EXPECT_EQ(TestWaitCompleted(event, "OnStartOnActive", SIXTH_ABILITY_CODE, WAIT_LAUNCHER_TIME), 0); + + g_tempDataStr = "OnConfigurationUpdated"; + EXPECT_NE(TestWaitCompleted(event, "OnConfigurationUpdated", SIXTH_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + GTEST_LOG_(INFO) << "\nAmsConfigurationUpdatedTest AMS_UpdateConfiguration_1200 end=========<"; + } + + /** + * @tc.number : 1300 + * @tc.name : AMS_UpdateConfiguration_1300 + * @tc.desc : Verify whether the results of the orientation function of the system configuration concerned by capability are correct. + */ + + HWTEST_F(AmsConfigurationUpdatedTest, AMS_UpdateConfiguration_1300, Function | MediumTest | Level1) + { + GTEST_LOG_(INFO) << "==========>\nAmsConfigurationUpdatedTest AMS_UpdateConfiguration_1300 start"; + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", MAIN_ABILITY, KIT_BUNDLE_NAME, params); + // start first ability + ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << "\nStartAbility ====>> " << eCode; + + g_tempDataStr = "OnStartOnActive"; + EXPECT_EQ(TestWaitCompleted(event, "OnStartOnActive", MAIN_ABILITY_CODE, WAIT_LAUNCHER_TIME), 0); + + Want wantEntity; + wantEntity.AddEntity(Want::FLAG_HOME_INTENT_FROM_SYSTEM); + STAbilityUtil::StartAbility(wantEntity, g_abilityMs); + GTEST_LOG_(INFO) << "====>Want::FLAG_HOME_INTENT_FROM_SYSTEM"; + DummyConfiguration mDummyConfiguration("orientation"); + g_abilityMs->UpdateConfiguration(mDummyConfiguration); + g_abilityMs->UpdateConfiguration(mDummyConfiguration); + g_abilityMs->UpdateConfiguration(mDummyConfiguration); + g_abilityMs->UpdateConfiguration(mDummyConfiguration); + g_abilityMs->UpdateConfiguration(mDummyConfiguration); + + + want = STAbilityUtil::MakeWant("device", MAIN_ABILITY, KIT_BUNDLE_NAME, params); + eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << "\nStartAbility S ====>> " << eCode; + + g_tempDataStr = "OnInactiveOnBackgroundOnForegroundOnActive"; + EXPECT_EQ(TestWaitCompleted(event, "OnInactiveOnBackgroundOnForegroundOnActive", MAIN_ABILITY_CODE), 0); + + g_tempDataStr = "Updated"; + EXPECT_EQ(TestWaitCompleted(event, "Updated", MAIN_ABILITY_CODE), 0); + + GTEST_LOG_(INFO) << "\nAmsConfigurationUpdatedTest AMS_UpdateConfiguration_1300 end=========<"; + } + /** + * @tc.number : 1400 + * @tc.name : AMS_UpdateConfiguration_1400 + * @tc.desc : Verify whether the results of the orientation function of the system configuration concerned by capability are correct. + */ + + HWTEST_F(AmsConfigurationUpdatedTest, AMS_UpdateConfiguration_1400, Function | MediumTest | Level1) + { + GTEST_LOG_(INFO) << "==========>\nAmsConfigurationUpdatedTest AMS_UpdateConfiguration_1400 start"; + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", MAIN_ABILITY, KIT_BUNDLE_NAME, params); + // start first ability + ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << "\nStartAbility ====>> " << eCode; + + g_tempDataStr = "OnStartOnActive"; + EXPECT_EQ(TestWaitCompleted(event, "OnStartOnActive", MAIN_ABILITY_CODE), 0); + + DummyConfiguration mDummyConfiguration("orientation#locale"); + g_abilityMs->UpdateConfiguration(mDummyConfiguration); + g_abilityMs->UpdateConfiguration(mDummyConfiguration); + + g_tempDataStr = "UpdatedUpdated"; + EXPECT_EQ(TestWaitCompleted(event, "UpdatedUpdated", MAIN_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + GTEST_LOG_(INFO) << "\nAmsConfigurationUpdatedTest AMS_UpdateConfiguration_1400 end=========<"; + } + +} // namespace + diff --git a/test/systemtest/common/ams/ams_data_ability_test/BUILD.gn b/test/systemtest/common/ams/ams_data_ability_test/BUILD.gn old mode 100644 new mode 100755 index 1688797f5e..c3b3641afa --- a/test/systemtest/common/ams/ams_data_ability_test/BUILD.gn +++ b/test/systemtest/common/ams/ams_data_ability_test/BUILD.gn @@ -22,6 +22,7 @@ ohos_systemtest("ams_data_ability_test") { include_dirs = [ "//foundation/distributedschedule/safwk/services/safwk/include", "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/include", + "//third_party/jsoncpp/include", ] sources = [ @@ -50,6 +51,7 @@ ohos_systemtest("ams_data_ability_test") { "//foundation/distributedschedule/dmsfwk/interfaces/innerkits/uri:zuri", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", "//utils/native/base:utils", ] diff --git a/test/systemtest/common/ams/ams_dfx_test/BUILD.gn b/test/systemtest/common/ams/ams_dfx_test/BUILD.gn old mode 100644 new mode 100755 index 15748cce11..8d4f04ed0a --- a/test/systemtest/common/ams/ams_dfx_test/BUILD.gn +++ b/test/systemtest/common/ams/ams_dfx_test/BUILD.gn @@ -21,6 +21,7 @@ ohos_systemtest("ams_dfx_test") { "//foundation/distributedschedule/safwk/services/safwk/include", "${appexecfwk_path}/test/resource/amssystemtestability/abilitySrc/common", "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/include", + "//third_party/jsoncpp/include", ] sources = [ @@ -47,6 +48,7 @@ ohos_systemtest("ams_dfx_test") { "${appexecfwk_path}/interfaces/innerkits/libeventhandler:libeventhandler", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", "//utils/native/base:utils", ] diff --git a/test/systemtest/common/ams/ams_dfx_test/ams_dfx_test.cpp b/test/systemtest/common/ams/ams_dfx_test/ams_dfx_test.cpp index 64cba34fe8..c52314ce50 100644 --- a/test/systemtest/common/ams/ams_dfx_test/ams_dfx_test.cpp +++ b/test/systemtest/common/ams/ams_dfx_test/ams_dfx_test.cpp @@ -66,9 +66,9 @@ static const std::string abilityStateOnInactive = ":OnInactive"; static const std::string abilityStateOnBackground = ":OnBackground"; static const std::string abilityStateOnForeground = ":OnForeground"; static const std::string abilityStateOnNewWant = ":OnNewWant"; -static const std::string g_abilityStateOnCommand = ":OnCommand"; -static const std::string g_abilityStateOnConnect = ":OnConnect"; -static const std::string g_abilityStateOnDisconnect = ":OnDisconnect"; +static const std::string abilityStateOnCommand = ":OnCommand"; +static const std::string abilityStateOnConnect = ":OnConnect"; +static const std::string abilityStateOnDisconnect = ":OnDisconnect"; static const int abilityStateCountOne = 1; static const int abilityStateCountTwo = 2; enum AbilityState_Test { @@ -114,9 +114,6 @@ public: const AbilityState_Test &midState = AbilityState_Test::ALLSUM, const std::string &args = (DUMP_STACK + " 1")); void ExpectAbilityNumInStack(const std::string &abilityName, int abilityNum); void ExpectServiceAbilityNumInStack(const std::string &abilityName, int abilityNum); - void GetFreeMem(const std::string &cmd, std::string &result); - std::string RemoveSurplusSpaces(const std::string &src); - std::vector Split(std::string str, const std::string &delim); class AppEventSubscriber : public CommonEventSubscriber { public: explicit AppEventSubscriber(const CommonEventSubscribeInfo &sp) : CommonEventSubscriber(sp) @@ -167,13 +164,11 @@ public: static sptr abilityMs_; static STtools::Event event_; static std::shared_ptr subscriber_; - static int *memTestValue_; }; sptr AmsDFXTest::appMs_ = nullptr; sptr AmsDFXTest::abilityMs_ = nullptr; STtools::Event AmsDFXTest::event_ = STtools::Event(); -int *AmsDFXTest::memTestValue_ = nullptr; std::shared_ptr AmsDFXTest::subscriber_ = nullptr; size_t AmsDFXTest::AbilityConnectCallback::onAbilityConnectDoneCount = 0; int AmsDFXTest::AbilityConnectCallback::resultConnectCode = 0; @@ -209,9 +204,6 @@ void AmsDFXTest::SetUp(void) void AmsDFXTest::TearDown(void) { GTEST_LOG_(INFO) << "void AmsDFXTest::TearDown(void)"; - if (memTestValue_) { - delete[] memTestValue_; - } std::vector bundleNames = GetBundleNames(bundleNameBase, bundleNameSuffix); STAbilityUtil::UninstallBundle(bundleNames); @@ -263,6 +255,10 @@ void AmsDFXTest::CheckAbilityStateByName(const std::string &abilityName, const s EXPECT_NE(pos, result.end()); MTDumpUtil::GetInstance()->GetAll("State", info, result); EXPECT_TRUE(pos < result.end()); + if (pos == result.end()) { + HILOG_ERROR("pos == result.end()"); + return; + } // ability state if (midState != "") { bool compareResult = ((*pos == state) || (*pos == midState)); @@ -330,53 +326,6 @@ void AmsDFXTest::AppEventSubscriber::OnReceiveEvent(const CommonEventData &data) } } -void AmsDFXTest::GetFreeMem(const std::string &cmd, std::string &result) -{ - result.clear(); - int MAX_SIZE = 1024; - char buf_ps[MAX_SIZE]; - FILE *ptr; - string command = "free " + cmd + "| grep Mem:"; - if (!command.empty() && (ptr = popen(command.c_str(), "r")) != nullptr) { - while (fgets(buf_ps, MAX_SIZE, ptr) != nullptr) { - result.append(buf_ps); - } - pclose(ptr); - ptr = nullptr; - } -} - -std::string AmsDFXTest::RemoveSurplusSpaces(const std::string &src) -{ - std::string result = ""; - for (int i = 0; src[i] != '\0'; i++) { - if (src[i] != ' ') - result.append(1, src[i]); - else if (src[i + 1] != ' ') - result.append(1, src[i]); - } - return result; -} - -std::vector AmsDFXTest::Split(std::string str, const std::string &delim) -{ - std::vector splitString; - while (str.size()) { - size_t index = str.find(delim); - if (index != std::string::npos) { - splitString.push_back(str.substr(0, index)); - str = str.substr(index + delim.size()); - if (str.size() == 0) { - splitString.push_back(str); - } - } else { - splitString.push_back(str); - str = ""; - } - } - return splitString; -} - /* * @tc.number : AMS_DFX_0100 * @tc.name : Lifecycle switch timeout. @@ -645,7 +594,7 @@ HWTEST_F(AmsDFXTest, AMS_DFX_1000, TestSize.Level1) { GTEST_LOG_(INFO) << "AmsDFXTest AMS_DFX_1000 start"; std::string bundleName = bundleNameBase + "DFX"; - std::string abilityName = abilityNameBase + "DFXA1"; + std::string abilityName = "AmsDfxStServiceAbilityA1"; MAP_STR_STR params; Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); @@ -679,7 +628,7 @@ HWTEST_F(AmsDFXTest, AMS_DFX_1100, TestSize.Level1) { GTEST_LOG_(INFO) << "AmsDFXTest AMS_DFX_1100 start"; std::string bundleName = bundleNameBase + "DFX"; - std::string abilityName = abilityNameBase + "DFXA2"; + std::string abilityName = "AmsDfxStServiceAbilityA2"; MAP_STR_STR params; Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); diff --git a/test/systemtest/common/ams/ams_kit_test/BUILD.gn b/test/systemtest/common/ams/ams_kit_test/BUILD.gn old mode 100644 new mode 100755 index 0758fd398b..9a3ebe5509 --- a/test/systemtest/common/ams/ams_kit_test/BUILD.gn +++ b/test/systemtest/common/ams/ams_kit_test/BUILD.gn @@ -22,6 +22,7 @@ ohos_systemtest("ams_kit_test") { "//foundation/distributedschedule/safwk/services/safwk/include", "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/include", "//base/notification/ces_standard/test/systemtest/common/resource", + "//third_party/jsoncpp/include", ] sources = [ "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/src/event.cpp", @@ -46,6 +47,7 @@ ohos_systemtest("ams_kit_test") { "${appexecfwk_path}/interfaces/innerkits/libeventhandler:libeventhandler", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", "//utils/native/base:utils", ] external_deps = [ @@ -63,6 +65,7 @@ ohos_systemtest("ams_kit_service_ability_test") { "//foundation/distributedschedule/safwk/services/safwk/include", "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/include", "//base/notification/ces_standard/test/systemtest/common/resource", + "//third_party/jsoncpp/include", ] sources = [ "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/src/event.cpp", @@ -87,6 +90,7 @@ ohos_systemtest("ams_kit_service_ability_test") { "${appexecfwk_path}/interfaces/innerkits/libeventhandler:libeventhandler", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", "//utils/native/base:utils", ] external_deps = [ @@ -104,6 +108,7 @@ ohos_systemtest("ams_kit_data_test") { "//foundation/distributedschedule/safwk/services/safwk/include", "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/include", "//base/notification/ces_standard/test/systemtest/common/resource", + "//third_party/jsoncpp/include", ] sources = [ "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/src/event.cpp", @@ -131,6 +136,7 @@ ohos_systemtest("ams_kit_data_test") { "//foundation/distributedschedule/dmsfwk/interfaces/innerkits/uri:zuri", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", "//utils/native/base:utils", ] external_deps = [ @@ -149,6 +155,7 @@ ohos_systemtest("ams_kit_a_test") { "//foundation/distributedschedule/safwk/services/safwk/include", "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/include", "//base/notification/ces_standard/test/systemtest/common/resource", + "//third_party/jsoncpp/include", ] sources = [ "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/src/event.cpp", @@ -174,6 +181,7 @@ ohos_systemtest("ams_kit_a_test") { "//foundation/distributedschedule/dmsfwk/interfaces/innerkits/uri:zuri", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", "//utils/native/base:utils", ] external_deps = [ @@ -192,6 +200,7 @@ ohos_systemtest("ams_kit_want_test") { "//foundation/distributedschedule/safwk/services/safwk/include", "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/include", "//base/notification/ces_standard/test/systemtest/common/resource", + "//third_party/jsoncpp/include", ] sources = [ "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/src/event.cpp", @@ -216,6 +225,7 @@ ohos_systemtest("ams_kit_want_test") { "${appexecfwk_path}/interfaces/innerkits/libeventhandler:libeventhandler", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", "//utils/native/base:utils", ] external_deps = [ @@ -234,6 +244,7 @@ ohos_systemtest("ams_kit_skills_test") { "//foundation/distributedschedule/safwk/services/safwk/include", "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/include", "//base/notification/ces_standard/test/systemtest/common/resource", + "//third_party/jsoncpp/include", ] sources = [ "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/src/event.cpp", @@ -258,6 +269,7 @@ ohos_systemtest("ams_kit_skills_test") { "${appexecfwk_path}/interfaces/innerkits/libeventhandler:libeventhandler", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", "//utils/native/base:utils", ] external_deps = [ @@ -276,6 +288,7 @@ ohos_systemtest("ams_kit_lifecycle_test") { "//foundation/distributedschedule/safwk/services/safwk/include", "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/include", "//base/notification/ces_standard/test/systemtest/common/resource", + "//third_party/jsoncpp/include", ] sources = [ "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/src/event.cpp", @@ -300,6 +313,7 @@ ohos_systemtest("ams_kit_lifecycle_test") { "${appexecfwk_path}/interfaces/innerkits/libeventhandler:libeventhandler", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", "//utils/native/base:utils", ] external_deps = [ @@ -318,6 +332,7 @@ ohos_systemtest("ams_kit_processinfo_test") { "//foundation/distributedschedule/safwk/services/safwk/include", "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/include", "//base/notification/ces_standard/test/systemtest/common/resource", + "//third_party/jsoncpp/include", ] sources = [ "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/src/event.cpp", @@ -342,6 +357,7 @@ ohos_systemtest("ams_kit_processinfo_test") { "${appexecfwk_path}/interfaces/innerkits/libeventhandler:libeventhandler", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", "//utils/native/base:utils", ] external_deps = [ diff --git a/test/systemtest/common/ams/ams_missionstack_test/BUILD.gn b/test/systemtest/common/ams/ams_missionstack_test/BUILD.gn new file mode 100644 index 0000000000..3b493d5a55 --- /dev/null +++ b/test/systemtest/common/ams/ams_missionstack_test/BUILD.gn @@ -0,0 +1,69 @@ +# Copyright (c) 2021 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/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/ams" + +ohos_systemtest("ams_missionstack_test") { + module_out_path = module_output_path + + include_dirs = [ + "${appexecfwk_path}/test/resource/amssystemtestability/abilitySrc/common/", + "//foundation/distributedschedule/safwk/services/safwk/include", + "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/include", + ] + + sources = [ + "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/src/event.cpp", + "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/src/module_test_dump_util.cpp", + "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/src/stoperator.cpp", + "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/src/system_test_ability_util.cpp", + "ams_missionstack_test.cpp", + ] + + configs = [ + "${aafwk_path}/services/abilitymgr:abilityms_config", + "${appexecfwk_path}/services/appmgr:appmgr_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${aafwk_path}/frameworks/kits/ability/native:dummy_classes", + "${aafwk_path}/interfaces/innerkits/want:want", + "${aafwk_path}/services/abilitymgr:abilityms", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${appexecfwk_path}/interfaces/innerkits/libeventhandler:libeventhandler", + "//foundation/distributedschedule/dmsfwk/interfaces/innerkits/uri:zuri", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + ] + + external_deps = [ + "ces_standard:cesfwk_core", + "ces_standard:cesfwk_innerkits", + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("systemtest") { + testonly = true + + deps = [ ":ams_missionstack_test" ] +} diff --git a/test/systemtest/common/ams/ams_missionstack_test/ams_missionstack_test.cpp b/test/systemtest/common/ams/ams_missionstack_test/ams_missionstack_test.cpp new file mode 100644 index 0000000000..9ffac8ca81 --- /dev/null +++ b/test/systemtest/common/ams/ams_missionstack_test/ams_missionstack_test.cpp @@ -0,0 +1,850 @@ +/* + * Copyright (c) 2021 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 +// #include +#include +//#include +//#include +//#include +//#include + +#include "ability_append_test_info.h" +// #include "ability_lifecycle.h" +// #include "ability_lifecycle_executor.h" +// #include "ability_manager_errors.h" +// #include "ability_manager_service.h" +// #include "app_mgr_service.h" +#include "common_event.h" +#include "common_event_manager.h" +//#include "event.h" +#include "hilog_wrapper.h" +// #include "module_test_dump_util.h" +// #include "sa_mgr_client.h" +// #include "semaphore_ex.h" +// #include "skills.h" +#include "stoperator.h" +//#include "system_ability_definition.h" +#include "system_test_ability_util.h" +//#include "uri.h" +namespace { +using namespace OHOS; +using namespace OHOS::AAFwk; +using namespace OHOS::AppExecFwk; +using namespace OHOS::EventFwk; +//using namespace OHOS::MTUtil; +using namespace OHOS::STtools; +using namespace OHOS::STABUtil; +using namespace testing::ext; + +using MAP_STR_STR = std::map; +static const string KIT_BUNDLE_NAME = "com.ohos.amsst.MissionStack"; +static const string KIT_HAP_NAME = "amsMissionStackTest"; +static const string KIT_BUNDLE_NAME_SUBSIDIARY = "com.ohos.amsst.MissionStackSubsidiary"; +static const string KIT_HAP_NAME_SUBSIDIARY = "amsMissionStackTestSubsidiary"; +static const string MAIN_ABILITY_NAME = "MainAbility"; +static const string SECOND_ABILITY_NAME = "SecondAbility"; +static const string THIRD_ABILITY_NAME = "ThirdAbility"; +static constexpr int WAIT_TIME = 1; +static constexpr int WAIT_LAUNCHER_TIME = 5; + + +static string g_eventMessage = ""; +class AmsMissionStackTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + + static void Reinstall(const std::string &hapName, const std::string &bundleName); + void ResetSystem() const; + static bool SubscribeEvent(); + static int TestWaitCompleted(Event &event, const std::string &eventName, const int code, const int timeout = 10); + static void TestCompleted(Event &event, const std::string &eventName, const int code); + + class AppEventSubscriber : public CommonEventSubscriber { + public: + explicit AppEventSubscriber(const CommonEventSubscribeInfo &sp) : CommonEventSubscriber(sp){}; + virtual void OnReceiveEvent(const CommonEventData &data) override; + ~AppEventSubscriber(){}; + }; + + static sptr g_abilityMs; + static Event event; +}; + +Event AmsMissionStackTest::event = Event(); +sptr AmsMissionStackTest::g_abilityMs = nullptr; + +void AmsMissionStackTest::AppEventSubscriber::OnReceiveEvent(const CommonEventData &data) +{ + GTEST_LOG_(INFO) << "OnReceiveEvent: event=" << data.GetWant().GetAction(); + GTEST_LOG_(INFO) << "OnReceiveEvent: data=" << data.GetData(); + GTEST_LOG_(INFO) << "OnReceiveEvent: code=" << data.GetCode(); + if (data.GetWant().GetAction() == g_EVENT_RESP_MAIN_LIFECYCLE || + data.GetWant().GetAction() == g_EVENT_RESP_SECOND_LIFECYCLE || + data.GetWant().GetAction() == g_EVENT_RESP_THIRD_LIFECYCLE || + data.GetWant().GetAction() == g_EVENT_RESP_MAIN_LIFECYCLE_SUBSIDIARY || + data.GetWant().GetAction() == g_EVENT_RESP_SECOND_LIFECYCLE_SUBSIDIARY + ) { + TestCompleted(event, data.GetData(), data.GetCode()); + } else if (data.GetWant().GetAction() == g_EVENT_RESP_MAIN || + data.GetWant().GetAction() == g_EVENT_RESP_SECOND || + data.GetWant().GetAction() == g_EVENT_RESP_THIRD || + data.GetWant().GetAction() == g_EVENT_RESP_MAIN_SUBSIDIARY || + data.GetWant().GetAction() == g_EVENT_RESP_SECOND_SUBSIDIARY + ) { + g_eventMessage = data.GetData(); + TestCompleted(event, data.GetWant().GetAction(), data.GetCode()); + GTEST_LOG_(INFO) << "OnReceiveEvent: g_eventMessage=" << data.GetData(); + } +} + +int AmsMissionStackTest::TestWaitCompleted( + Event &event, const std::string &eventName, const int code, const int timeout) +{ + GTEST_LOG_(INFO) << "TestWaitCompleted : " << eventName << " " << code; + return STAbilityUtil::WaitCompleted(event, eventName, code, timeout); +} + +void AmsMissionStackTest::TestCompleted(Event &event, const std::string &eventName, const int code) +{ + GTEST_LOG_(INFO) << "TestCompleted : " << eventName << " " << code; + return STAbilityUtil::Completed(event, eventName, code); +} + +void AmsMissionStackTest::SetUpTestCase(void) +{ + if (!SubscribeEvent()) { + GTEST_LOG_(INFO) << "SubscribeEvent error"; + } +} + +void AmsMissionStackTest::TearDownTestCase(void) +{} + +static int CODE_ = 0; +void AmsMissionStackTest::SetUp(void) +{ + STAbilityUtil::Install(KIT_HAP_NAME); + STAbilityUtil::CleanMsg(event); + CODE_++; + sleep(WAIT_LAUNCHER_TIME); +} + +void AmsMissionStackTest::TearDown(void) +{ + STAbilityUtil::Uninstall(KIT_BUNDLE_NAME); + STAbilityUtil::CleanMsg(event); +} + +bool AmsMissionStackTest::SubscribeEvent() +{ + std::vector eventList = { + g_EVENT_RESP_MAIN_LIFECYCLE, + g_EVENT_RESP_SECOND_LIFECYCLE, + g_EVENT_RESP_THIRD_LIFECYCLE, + g_EVENT_RESP_MAIN, + g_EVENT_RESP_SECOND, + g_EVENT_RESP_THIRD, + + g_EVENT_RESP_MAIN_SUBSIDIARY, + g_EVENT_RESP_MAIN_LIFECYCLE_SUBSIDIARY, + + g_EVENT_RESP_SECOND_SUBSIDIARY, + g_EVENT_RESP_SECOND_LIFECYCLE_SUBSIDIARY, + }; + MatchingSkills matchingSkills; + for (const auto &e : eventList) { + matchingSkills.AddEvent(e); + } + CommonEventSubscribeInfo subscribeInfo(matchingSkills); + subscribeInfo.SetPriority(1); + auto subscriber = std::make_shared(subscribeInfo); + return CommonEventManager::SubscribeCommonEvent(subscriber); +} + +void AmsMissionStackTest::Reinstall(const std::string &hapName, const std::string &bundleName) +{ + STAbilityUtil::Uninstall(bundleName); + STAbilityUtil::Install(hapName); +} + + +/** + * @tc.number : FWK_MissionStack_0100 + * @tc.name : test LockMission in ability_context.h + * @tc.desc : Verify that the result of LockMission function is correct. + */ +HWTEST_F(AmsMissionStackTest, FWK_MissionStack_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_0100 start"; + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", MAIN_ABILITY_NAME, KIT_BUNDLE_NAME, params); + // start first ability + ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << eCode; + + EXPECT_EQ(TestWaitCompleted(event, "OnStart", MAIN_ABILITY_CODE), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnActive", MAIN_ABILITY_CODE), 0); + STAbilityUtil::CleanMsg(event); + STAbilityUtil::PublishEvent( + g_EVENT_REQU_MAIN, CODE_, "MissionStack_" + std::to_string((int)MissionStackApi::LockMission) + "_0"); + EXPECT_EQ(TestWaitCompleted(event, g_EVENT_RESP_MAIN, CODE_), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnBackground", MAIN_ABILITY_CODE), 0); + + EXPECT_EQ(TestWaitCompleted(event, "OnStart", SECOND_ABILITY_CODE), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnActive", SECOND_ABILITY_CODE), 0); + STAbilityUtil::CleanMsg(event); + STAbilityUtil::PublishEvent( + g_EVENT_REQU_SECOND, CODE_, "MissionStack_" + std::to_string((int)MissionStackApi::LockMission) + "_0"); + EXPECT_EQ(TestWaitCompleted(event, g_EVENT_RESP_SECOND, CODE_), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnStop", SECOND_ABILITY_CODE), 0); + + EXPECT_EQ(TestWaitCompleted(event, "OnActive", MAIN_ABILITY_CODE), 0); + + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_0100 end"; +} + +/** + * @tc.number : FWK_MissionStack_0200 + * @tc.name : test LockMission in ability_context.h + * @tc.desc : Verify that the result of LockMission function is correct. + */ +HWTEST_F(AmsMissionStackTest, FWK_MissionStack_0200, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_0200 start"; + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", MAIN_ABILITY_NAME, KIT_BUNDLE_NAME, params); + // start first ability + ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << eCode; + + EXPECT_EQ(TestWaitCompleted(event, "OnStart", MAIN_ABILITY_CODE), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnActive", MAIN_ABILITY_CODE), 0); + STAbilityUtil::CleanMsg(event); + STAbilityUtil::PublishEvent( + g_EVENT_REQU_MAIN, CODE_, "MissionStack_" + std::to_string((int)MissionStackApi::LockMission) + "_1"); + EXPECT_EQ(TestWaitCompleted(event, g_EVENT_RESP_MAIN, CODE_), 0); + + EXPECT_NE(TestWaitCompleted(event, "OnBackground", MAIN_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_0200 end"; +} + +/** + * @tc.number : FWK_MissionStack_0300 + * @tc.name : test LockMission in ability_context.h + * @tc.desc : Verify that the result of LockMission function is correct. + */ +HWTEST_F(AmsMissionStackTest, FWK_MissionStack_0300, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_0300 start"; + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", MAIN_ABILITY_NAME, KIT_BUNDLE_NAME, params); + // start first ability + ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << eCode; + + EXPECT_EQ(TestWaitCompleted(event, "OnStart", MAIN_ABILITY_CODE), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnActive", MAIN_ABILITY_CODE), 0); + STAbilityUtil::CleanMsg(event); + STAbilityUtil::PublishEvent( + g_EVENT_REQU_MAIN, CODE_, "MissionStack_" + std::to_string((int)MissionStackApi::LockMission) + "_2"); + EXPECT_EQ(TestWaitCompleted(event, g_EVENT_RESP_MAIN, CODE_), 0); + + Want wantEntity; + wantEntity.AddEntity(Want::FLAG_HOME_INTENT_FROM_SYSTEM); + STAbilityUtil::StartAbility(wantEntity, g_abilityMs); + + EXPECT_NE(TestWaitCompleted(event, "OnBackground", MAIN_ABILITY_CODE), 0); + + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_0300 end"; +} + +/** + * @tc.number : FWK_MissionStack_0400 + * @tc.name : + * @tc.desc : + */ +HWTEST_F(AmsMissionStackTest, FWK_MissionStack_0400, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_0400 start"; + //GTEST_LOG_(INFO) << "需要使用JS环境测试"; + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_0400 end"; +} + +/** + * @tc.number : FWK_MissionStack_0500 + * @tc.name : test LockMission in ability_context.h + * @tc.desc : Verify that the result of LockMission function is correct. + */ +HWTEST_F(AmsMissionStackTest, FWK_MissionStack_0500, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_0500 start"; + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", THIRD_ABILITY_NAME, KIT_BUNDLE_NAME, params); + // start third ability + ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << eCode; + + EXPECT_EQ(TestWaitCompleted(event, "OnStart", THIRD_ABILITY_CODE), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnActive", THIRD_ABILITY_CODE), 0); + STAbilityUtil::CleanMsg(event); + STAbilityUtil::PublishEvent( + g_EVENT_REQU_THIRD, CODE_, "MissionStack_" + std::to_string((int)MissionStackApi::LockMission) + "_4"); + EXPECT_EQ(TestWaitCompleted(event, g_EVENT_RESP_THIRD, CODE_), 0); + + EXPECT_NE(TestWaitCompleted(event, "OnStart", SECOND_ABILITY_CODE), 0); + + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_0500 end"; +} + +/** + * @tc.number : FWK_MissionStack_0600 + * @tc.name : test LockMission in ability_context.h + * @tc.desc : Verify that the result of LockMission function is correct. + */ +HWTEST_F(AmsMissionStackTest, FWK_MissionStack_0600, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_0600 start"; + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", MAIN_ABILITY_NAME, KIT_BUNDLE_NAME, params); + // start third ability + ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << eCode; + + EXPECT_EQ(TestWaitCompleted(event, "OnStart", MAIN_ABILITY_CODE), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnActive", MAIN_ABILITY_CODE), 0); + STAbilityUtil::CleanMsg(event); + STAbilityUtil::PublishEvent( + g_EVENT_REQU_MAIN, CODE_, "MissionStack_" + std::to_string((int)MissionStackApi::LockMission) + "_5"); + EXPECT_EQ(TestWaitCompleted(event, g_EVENT_RESP_MAIN, CODE_), 0); + + EXPECT_NE(TestWaitCompleted(event, "OnStart", THIRD_ABILITY_CODE), 0); + + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_0600 end"; +} + +/** + * @tc.number : FWK_MissionStack_0700 + * @tc.name : test LockMission in ability_context.h + * @tc.desc : Verify that the result of LockMission function is correct. + */ +HWTEST_F(AmsMissionStackTest, FWK_MissionStack_0700, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_0700 start"; + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", MAIN_ABILITY_NAME, KIT_BUNDLE_NAME, params); + // start first ability + ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << eCode; + + EXPECT_EQ(TestWaitCompleted(event, "OnStart", MAIN_ABILITY_CODE), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnActive", MAIN_ABILITY_CODE), 0); + STAbilityUtil::CleanMsg(event); + STAbilityUtil::PublishEvent( + g_EVENT_REQU_MAIN, CODE_, "MissionStack_" + std::to_string((int)MissionStackApi::LockMission) + "_6"); + EXPECT_EQ(TestWaitCompleted(event, g_EVENT_RESP_MAIN, CODE_), 0); + + Want wantEntity; + wantEntity.AddEntity(Want::FLAG_HOME_INTENT_FROM_SYSTEM); + STAbilityUtil::StartAbility(wantEntity, g_abilityMs); + + EXPECT_EQ(TestWaitCompleted(event, "OnBackground", MAIN_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_0700 end"; +} + +/** + * @tc.number : FWK_MissionStack_0800 + * @tc.name : + * @tc.desc : + */ +HWTEST_F(AmsMissionStackTest, FWK_MissionStack_0800, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_0800 start"; + //GTEST_LOG_(INFO) << "需要使用JS环境测试"; + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_0800 end"; +} + +/** + * @tc.number : FWK_MissionStack_0900 + * @tc.name : test LockMission in ability_context.h + * @tc.desc : Verify that the result of LockMission function is correct. + */ +HWTEST_F(AmsMissionStackTest, FWK_MissionStack_0900, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_0900 start"; + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", MAIN_ABILITY_NAME, KIT_BUNDLE_NAME, params); + // start first ability + ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << eCode; + + EXPECT_EQ(TestWaitCompleted(event, "OnStart", MAIN_ABILITY_CODE), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnActive", MAIN_ABILITY_CODE), 0); + STAbilityUtil::CleanMsg(event); + STAbilityUtil::PublishEvent( + g_EVENT_REQU_MAIN, CODE_, "MissionStack_" + std::to_string((int)MissionStackApi::LockMission) + "_8"); + EXPECT_EQ(TestWaitCompleted(event, g_EVENT_RESP_MAIN, CODE_), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnBackground", MAIN_ABILITY_CODE), 0); + + EXPECT_EQ(TestWaitCompleted(event, "OnStart", SECOND_ABILITY_CODE), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnActive", SECOND_ABILITY_CODE), 0); + STAbilityUtil::CleanMsg(event); + STAbilityUtil::PublishEvent( + g_EVENT_REQU_SECOND, CODE_, "MissionStack_" + std::to_string((int)MissionStackApi::LockMission) + "_8"); + EXPECT_EQ(TestWaitCompleted(event, g_EVENT_RESP_SECOND, CODE_), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnStop", SECOND_ABILITY_CODE), 0); + + EXPECT_EQ(TestWaitCompleted(event, "OnActive", MAIN_ABILITY_CODE), 0); + + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_0900 end"; +} + +/** + * @tc.number : FWK_MissionStack_1000 + * @tc.name : test LockMission in ability_context.h + * @tc.desc : Verify that the result of LockMission function is correct. + */ +HWTEST_F(AmsMissionStackTest, FWK_MissionStack_1000, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_1000 start"; + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", MAIN_ABILITY_NAME, KIT_BUNDLE_NAME, params); + // start first ability + ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << eCode; + + EXPECT_EQ(TestWaitCompleted(event, "OnStart", MAIN_ABILITY_CODE), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnActive", MAIN_ABILITY_CODE), 0); + STAbilityUtil::CleanMsg(event); + STAbilityUtil::PublishEvent( + g_EVENT_REQU_MAIN, CODE_, "MissionStack_" + std::to_string((int)MissionStackApi::LockMission) + "_9"); + EXPECT_EQ(TestWaitCompleted(event, g_EVENT_RESP_MAIN, CODE_), 0); + string appInfo = g_eventMessage; + + GTEST_LOG_(INFO) << "id=" << appInfo; + //EXPECT_EQ(appInfo, "1"); + + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_1000 end"; +} + +/** + * @tc.number : FWK_MissionStack_1100 + * @tc.name : + * @tc.desc : + */ +HWTEST_F(AmsMissionStackTest, FWK_MissionStack_1100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_1100 start"; + //GTEST_LOG_(INFO) << "需要使用JS环境测试"; + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_1100 end"; +} + +/** + * @tc.number : FWK_MissionStack_1200 + * @tc.name : test MoveMissionToEnd in ability_context.h + * @tc.desc : Verify that the result of MoveMissionToEnd function is correct. + */ +HWTEST_F(AmsMissionStackTest, FWK_MissionStack_1200, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_1200 start"; + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", MAIN_ABILITY_NAME, KIT_BUNDLE_NAME, params); + // start first ability + ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << eCode; + + EXPECT_EQ(TestWaitCompleted(event, "OnStart", MAIN_ABILITY_CODE), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnActive", MAIN_ABILITY_CODE), 0); + STAbilityUtil::CleanMsg(event); + STAbilityUtil::PublishEvent( + g_EVENT_REQU_MAIN, CODE_, "MissionStack_" + std::to_string((int)MissionStackApi::LockMission) + "_11"); + EXPECT_EQ(TestWaitCompleted(event, g_EVENT_RESP_MAIN, CODE_), 0); + + EXPECT_EQ(TestWaitCompleted(event, "OnBackground", MAIN_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_1200 end"; +} + +/** + * @tc.number : FWK_MissionStack_1300 + * @tc.name : test MoveMissionToEnd in ability_context.h + * @tc.desc : Verify that the result of MoveMissionToEnd function is correct. + */ +HWTEST_F(AmsMissionStackTest, FWK_MissionStack_1300, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_1300 start"; + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", MAIN_ABILITY_NAME, KIT_BUNDLE_NAME, params); + // start first ability + ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << eCode; + + EXPECT_EQ(TestWaitCompleted(event, "OnStart", MAIN_ABILITY_CODE), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnActive", MAIN_ABILITY_CODE), 0); + STAbilityUtil::CleanMsg(event); + STAbilityUtil::PublishEvent( + g_EVENT_REQU_MAIN, CODE_, "MissionStack_" + std::to_string((int)MissionStackApi::LockMission) + "_12"); + EXPECT_EQ(TestWaitCompleted(event, g_EVENT_RESP_MAIN, CODE_), 0); + + EXPECT_EQ(TestWaitCompleted(event, "OnBackground", MAIN_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_1300 end"; +} + +/** + * @tc.number : FWK_MissionStack_1400 + * @tc.name : test MoveMissionToEnd in ability_context.h + * @tc.desc : Verify that the result of MoveMissionToEnd function is correct. + */ +HWTEST_F(AmsMissionStackTest, FWK_MissionStack_1400, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_1400 start"; + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", MAIN_ABILITY_NAME, KIT_BUNDLE_NAME, params); + // start first ability + ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << eCode; + + EXPECT_EQ(TestWaitCompleted(event, "OnStart", MAIN_ABILITY_CODE), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnActive", MAIN_ABILITY_CODE), 0); + STAbilityUtil::CleanMsg(event); + STAbilityUtil::PublishEvent( + g_EVENT_REQU_MAIN, CODE_, "MissionStack_" + std::to_string((int)MissionStackApi::LockMission) + "_13"); + EXPECT_EQ(TestWaitCompleted(event, g_EVENT_RESP_MAIN, CODE_), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnBackground", MAIN_ABILITY_CODE), 0); + + EXPECT_EQ(TestWaitCompleted(event, "OnStart", SECOND_ABILITY_CODE), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnActive", SECOND_ABILITY_CODE), 0); + STAbilityUtil::CleanMsg(event); + STAbilityUtil::PublishEvent( + g_EVENT_REQU_SECOND, CODE_, "MissionStack_" + std::to_string((int)MissionStackApi::LockMission) + "_13"); + EXPECT_EQ(TestWaitCompleted(event, g_EVENT_RESP_SECOND, CODE_), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnBackground", SECOND_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_1400 end"; +} + +/** + * @tc.number : FWK_MissionStack_1500 + * @tc.name : test MoveMissionToEnd in ability_context.h + * @tc.desc : Verify that the result of MoveMissionToEnd function is correct. + */ +HWTEST_F(AmsMissionStackTest, FWK_MissionStack_1500, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_1500 start"; + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", MAIN_ABILITY_NAME, KIT_BUNDLE_NAME, params); + // start first ability + ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << eCode; + + EXPECT_EQ(TestWaitCompleted(event, "OnStart", MAIN_ABILITY_CODE), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnActive", MAIN_ABILITY_CODE), 0); + STAbilityUtil::CleanMsg(event); + STAbilityUtil::PublishEvent( + g_EVENT_REQU_MAIN, CODE_, "MissionStack_" + std::to_string((int)MissionStackApi::LockMission) + "_14"); + EXPECT_EQ(TestWaitCompleted(event, g_EVENT_RESP_MAIN, CODE_), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnBackground", MAIN_ABILITY_CODE), 0); + + EXPECT_EQ(TestWaitCompleted(event, "OnStart", SECOND_ABILITY_CODE), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnActive", SECOND_ABILITY_CODE), 0); + STAbilityUtil::CleanMsg(event); + STAbilityUtil::PublishEvent( + g_EVENT_REQU_SECOND, CODE_, "MissionStack_" + std::to_string((int)MissionStackApi::LockMission) + "_14"); + EXPECT_EQ(TestWaitCompleted(event, g_EVENT_RESP_SECOND, CODE_), 0); + EXPECT_NE(TestWaitCompleted(event, "OnBackground", SECOND_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_1500 end"; +} + +/** + * @tc.number : FWK_MissionStack_1600 + * @tc.name : test MoveMissionToEnd in ability_context.h + * @tc.desc : Verify that the result of MoveMissionToEnd function is correct. + */ +HWTEST_F(AmsMissionStackTest, FWK_MissionStack_1600, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_1600 start"; + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", MAIN_ABILITY_NAME, KIT_BUNDLE_NAME, params); + // start first ability + ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << eCode; + + EXPECT_EQ(TestWaitCompleted(event, "OnStart", MAIN_ABILITY_CODE), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnActive", MAIN_ABILITY_CODE), 0); + Want wantEntity; + wantEntity.AddEntity(Want::FLAG_HOME_INTENT_FROM_SYSTEM); + STAbilityUtil::StartAbility(wantEntity, g_abilityMs); + sleep(WAIT_LAUNCHER_TIME); + STAbilityUtil::CleanMsg(event); + + STAbilityUtil::Install(KIT_HAP_NAME_SUBSIDIARY); + STAbilityUtil::CleanMsg(event); + sleep(WAIT_LAUNCHER_TIME); + want = STAbilityUtil::MakeWant("device", MAIN_ABILITY_NAME, KIT_BUNDLE_NAME_SUBSIDIARY, params); + // start first ability + eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) <<"SUBSIDIARY:StartAbility:eCode=" << eCode; + + EXPECT_EQ(TestWaitCompleted(event, "OnStart", MAIN_ABILITY_CODE_SUBSIDIARY), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnActive", MAIN_ABILITY_CODE_SUBSIDIARY), 0); + + STAbilityUtil::PublishEvent( + g_EVENT_REQU_MAIN_SUBSIDIARY, CODE_, "MissionStack_" + std::to_string((int)MissionStackApi::LockMission) + "_0"); + EXPECT_EQ(TestWaitCompleted(event, g_EVENT_RESP_MAIN_SUBSIDIARY, CODE_), 0); + + EXPECT_EQ(TestWaitCompleted(event, "OnBackground", MAIN_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnBackground", MAIN_ABILITY_CODE_SUBSIDIARY,WAIT_LAUNCHER_TIME), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnStart", SECOND_ABILITY_CODE_SUBSIDIARY), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnActive", SECOND_ABILITY_CODE_SUBSIDIARY), 0); + + STAbilityUtil::PublishEvent( + g_EVENT_REQU_MAIN_SUBSIDIARY, CODE_, "MissionStack_" + std::to_string((int)MissionStackApi::LockMission) + "_1"); + EXPECT_EQ(TestWaitCompleted(event, g_EVENT_RESP_MAIN_SUBSIDIARY, CODE_), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnBackground", SECOND_ABILITY_CODE_SUBSIDIARY,WAIT_LAUNCHER_TIME), 0); + + STAbilityUtil::Uninstall(KIT_BUNDLE_NAME_SUBSIDIARY); + STAbilityUtil::CleanMsg(event); + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_1600 end"; +} + +// /** +// * @tc.number : FWK_MissionStack_1700 +// * @tc.name : test MoveMissionToEnd in ability_context.h +// * @tc.desc : Verify that the result of MoveMissionToEnd function is correct. +// */ +HWTEST_F(AmsMissionStackTest, FWK_MissionStack_1700, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_1700 start"; + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", MAIN_ABILITY_NAME, KIT_BUNDLE_NAME, params); + // start first ability + ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << eCode; + + EXPECT_EQ(TestWaitCompleted(event, "OnStart", MAIN_ABILITY_CODE), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnActive", MAIN_ABILITY_CODE), 0); + Want wantEntity; + wantEntity.AddEntity(Want::FLAG_HOME_INTENT_FROM_SYSTEM); + STAbilityUtil::StartAbility(wantEntity, g_abilityMs); + sleep(WAIT_LAUNCHER_TIME); + STAbilityUtil::CleanMsg(event); + + STAbilityUtil::Install(KIT_HAP_NAME_SUBSIDIARY); + STAbilityUtil::CleanMsg(event); + sleep(WAIT_LAUNCHER_TIME); + want = STAbilityUtil::MakeWant("device", MAIN_ABILITY_NAME, KIT_BUNDLE_NAME_SUBSIDIARY, params); + // start first ability + eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) <<"SUBSIDIARY:StartAbility:eCode=" << eCode; + + EXPECT_EQ(TestWaitCompleted(event, "OnStart", MAIN_ABILITY_CODE_SUBSIDIARY), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnActive", MAIN_ABILITY_CODE_SUBSIDIARY), 0); + + STAbilityUtil::PublishEvent( + g_EVENT_REQU_MAIN_SUBSIDIARY, CODE_, "MissionStack_" + std::to_string((int)MissionStackApi::LockMission) + "_0"); + EXPECT_EQ(TestWaitCompleted(event, g_EVENT_RESP_MAIN_SUBSIDIARY, CODE_), 0); + + EXPECT_EQ(TestWaitCompleted(event, "OnBackground", MAIN_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnBackground", MAIN_ABILITY_CODE_SUBSIDIARY,WAIT_LAUNCHER_TIME), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnStart", SECOND_ABILITY_CODE_SUBSIDIARY), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnActive", SECOND_ABILITY_CODE_SUBSIDIARY), 0); + + STAbilityUtil::PublishEvent( + g_EVENT_REQU_MAIN_SUBSIDIARY, CODE_, "MissionStack_" + std::to_string((int)MissionStackApi::LockMission) + "_2"); + EXPECT_EQ(TestWaitCompleted(event, g_EVENT_RESP_MAIN_SUBSIDIARY, CODE_), 0); + EXPECT_NE(TestWaitCompleted(event, "OnBackground", SECOND_ABILITY_CODE_SUBSIDIARY,WAIT_LAUNCHER_TIME), 0); + + STAbilityUtil::Uninstall(KIT_BUNDLE_NAME_SUBSIDIARY); + STAbilityUtil::CleanMsg(event); + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_1700 end"; +} + +/** + * @tc.number : FWK_MissionStack_1800 + * @tc.name : test MoveMissionToEnd in ability_context.h + * @tc.desc : Verify that the result of MoveMissionToEnd function is correct. + */ +HWTEST_F(AmsMissionStackTest, FWK_MissionStack_1800, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_1800 start"; + MAP_STR_STR params; + Want want = STAbilityUtil::MakeWant("device", MAIN_ABILITY_NAME, KIT_BUNDLE_NAME, params); + // start first ability + ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); + GTEST_LOG_(INFO) << eCode; + + EXPECT_EQ(TestWaitCompleted(event, "OnStart", MAIN_ABILITY_CODE), 0); + EXPECT_EQ(TestWaitCompleted(event, "OnActive", MAIN_ABILITY_CODE), 0); + STAbilityUtil::CleanMsg(event); + STAbilityUtil::PublishEvent( + g_EVENT_REQU_MAIN, CODE_, "MissionStack_" + std::to_string((int)MissionStackApi::LockMission) + "_17"); + EXPECT_EQ(TestWaitCompleted(event, g_EVENT_RESP_MAIN, CODE_), 0); + + EXPECT_NE(TestWaitCompleted(event, "OnBackground", MAIN_ABILITY_CODE,WAIT_LAUNCHER_TIME), 0); + + GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_MissionStack_1800 end"; +} + +// /** +// * @tc.number : FWK_SaveAbilityState_0100 +// * @tc.name : +// * @tc.desc : +// */ +// HWTEST_F(AmsMissionStackTest, FWK_SaveAbilityState_0100, Function | MediumTest | Level1) +// { +// GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_SaveAbilityState_0100 start"; +// MAP_STR_STR params; +// Want want = STAbilityUtil::MakeWant("device", MAIN_ABILITY_NAME, KIT_BUNDLE_NAME, params); +// // start first ability +// ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); +// GTEST_LOG_(INFO) << eCode; + +// EXPECT_EQ(TestWaitCompleted(event, "OnStart", MAIN_ABILITY_CODE), 0); +// EXPECT_EQ(TestWaitCompleted(event, "OnActive", MAIN_ABILITY_CODE), 0); + +// Want wantEntity; +// wantEntity.AddEntity(Want::FLAG_HOME_INTENT_FROM_SYSTEM); +// STAbilityUtil::StartAbility(wantEntity, g_abilityMs); + +// EXPECT_NE(TestWaitCompleted(event, "OnSaveAbilityState", MAIN_ABILITY_CODE), 0); +// GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_SaveAbilityState_0100 end"; +// } + +// /** +// * @tc.number : FWK_SaveAbilityState_0200 +// * @tc.name : +// * @tc.desc : +// */ +// HWTEST_F(AmsMissionStackTest, FWK_SaveAbilityState_0200, Function | MediumTest | Level1) +// { +// GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_SaveAbilityState_0200 start"; + +// // 该case需要屏幕翻转事件 +// GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_SaveAbilityState_0200 end"; +// } + +// /** +// * @tc.number : FWK_SaveAbilityState_0300 +// * @tc.name : +// * @tc.desc : +// */ +// HWTEST_F(AmsMissionStackTest, FWK_SaveAbilityState_0300, Function | MediumTest | Level1) +// { +// GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_SaveAbilityState_0300 start"; +// MAP_STR_STR params; +// Want want = STAbilityUtil::MakeWant("device", MAIN_ABILITY_NAME, KIT_BUNDLE_NAME, params); +// // start first ability +// ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); +// GTEST_LOG_(INFO) << eCode; + +// EXPECT_EQ(TestWaitCompleted(event, "OnStart", MAIN_ABILITY_CODE), 0); +// EXPECT_EQ(TestWaitCompleted(event, "OnActive", MAIN_ABILITY_CODE), 0); +// STAbilityUtil::CleanMsg(event); +// STAbilityUtil::PublishEvent( +// g_EVENT_REQU_MAIN, CODE_, "AbilityState_" + std::to_string((int)TestAbilityState::OnSaveAbilityState) + "_2"); +// EXPECT_EQ(TestWaitCompleted(event, g_EVENT_RESP_MAIN, CODE_), 0); + +// EXPECT_EQ(TestWaitCompleted(event, "OnStart", SECOND_ABILITY_CODE), 0); +// EXPECT_EQ(TestWaitCompleted(event, "OnActive", SECOND_ABILITY_CODE), 0); + +// EXPECT_NE(TestWaitCompleted(event, "OnSaveAbilityState", MAIN_ABILITY_CODE), 0); +// GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_SaveAbilityState_0300 end"; +// } + +// /** +// * @tc.number : FWK_RestoreAbilityState_0100 +// * @tc.name : +// * @tc.desc : +// */ +// HWTEST_F(AmsMissionStackTest, FWK_RestoreAbilityState_0100, Function | MediumTest | Level1) +// { +// GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_RestoreAbilityState_0100 start"; + +// MAP_STR_STR params; +// Want want = STAbilityUtil::MakeWant("device", THIRD_ABILITY_NAME, KIT_BUNDLE_NAME, params); +// // start first ability +// ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); +// GTEST_LOG_(INFO) << eCode; + +// EXPECT_EQ(TestWaitCompleted(event, "OnStart", THIRD_ABILITY_CODE), 0); +// EXPECT_EQ(TestWaitCompleted(event, "OnActive", THIRD_ABILITY_CODE), 0); + +// Want wantEntity; +// wantEntity.AddEntity(Want::FLAG_HOME_INTENT_FROM_SYSTEM); +// STAbilityUtil::StartAbility(wantEntity, g_abilityMs); + +// sleep(WAIT_LAUNCHER_TIME); +// eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); +// GTEST_LOG_(INFO) << eCode; +// EXPECT_EQ(TestWaitCompleted(event, "OnActive", THIRD_ABILITY_CODE), 0); + +// EXPECT_NE(TestWaitCompleted(event, "OnRestoreAbilityState", THIRD_ABILITY_CODE), 0); + +// GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_RestoreAbilityState_0100 end"; +// } + +// /** +// * @tc.number : FWK_RestoreAbilityState_0200 +// * @tc.name : +// * @tc.desc : +// */ +// HWTEST_F(AmsMissionStackTest, FWK_RestoreAbilityState_0200, Function | MediumTest | Level1) +// { +// GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_RestoreAbilityState_0200 start"; +// // 该case需要屏幕翻转事件 +// GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_RestoreAbilityState_0200 end"; +// } + +// /** +// * @tc.number : FWK_RestoreAbilityState_0300 +// * @tc.name : +// * @tc.desc : +// */ +// HWTEST_F(AmsMissionStackTest, FWK_RestoreAbilityState_0300, Function | MediumTest | Level1) +// { +// GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_RestoreAbilityState_0300 start"; +// MAP_STR_STR params; +// Want want = STAbilityUtil::MakeWant("device", MAIN_ABILITY_NAME, KIT_BUNDLE_NAME, params); +// // start first ability +// ErrCode eCode = STAbilityUtil::StartAbility(want, g_abilityMs, WAIT_TIME); +// GTEST_LOG_(INFO) << eCode; + +// EXPECT_EQ(TestWaitCompleted(event, "OnStart", MAIN_ABILITY_CODE), 0); +// EXPECT_EQ(TestWaitCompleted(event, "OnActive", MAIN_ABILITY_CODE), 0); +// STAbilityUtil::CleanMsg(event); +// STAbilityUtil::PublishEvent( +// g_EVENT_REQU_MAIN, CODE_, "AbilityState_" + std::to_string((int)TestAbilityState::OnRestoreAbilityState) + "_2"); +// EXPECT_EQ(TestWaitCompleted(event, g_EVENT_RESP_MAIN, CODE_), 0); + +// EXPECT_EQ(TestWaitCompleted(event, "OnStart", SECOND_ABILITY_CODE), 0); +// EXPECT_EQ(TestWaitCompleted(event, "OnActive", SECOND_ABILITY_CODE), 0); +// STAbilityUtil::PublishEvent( +// g_EVENT_REQU_SECOND, CODE_, "AbilityState_" + std::to_string((int)TestAbilityState::OnRestoreAbilityState) + "_2"); +// EXPECT_EQ(TestWaitCompleted(event, g_EVENT_RESP_SECOND, CODE_), 0); +// EXPECT_EQ(TestWaitCompleted(event, "OnStop", SECOND_ABILITY_CODE), 0); + +// EXPECT_NE(TestWaitCompleted(event, "OnRestoreAbilityState", MAIN_ABILITY_CODE), 0); + +// GTEST_LOG_(INFO) << "AmsMissionStackTest FWK_RestoreAbilityState_0300 end"; +// } + +} // namespace diff --git a/test/systemtest/common/ams/ams_page_ability_test/BUILD.gn b/test/systemtest/common/ams/ams_page_ability_test/BUILD.gn old mode 100644 new mode 100755 index b5db3c8266..17487b999a --- a/test/systemtest/common/ams/ams_page_ability_test/BUILD.gn +++ b/test/systemtest/common/ams/ams_page_ability_test/BUILD.gn @@ -20,6 +20,7 @@ ohos_systemtest("ams_page_ability_test") { include_dirs = [ "//foundation/distributedschedule/safwk/services/safwk/include", "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/include", + "//third_party/jsoncpp/include", ] sources = [ @@ -46,6 +47,7 @@ ohos_systemtest("ams_page_ability_test") { "${appexecfwk_path}/interfaces/innerkits/libeventhandler:libeventhandler", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", "//utils/native/base:utils", ] diff --git a/test/systemtest/common/ams/ams_page_ability_test/ams_page_ability_test.cpp b/test/systemtest/common/ams/ams_page_ability_test/ams_page_ability_test.cpp index d4f7ea3be8..74be16d880 100644 --- a/test/systemtest/common/ams/ams_page_ability_test/ams_page_ability_test.cpp +++ b/test/systemtest/common/ams/ams_page_ability_test/ams_page_ability_test.cpp @@ -97,7 +97,6 @@ static const std::string abilityStateOnForeground = ":OnForeground"; static const std::string abilityStateOnNewWant = ":OnNewWant"; static const int abilityStateCountOne = 1; static const int abilityStateCountTwo = 2; -static const int abilityStateCountThree = 3; } // namespace class AmsPageAbilityTest : public testing::Test { @@ -111,7 +110,7 @@ public: static void CheckAbilityStateByName(const std::string &abilityName, const std::vector &info, const std::string &state, const std::string &midState); void ExpectAbilityCurrentState(const std::string &abilityName, const AbilityState_Test ¤tState, - const AbilityState_Test &midState = AbilityState_Test::ALLSUM, const std::string &args = (DUMP_STACK + " 1")); + const AbilityState_Test &midState = AbilityState_Test::ALLSUM, const std::string &args = DUMP_ALL); void ExpectAbilityNumInStack(const std::string &abilityName, int abilityNum); void ClearSystem(); void ShowDump(); @@ -206,6 +205,10 @@ void AmsPageAbilityTest::CheckAbilityStateByName(const std::string &abilityName, EXPECT_NE(pos, result.end()); MTDumpUtil::GetInstance()->GetAll("State", info, result); EXPECT_TRUE(pos < result.end()); + if (pos == result.end()) { + HILOG_ERROR("pos == result.end()"); + return; + } // ability state if (midState != "") { bool compareResult = ((*pos == state) || (*pos == midState)); @@ -1163,12 +1166,13 @@ HWTEST_F(AmsPageAbilityTest, AMS_Page_Ability_2200, Function | MediumTest | Leve std::string bundleName = bundleNameBase + "A"; std::string abilityName = abilityNameBase + "A1"; MAP_STR_STR params; - params["shouldReturn"] = abilityName; Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); STAbilityUtil::StartAbility(want, abilityMs_); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountOne), 0); + int eventCode = 0; + STAbilityUtil::PublishEvent(terminatePageAbility, eventCode, abilityName); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnInactive, abilityStateCountOne), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnBackground, abilityStateCountOne), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStop, abilityStateCountOne), 0); @@ -1198,7 +1202,6 @@ HWTEST_F(AmsPageAbilityTest, AMS_Page_Ability_2300, Function | MediumTest | Leve MAP_STR_STR params; params["targetBundle"] = bundleName; params["targetAbility"] = abilityName2; - params["shouldReturn"] = abilityName2; Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); STAbilityUtil::StartAbility(want, abilityMs_); @@ -1206,6 +1209,8 @@ HWTEST_F(AmsPageAbilityTest, AMS_Page_Ability_2300, Function | MediumTest | Leve EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountOne), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnInactive, abilityStateCountOne), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnActive, abilityStateCountOne), 0); + int eventCode = 0; + STAbilityUtil::PublishEvent(terminatePageAbility, eventCode, abilityName2); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnInactive, abilityStateCountOne), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountTwo), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnBackground, abilityStateCountOne), 0); @@ -1239,7 +1244,6 @@ HWTEST_F(AmsPageAbilityTest, AMS_Page_Ability_2400, Function | MediumTest | Leve MAP_STR_STR params; params["targetBundle"] = bundleName2; params["targetAbility"] = abilityName2; - params["shouldReturn"] = abilityName2; Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); STAbilityUtil::StartAbility(want, abilityMs_); @@ -1247,6 +1251,8 @@ HWTEST_F(AmsPageAbilityTest, AMS_Page_Ability_2400, Function | MediumTest | Leve EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountOne), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnInactive, abilityStateCountOne), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnActive, abilityStateCountOne), 0); + int eventCode = 0; + STAbilityUtil::PublishEvent(terminatePageAbility, eventCode, abilityName2); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnInactive, abilityStateCountOne), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountTwo), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnBackground, abilityStateCountOne), 0); @@ -1279,16 +1285,17 @@ HWTEST_F(AmsPageAbilityTest, AMS_Page_Ability_2500, Function | MediumTest | Leve MAP_STR_STR params; params["targetBundle"] = bundleName; params["targetAbility"] = abilityName2; - params["shouldReturn"] = abilityName; Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); STAbilityUtil::StartAbility(want, abilityMs_); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountOne), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnInactive, abilityStateCountOne), 0); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnActive, abilityStateCountOne), 0); + int eventCode = 0; + STAbilityUtil::PublishEvent(terminatePageAbility, eventCode, abilityName); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnBackground, abilityStateCountOne), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStop, abilityStateCountOne), 0); - EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnActive, abilityStateCountOne), 0); // ability "A1" not in stack(terminated) ExpectAbilityNumInStack(abilityName, 0); @@ -1413,9 +1420,8 @@ HWTEST_F(AmsPageAbilityTest, AMS_Page_Ability_2700, Function | MediumTest | Leve EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName3 + abilityStateOnBackground, abilityStateCountOne), 0); // Back Ability I4(singletop) - params["shouldReturn"] = abilityName4; - want = STAbilityUtil::MakeWant("device", abilityName4, bundleName1, params); - STAbilityUtil::StartAbility(want, abilityMs_); + int eventCode = 0; + STAbilityUtil::PublishEvent(terminatePageAbility, eventCode, abilityName4); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnActive, abilityStateCountTwo), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName4 + abilityStateOnStop, abilityStateCountOne), 0); @@ -1424,9 +1430,7 @@ HWTEST_F(AmsPageAbilityTest, AMS_Page_Ability_2700, Function | MediumTest | Leve ExpectAbilityCurrentState(abilityName2, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); ExpectAbilityCurrentState(abilityName3, AbilityState_Test::BACKGROUND, AbilityState_Test::ACTIVATING); // Back Ability I2(singletop) - params["shouldReturn"] = abilityName2; - want = STAbilityUtil::MakeWant("device", abilityName2, bundleName1, params); - STAbilityUtil::StartAbility(want, abilityMs_); + STAbilityUtil::PublishEvent(terminatePageAbility, eventCode, abilityName2); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName1 + abilityStateOnActive, abilityStateCountTwo), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStop, abilityStateCountOne), 0); @@ -1435,9 +1439,7 @@ HWTEST_F(AmsPageAbilityTest, AMS_Page_Ability_2700, Function | MediumTest | Leve ExpectAbilityCurrentState(abilityName1, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); ExpectAbilityCurrentState(abilityName3, AbilityState_Test::BACKGROUND, AbilityState_Test::MOVING_BACKGROUND); // Back Ability I1(singletop) - params["shouldReturn"] = abilityName1; - want = STAbilityUtil::MakeWant("device", abilityName1, bundleName1, params); - STAbilityUtil::StartAbility(want, abilityMs_); + STAbilityUtil::PublishEvent(terminatePageAbility, eventCode, abilityName1); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName1 + abilityStateOnStop, abilityStateCountOne), 0); ExpectAbilityCurrentState(launcherAbilityName, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING, DUMP_ALL); @@ -1577,9 +1579,8 @@ HWTEST_F(AmsPageAbilityTest, AMS_Page_Ability_2900, Function | MediumTest | Leve ExpectAbilityNumInStack(abilityName3, 1); ExpectAbilityCurrentState(abilityName3, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); // Start Ability I3(SI) Back - params["shouldReturn"] = abilityName3; - want = STAbilityUtil::MakeWant("device", abilityName3, bundleName1, params); - STAbilityUtil::StartAbility(want, abilityMs_); + int eventCode = 0; + STAbilityUtil::PublishEvent(terminatePageAbility, eventCode, abilityName3); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName5 + abilityStateOnActive, abilityStateCountTwo), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName3 + abilityStateOnStop, abilityStateCountOne), 0); @@ -1728,20 +1729,16 @@ HWTEST_F(AmsPageAbilityTest, AMS_Page_Ability_3100, Function | MediumTest | Leve ExpectAbilityCurrentState(abilityName3, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); // I3(SI) back - params["shouldReturn"] = abilityName3; - want = STAbilityUtil::MakeWant("device", abilityName3, bundleName1, params); - STAbilityUtil::StartAbility(want, abilityMs_); + int eventCode = 0; + STAbilityUtil::PublishEvent(terminatePageAbility, eventCode, abilityName3); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName5 + abilityStateOnActive, abilityStateCountTwo), 0); // Ability I3 back, B1(singletop) State Is ACTIVE ExpectAbilityCurrentState(abilityName5, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); // B1(singletop) back - params["shouldReturn"] = abilityName5; - want = STAbilityUtil::MakeWant("device", abilityName5, bundleName2, params); - STAbilityUtil::StartAbility(want, abilityMs_); + STAbilityUtil::PublishEvent(terminatePageAbility, eventCode, abilityName5); - EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName5 + abilityStateOnActive, abilityStateCountThree), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName5 + abilityStateOnBackground, abilityStateCountTwo), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName5 + abilityStateOnStop, abilityStateCountOne), 0); @@ -1955,9 +1952,8 @@ HWTEST_F(AmsPageAbilityTest, AMS_Page_Ability_3700, Function | MediumTest | Leve ExpectAbilityCurrentState(abilityName1, AbilityState_Test::BACKGROUND, AbilityState_Test::MOVING_BACKGROUND); // Back Ability G2(singletop) - params["shouldReturn"] = abilityName2; - want = STAbilityUtil::MakeWant("device", abilityName2, bundleName1, params); - STAbilityUtil::StartAbility(want, abilityMs_); + int eventCode = 0; + STAbilityUtil::PublishEvent(terminatePageAbility, eventCode, abilityName2); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName1 + abilityStateOnActive, abilityStateCountTwo), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnBackground, abilityStateCountOne), 0); @@ -2000,9 +1996,8 @@ HWTEST_F(AmsPageAbilityTest, AMS_Page_Ability_3800, Function | MediumTest | Leve ExpectAbilityCurrentState(abilityName1, AbilityState_Test::BACKGROUND, AbilityState_Test::MOVING_BACKGROUND); // Back Ability H1(singletop) - params["shouldReturn"] = abilityName2; - want = STAbilityUtil::MakeWant("device", abilityName2, bundleName2, params); - STAbilityUtil::StartAbility(want, abilityMs_); + int eventCode = 0; + STAbilityUtil::PublishEvent(terminatePageAbility, eventCode, abilityName2); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName1 + abilityStateOnActive, abilityStateCountTwo), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnBackground, abilityStateCountOne), 0); @@ -2080,11 +2075,8 @@ HWTEST_F(AmsPageAbilityTest, AMS_Page_Ability_4000, Function | MediumTest | Leve ExpectAbilityCurrentState(abilityName1, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); // Terminate Ability G1(SI) - params["shouldReturn"] = abilityName1; - want = STAbilityUtil::MakeWant("device", abilityName1, bundleName1, params); - STAbilityUtil::StartAbility(want, abilityMs_); - EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName1 + abilityStateOnNewWant, abilityStateCountOne), 0); - EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName1 + abilityStateOnActive, abilityStateCountTwo), 0); + int eventCode = 0; + STAbilityUtil::PublishEvent(terminatePageAbility, eventCode, abilityName1); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName1 + abilityStateOnBackground, abilityStateCountOne), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName1 + abilityStateOnStop, abilityStateCountOne), 0); @@ -2127,9 +2119,8 @@ HWTEST_F(AmsPageAbilityTest, AMS_Page_Ability_4100, Function | MediumTest | Leve ExpectAbilityCurrentState(abilityName2, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); ExpectAbilityCurrentState(abilityName1, AbilityState_Test::BACKGROUND, AbilityState_Test::MOVING_BACKGROUND); // terminate Ability G2(singletop) - params["shouldReturn"] = abilityName2; - want = STAbilityUtil::MakeWant("device", abilityName2, bundleName1, params); - STAbilityUtil::StartAbility(want, abilityMs_); + int eventCode = 0; + STAbilityUtil::PublishEvent(terminatePageAbility, eventCode, abilityName2); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName1 + abilityStateOnActive, abilityStateCountTwo), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnBackground, abilityStateCountOne), 0); @@ -2176,11 +2167,9 @@ HWTEST_F(AmsPageAbilityTest, AMS_Page_Ability_4200, Function | MediumTest | Leve ExpectAbilityCurrentState(abilityName1, AbilityState_Test::BACKGROUND, AbilityState_Test::MOVING_BACKGROUND); // terminate Ability H1(singletop) - params["shouldReturn"] = abilityName2; - want = STAbilityUtil::MakeWant("device", abilityName2, bundleName2, params); - STAbilityUtil::StartAbility(want, abilityMs_); - EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnActive, abilityStateCountTwo), 0); - EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnNewWant, abilityStateCountOne), 0); + int eventCode = 0; + STAbilityUtil::PublishEvent(terminatePageAbility, eventCode, abilityName2); + EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnBackground, abilityStateCountOne), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName1 + abilityStateOnActive, abilityStateCountTwo), 0); @@ -2236,15 +2225,11 @@ HWTEST_F(AmsPageAbilityTest, AMS_Page_Ability_4300, Function | MediumTest | Leve ExpectAbilityCurrentState(abilityName1, AbilityState_Test::BACKGROUND, AbilityState_Test::MOVING_BACKGROUND); // terminate Ability G1(SI) - params["shouldReturn"] = abilityName1; - want = STAbilityUtil::MakeWant("device", abilityName1, bundleName1, params); - STAbilityUtil::StartAbility(want, abilityMs_); + int eventCode = 0; + STAbilityUtil::PublishEvent(terminatePageAbility, eventCode, abilityName1); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName1 + abilityStateOnStop, abilityStateCountOne), 0); - // terminate Ability G1(SI), Launcher Ability State Is ACTIVE - ExpectAbilityCurrentState(launcherAbilityName, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING, DUMP_ALL); - GTEST_LOG_(INFO) << "AmsPageAbilityTest AMS_Page_Ability_4300 end"; } @@ -2768,7 +2753,6 @@ HWTEST_F(AmsPageAbilityTest, AMS_Page_Ability_5500, Function | MediumTest | Leve STAbilityUtil::StopAbility(terminatePageAbility, 0, abilityName2); - EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnForeground, abilityStateCountOne), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountTwo), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnBackground, abilityStateCountOne), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStop, abilityStateCountOne), 0); @@ -2777,6 +2761,7 @@ HWTEST_F(AmsPageAbilityTest, AMS_Page_Ability_5500, Function | MediumTest | Leve ExpectAbilityCurrentState(abilityName, AbilityState_Test::ACTIVE, AbilityState_Test::ACTIVATING); // ability "N2" not in stack ExpectAbilityNumInStack(abilityName2, 0); + ShowDump(); GTEST_LOG_(INFO) << "AmsPageAbilityTest AMS_Page_Ability_5500 end"; } @@ -2884,11 +2869,12 @@ HWTEST_F(AmsPageAbilityTest, AMS_Page_Ability_5800, Function | MediumTest | Leve std::string bundleName = bundleNameBase + "N"; std::string abilityName = abilityNameBase + "N1"; MAP_STR_STR params; - params["shouldReturn"] = abilityName; Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); STAbilityUtil::StartAbility(want, abilityMs_); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountOne), 0); + int eventCode = 0; + STAbilityUtil::PublishEvent(terminatePageAbility, eventCode, abilityName); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnInactive, abilityStateCountOne), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnBackground, abilityStateCountOne), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStop, abilityStateCountOne), 0); @@ -2918,7 +2904,6 @@ HWTEST_F(AmsPageAbilityTest, AMS_Page_Ability_5900, Function | MediumTest | Leve MAP_STR_STR params; params["targetBundle"] = bundleName; params["targetAbility"] = abilityName2; - params["shouldReturn"] = abilityName2; Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); STAbilityUtil::StartAbility(want, abilityMs_); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); @@ -2926,6 +2911,8 @@ HWTEST_F(AmsPageAbilityTest, AMS_Page_Ability_5900, Function | MediumTest | Leve EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnInactive, abilityStateCountOne), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStart, abilityStateCountOne), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnActive, abilityStateCountOne), 0); + int eventCode = 0; + STAbilityUtil::PublishEvent(terminatePageAbility, eventCode, abilityName2); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnBackground, abilityStateCountOne), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStop, abilityStateCountOne), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountTwo), 0); @@ -2958,7 +2945,6 @@ HWTEST_F(AmsPageAbilityTest, AMS_Page_Ability_6000, Function | MediumTest | Leve MAP_STR_STR params; params["targetBundle"] = bundleName2; params["targetAbility"] = abilityName2; - params["shouldReturn"] = abilityName2; Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); STAbilityUtil::StartAbility(want, abilityMs_); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); @@ -2966,6 +2952,8 @@ HWTEST_F(AmsPageAbilityTest, AMS_Page_Ability_6000, Function | MediumTest | Leve EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnInactive, abilityStateCountOne), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStart, abilityStateCountOne), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnActive, abilityStateCountOne), 0); + int eventCode = 0; + STAbilityUtil::PublishEvent(terminatePageAbility, eventCode, abilityName2); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnBackground, abilityStateCountOne), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStop, abilityStateCountOne), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnActive, abilityStateCountTwo), 0); @@ -2997,7 +2985,6 @@ HWTEST_F(AmsPageAbilityTest, AMS_Page_Ability_6100, Function | MediumTest | Leve MAP_STR_STR params; params["targetBundle"] = bundleName; params["targetAbility"] = abilityName2; - params["shouldReturn"] = abilityName; Want want = STAbilityUtil::MakeWant("device", abilityName, bundleName, params); STAbilityUtil::StartAbility(want, abilityMs_); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStart, abilityStateCountOne), 0); @@ -3006,6 +2993,8 @@ HWTEST_F(AmsPageAbilityTest, AMS_Page_Ability_6100, Function | MediumTest | Leve EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStart, abilityStateCountOne), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnActive, abilityStateCountOne), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnBackground, abilityStateCountOne), 0); + int eventCode = 0; + STAbilityUtil::PublishEvent(terminatePageAbility, eventCode, abilityName); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName + abilityStateOnStop, abilityStateCountOne), 0); // ability "N1" not in stack(terminated) @@ -3393,14 +3382,18 @@ HWTEST_F(AmsPageAbilityTest, AMS_Page_Ability_6700, Function | MediumTest | Leve STAbilityUtil::PublishEvent(terminatePageAbility, eventCode, abilityName5); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName3 + abilityStateOnActive, abilityStateCountTwo), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName5 + abilityStateOnStop, abilityStateCountOne), 0); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); STAbilityUtil::PublishEvent(terminatePageAbility, eventCode, abilityName3); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnActive, abilityStateCountTwo), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName3 + abilityStateOnStop, abilityStateCountOne), 0); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); STAbilityUtil::PublishEvent(terminatePageAbility, eventCode, abilityName2); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName1 + abilityStateOnActive, abilityStateCountTwo), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStop, abilityStateCountOne), 0); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); STAbilityUtil::PublishEvent(terminatePageAbility, eventCode, abilityName1); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName1 + abilityStateOnStop, abilityStateCountOne), 0); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); MissionStackInfo missionStackInfo; GetAllStackInfo(missionStackInfo); EXPECT_TRUE(missionStackInfo.missionRecords.size() == 0); @@ -3450,14 +3443,18 @@ HWTEST_F(AmsPageAbilityTest, AMS_Page_Ability_6800, Function | MediumTest | Leve STAbilityUtil::PublishEvent(terminatePageAbility, eventCode, abilityName5); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName3 + abilityStateOnActive, abilityStateCountTwo), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName5 + abilityStateOnStop, abilityStateCountOne), 0); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); STAbilityUtil::PublishEvent(terminatePageAbility, eventCode, abilityName3); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnActive, abilityStateCountTwo), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName3 + abilityStateOnStop, abilityStateCountOne), 0); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); STAbilityUtil::PublishEvent(terminatePageAbility, eventCode, abilityName2); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName1 + abilityStateOnActive, abilityStateCountTwo), 0); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName2 + abilityStateOnStop, abilityStateCountOne), 0); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); STAbilityUtil::PublishEvent(terminatePageAbility, eventCode, abilityName1); EXPECT_EQ(STAbilityUtil::WaitCompleted(event_, abilityName1 + abilityStateOnStop, abilityStateCountOne), 0); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); MissionStackInfo missionStackInfo; GetAllStackInfo(missionStackInfo); EXPECT_TRUE(missionStackInfo.missionRecords.size() == 0); diff --git a/test/systemtest/common/ams/ams_power_test/BUILD.gn b/test/systemtest/common/ams/ams_power_test/BUILD.gn old mode 100644 new mode 100755 index a8f782b54c..b7e7aa63e1 --- a/test/systemtest/common/ams/ams_power_test/BUILD.gn +++ b/test/systemtest/common/ams/ams_power_test/BUILD.gn @@ -21,6 +21,7 @@ ohos_systemtest("ams_power_test") { "//foundation/distributedschedule/safwk/services/safwk/include", "${appexecfwk_path}/test/resource/amssystemtestability/abilitySrc/common", "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/include", + "//third_party/jsoncpp/include", ] sources = [ @@ -47,6 +48,7 @@ ohos_systemtest("ams_power_test") { "${appexecfwk_path}/interfaces/innerkits/libeventhandler:libeventhandler", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", "//utils/native/base:utils", ] diff --git a/test/systemtest/common/ams/ams_power_test/ams_power_test.cpp b/test/systemtest/common/ams/ams_power_test/ams_power_test.cpp index 97a34cd8af..3bb00b27a4 100644 --- a/test/systemtest/common/ams/ams_power_test/ams_power_test.cpp +++ b/test/systemtest/common/ams/ams_power_test/ams_power_test.cpp @@ -119,13 +119,11 @@ public: static sptr abilityMs_; static STtools::Event event_; static std::shared_ptr subscriber_; - static int *memTestValue_; }; sptr AmsPowerTest::appMs_ = nullptr; sptr AmsPowerTest::abilityMs_ = nullptr; STtools::Event AmsPowerTest::event_ = STtools::Event(); -int *AmsPowerTest::memTestValue_ = nullptr; std::shared_ptr AmsPowerTest::subscriber_ = nullptr; void AmsPowerTest::SetUpTestCase(void) @@ -160,9 +158,6 @@ void AmsPowerTest::SetUp(void) void AmsPowerTest::TearDown(void) { GTEST_LOG_(INFO) << "void AmsPowerTest::TearDown(void)"; - if (memTestValue_) { - delete[] memTestValue_; - } STAbilityUtil::RemoveStack(1, abilityMs_, WAIT_TIME, WAIT_LAUNCHER_OK); std::vector vecBundleName; for (const auto &suffix : bundleNameSuffix) { @@ -217,6 +212,10 @@ void AmsPowerTest::CheckAbilityStateByName(const std::string &abilityName, const EXPECT_NE(pos, result.end()); MTDumpUtil::GetInstance()->GetAll("State", info, result); EXPECT_TRUE(pos < result.end()); + if (pos == result.end()) { + HILOG_ERROR("pos == result.end()"); + return; + } // ability state if (midState != "") { bool compareResult = ((*pos == state) || (*pos == midState)); diff --git a/test/systemtest/common/ams/ams_service_ability_test/BUILD.gn b/test/systemtest/common/ams/ams_service_ability_test/BUILD.gn index 082648f0e9..e293251fc1 100755 --- a/test/systemtest/common/ams/ams_service_ability_test/BUILD.gn +++ b/test/systemtest/common/ams/ams_service_ability_test/BUILD.gn @@ -22,6 +22,7 @@ ohos_systemtest("ams_service_ability_test") { include_dirs = [ "//foundation/distributedschedule/services/safwk/include", "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/include", + "//third_party/jsoncpp/include", ] sources = [ @@ -49,6 +50,7 @@ ohos_systemtest("ams_service_ability_test") { "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", "//utils/native/base:utils", ] diff --git a/test/systemtest/common/ams/ams_service_ability_test/ams_service_ability_test.cpp b/test/systemtest/common/ams/ams_service_ability_test/ams_service_ability_test.cpp index 07e3157035..2562f1e863 100644 --- a/test/systemtest/common/ams/ams_service_ability_test/ams_service_ability_test.cpp +++ b/test/systemtest/common/ams/ams_service_ability_test/ams_service_ability_test.cpp @@ -331,7 +331,7 @@ void AmsServiceAbilityTest::CheckAbilityStateByName( // ability exist EXPECT_NE(pos, result.end()); MTDumpUtil::GetInstance()->GetAll("State", info, result); - ASSERT_TRUE(pos < result.end()); + EXPECT_TRUE(pos < result.end()); // ability state EXPECT_EQ(Trim(*pos), state); } diff --git a/test/systemtest/common/ams/tool/BUILD.gn b/test/systemtest/common/ams/tool/BUILD.gn old mode 100644 new mode 100755 index b92bc15c53..f634483837 --- a/test/systemtest/common/ams/tool/BUILD.gn +++ b/test/systemtest/common/ams/tool/BUILD.gn @@ -16,6 +16,7 @@ import("//foundation/appexecfwk/standard/appexecfwk.gni") config("system_test_ability_util_config") { include_dirs = [ + "//third_party/jsoncpp/include", "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/include", "//foundation/distributedschedule/safwk/services/safwk/include", ] @@ -48,6 +49,7 @@ ohos_shared_library("system_test_ability_util_lib") { "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core:appexecfwk_core", "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler:libeventhandler", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/jsoncpp:jsoncpp", "//utils/native/base:utils", ] diff --git a/test/systemtest/common/bms/BUILD.gn b/test/systemtest/common/bms/BUILD.gn index ebf10ab58e..cc0943c851 100755 --- a/test/systemtest/common/bms/BUILD.gn +++ b/test/systemtest/common/bms/BUILD.gn @@ -9,7 +9,7 @@ # 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. +# limitations under the License. import("//build/ohos.gni") import("//foundation/appexecfwk/standard/appexecfwk.gni") @@ -72,6 +72,7 @@ group("systemtest_bms") { deps = [ "acts_bms_kit_system_test:systemtest", "bms_install_system_test:systemtest", + "bms_launcher_service_system_test:systemtest", "bms_search_system_test:systemtest", "bms_uninstall_system_test:systemtest", ] diff --git a/test/systemtest/common/bms/acts_bms_kit_system_test/acts_bms_kit_system_test.cpp b/test/systemtest/common/bms/acts_bms_kit_system_test/acts_bms_kit_system_test.cpp old mode 100755 new mode 100644 index f43c80c632..a7561ee6b6 --- a/test/systemtest/common/bms/acts_bms_kit_system_test/acts_bms_kit_system_test.cpp +++ b/test/systemtest/common/bms/acts_bms_kit_system_test/acts_bms_kit_system_test.cpp @@ -14,6 +14,7 @@ */ #include +#include #include #include @@ -31,6 +32,7 @@ using OHOS::AAFwk::Want; using namespace testing::ext; +using namespace std::chrono_literals; namespace { const std::string THIRD_BUNDLE_PATH = "/data/test/bms_bundle/"; @@ -58,6 +60,9 @@ public: virtual ~BundleStatusCallbackImpl() override; virtual void OnBundleStateChanged(const uint8_t installType, const int32_t resultCode, const std::string &resultMsg, const std::string &bundleName) override; + virtual void OnBundleAdded(const std::string &bundleName, const int userId) override{}; + virtual void OnBundleUpdated(const std::string &bundleName, const int userId) override{}; + virtual void OnBundleRemoved(const std::string &bundleName, const int userId) override{}; private: DISALLOW_COPY_AND_MOVE(BundleStatusCallbackImpl); @@ -181,7 +186,6 @@ public: const std::string &bundleName, const std::string &modulePackage, std::vector &resvec); static sptr GetBundleMgrProxy(); static sptr GetInstallerProxy(); - bool CreateFile(const std::string &path) const; void CheckBundleInfo(const uint32_t index, BundleInfo &bundleInfo) const; void CreateDir(const std::string &path) const; void CheckFileExist(const std::string &bundleName) const; @@ -225,7 +229,7 @@ void ActsBmsKitSystemTest::Install( installParam.installFlag = installFlag; installParam.userId = Constants::DEFAULT_USERID; sptr statusReceiver = (new (std::nothrow) StatusReceiverImpl()); - ASSERT_NE(statusReceiver, nullptr); + EXPECT_NE(statusReceiver, nullptr); installerProxy->Install(bundleFilePath, installParam, statusReceiver); resvec.push_back(statusReceiver->GetResultMsg()); } @@ -246,7 +250,7 @@ void ActsBmsKitSystemTest::Uninstall(const std::string &bundleName, std::vector< InstallParam installParam; installParam.userId = Constants::DEFAULT_USERID; sptr statusReceiver = (new (std::nothrow) StatusReceiverImpl()); - ASSERT_NE(statusReceiver, nullptr); + EXPECT_NE(statusReceiver, nullptr); installerProxy->Uninstall(bundleName, installParam, statusReceiver); resvec.push_back(statusReceiver->GetResultMsg()); } @@ -269,7 +273,7 @@ void ActsBmsKitSystemTest::HapUninstall( InstallParam installParam; installParam.userId = Constants::DEFAULT_USERID; sptr statusReceiver = (new (std::nothrow) StatusReceiverImpl()); - ASSERT_NE(statusReceiver, nullptr); + EXPECT_NE(statusReceiver, nullptr); installerProxy->Uninstall(bundleName, modulePackage, installParam, statusReceiver); resvec.push_back(statusReceiver->GetResultMsg()); } @@ -312,62 +316,28 @@ sptr ActsBmsKitSystemTest::GetInstallerProxy() return installerProxy; } -bool ActsBmsKitSystemTest::CreateFile(const std::string &path) const -{ - if (path.size() > PATH_MAX) { - APP_LOGE("CreateFile the length of path is too long"); - return false; - } - - std::string realPath; - realPath.reserve(PATH_MAX); - realPath.resize(PATH_MAX - 1); - - if (realpath(path.c_str(), &(realPath[0])) != nullptr) { - APP_LOGW("CreateFile-translate:%{public}s already exist path", realPath.c_str()); - return true; - } - - mode_t mode = 0666; - int fd = open(realPath.c_str(), O_RDWR | O_CREAT, mode); - if (fd == -1) { - APP_LOGE("CreateFile-open:%{public}s error", realPath.c_str()); - return false; - } - if (close(fd) != 0) { - APP_LOGW("CreateFile-close:%{public}s error", realPath.c_str()); - return false; - } - - if (access(realPath.c_str(), F_OK) != 0) { - APP_LOGE("CreateFile-checkFile:%{public}s not exist", realPath.c_str()); - return false; - } - return true; -} - void ActsBmsKitSystemTest::CheckFileExist(const std::string &bundleName) const { int bundleDataExist = access((BUNDLE_DATA_ROOT_PATH + bundleName).c_str(), F_OK); - ASSERT_EQ(bundleDataExist, 0) << "the bundle data dir doesn't exist: " << bundleName; + EXPECT_EQ(bundleDataExist, 0) << "the bundle data dir doesn't exist: " << bundleName; } void ActsBmsKitSystemTest::CheckFileExist(const std::string &bundleName, const std::string &modulePackage) const { int bundleDataExist = access((BUNDLE_DATA_ROOT_PATH + bundleName + "/" + modulePackage).c_str(), F_OK); - ASSERT_EQ(bundleDataExist, 0) << "the bundle data dir doesn't exist: " << bundleName; + EXPECT_EQ(bundleDataExist, 0) << "the bundle data dir doesn't exist: " << bundleName; } void ActsBmsKitSystemTest::CheckFileNonExist(const std::string &bundleName) const { int bundleDataExist = access((BUNDLE_DATA_ROOT_PATH + bundleName).c_str(), F_OK); - ASSERT_NE(bundleDataExist, 0) << "the bundle data dir exists: " << bundleName; + EXPECT_NE(bundleDataExist, 0) << "the bundle data dir exists: " << bundleName; } void ActsBmsKitSystemTest::CheckFileNonExist(const std::string &bundleName, const std::string &modulePackage) const { int bundleDataExist = access((BUNDLE_DATA_ROOT_PATH + bundleName + "/" + modulePackage).c_str(), F_OK); - ASSERT_NE(bundleDataExist, 0) << "the bundle data dir exists: " << bundleName; + EXPECT_NE(bundleDataExist, 0) << "the bundle data dir exists: " << bundleName; } void ActsBmsKitSystemTest::CheckBundleInfo(const uint32_t index, BundleInfo &bundleInfo) const @@ -404,7 +374,7 @@ void ActsBmsKitSystemTest::CheckBundleInfo(const uint32_t index, BundleInfo &bun EXPECT_EQ(iter->bundleName, BASE_BUNDLE_NAME + std::to_string(index)); EXPECT_EQ(iter->description, ""); EXPECT_EQ(iter->label, "bmsThirdBundle_A2 Ability"); - EXPECT_EQ(iter->moduleName, "bmsThirdBundle1"); + EXPECT_EQ(iter->moduleName, "testability"); std::cout << "abilityInfo-moduleName:" << iter->moduleName << std::endl; EXPECT_EQ(iter->uri, ""); EXPECT_EQ(iter->visible, true); @@ -467,11 +437,11 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleInfo_0100, Function | MediumTest | Level Install(bundleFilePath, InstallFlag::NORMAL, resvec); CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } BundleInfo bundleInfo; bool getInfoResult = bundleMgrProxy->GetBundleInfo(appName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); @@ -480,7 +450,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleInfo_0100, Function | MediumTest | Level resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!getInfoResult) { APP_LOGI("GetBundleInfo_0100 failed - cycle count: %{public}d", i); break; @@ -513,11 +483,11 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleInfo_0200, Function | MediumTest | Level Install(bundleFilePath, InstallFlag::NORMAL, resvec); CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } BundleInfo bundleInfo; bool getInfoResult = bundleMgrProxy->GetBundleInfo(appName, BundleFlag::GET_BUNDLE_WITH_ABILITIES, bundleInfo); @@ -526,7 +496,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleInfo_0200, Function | MediumTest | Level resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!getInfoResult) { APP_LOGI("GetBundleInfo_0200 failed - cycle count: %{public}d", i); @@ -561,11 +531,11 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleInfo_0300, Function | MediumTest | Level CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } BundleInfo bundleInfo; bool getInfoResult = bundleMgrProxy->GetBundleInfo(appName, BundleFlag::GET_BUNDLE_WITH_ABILITIES, bundleInfo); @@ -574,7 +544,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleInfo_0300, Function | MediumTest | Level resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!getInfoResult) { APP_LOGI("GetBundleInfo_0300 failed - cycle count: %{public}d", i); @@ -609,11 +579,11 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleInfo_0400, Function | MediumTest | Level CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Failure[ERR_INSTALL_PARSE_NO_PROFILE]") << "Success!"; + EXPECT_EQ(installResult, "Failure[ERR_INSTALL_PARSE_NO_PROFILE]") << "Success!"; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } BundleInfo bundleInfo; bool getInfoResult = bundleMgrProxy->GetBundleInfo(appName, BundleFlag::GET_BUNDLE_WITH_ABILITIES, bundleInfo); @@ -652,11 +622,11 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleInfo_0500, Function | MediumTest | Level CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Failure[ERR_INSTALL_INVALID_HAP_NAME]"); + EXPECT_EQ(installResult, "Failure[ERR_INSTALL_INVALID_HAP_NAME]"); sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } BundleInfo bundleInfo; bool getInfoResult = bundleMgrProxy->GetBundleInfo(appName, BundleFlag::GET_BUNDLE_WITH_ABILITIES, bundleInfo); @@ -694,11 +664,11 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleInfo_0600, Function | MediumTest | Level CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } appName = BASE_BUNDLE_NAME + "e"; BundleInfo bundleInfo; @@ -708,7 +678,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleInfo_0600, Function | MediumTest | Level appName = BASE_BUNDLE_NAME + "1"; Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (getInfoResult) { APP_LOGI("GetBundleInfo_0600 failed - cycle count: %{public}d", i); @@ -742,7 +712,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleInfo_0700, Function | MediumTest | Level sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } BundleInfo bundleInfo; @@ -787,13 +757,13 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleInfo_0800, Function | MediumTest | Level Install(bundleFilePath, InstallFlag::NORMAL, resvec); CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; BundleInfo bundleInfo; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getInfoResult = bundleMgrProxy->GetBundleInfo(appName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); EXPECT_TRUE(getInfoResult); @@ -802,7 +772,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleInfo_0800, Function | MediumTest | Level resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!getInfoResult) { APP_LOGI("GetBundleInfo_0800 failed - cycle count: %{public}d", i); break; @@ -834,13 +804,13 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleInfo_0900, Function | MediumTest | Level Install(bundleFilePath, InstallFlag::NORMAL, resvec); CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; BundleInfo bundleInfo; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getInfoResult = bundleMgrProxy->GetBundleInfo(appName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); EXPECT_TRUE(getInfoResult); @@ -849,7 +819,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleInfo_0900, Function | MediumTest | Level resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!getInfoResult) { APP_LOGI("GetBundleInfo_0900 failed - cycle count: %{public}d", i); break; @@ -882,12 +852,12 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleInfos_0100, Function | MediumTest | Leve std::string hapFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle" + std::to_string(i) + ".hap"; Install(hapFilePath, InstallFlag::NORMAL, resvec); installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; } sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::vector bundleInfos; bool getInfoResult = bundleMgrProxy->GetBundleInfos(BundleFlag::GET_BUNDLE_DEFAULT, bundleInfos); @@ -906,7 +876,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleInfos_0100, Function | MediumTest | Leve std::vector resvec2; Uninstall(appName, resvec2); std::string uninstallResult = commonTool.VectorToStr(resvec2); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; } if (!getInfoResult) { APP_LOGI("GetBundleInfos_0100 failed - cycle count: %{public}d", i); @@ -936,7 +906,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleInfos_0200, Function | MediumTest | Leve sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::vector bundleInfos; @@ -955,7 +925,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleInfos_0200, Function | MediumTest | Leve break; } } - EXPECT_EQ(count, 3); + EXPECT_GE(count, 2); if (!getInfoResult) { APP_LOGI("GetBundleInfos_0200 failed - cycle count: %{public}d", i); @@ -991,12 +961,12 @@ HWTEST_F(ActsBmsKitSystemTest, GetApplicationInfo_0100, Function | MediumTest | CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } ApplicationInfo appInfo; int userId = Constants::DEFAULT_USERID; @@ -1007,7 +977,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetApplicationInfo_0100, Function | MediumTest | resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!getInfoResult) { APP_LOGI("GetApplicationInfo_0100 failed - cycle count: %{public}d", i); @@ -1042,12 +1012,12 @@ HWTEST_F(ActsBmsKitSystemTest, GetApplicationInfo_0200, Function | MediumTest | CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } ApplicationInfo appInfo; int userId = Constants::DEFAULT_USERID; @@ -1055,11 +1025,10 @@ HWTEST_F(ActsBmsKitSystemTest, GetApplicationInfo_0200, Function | MediumTest | appName, ApplicationFlag::GET_APPLICATION_INFO_WITH_PERMS, userId, appInfo); std::string permission = commonTool.VectorToStr(appInfo.permissions); EXPECT_TRUE(getInfoResult); - std::cout << permission << std::endl; resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!getInfoResult) { APP_LOGI("GetApplicationInfo_0200 failed - cycle count: %{public}d", i); @@ -1094,12 +1063,12 @@ HWTEST_F(ActsBmsKitSystemTest, GetApplicationInfo_0300, Function | MediumTest | CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } ApplicationInfo appInfo; int userId = Constants::DEFAULT_USERID; @@ -1111,7 +1080,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetApplicationInfo_0300, Function | MediumTest | appName = BASE_BUNDLE_NAME + "1"; Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (getInfoResult) { APP_LOGI("GetApplicationInfo_0300 failed - cycle count: %{public}d", i); @@ -1146,12 +1115,12 @@ HWTEST_F(ActsBmsKitSystemTest, GetApplicationInfo_0400, Function | MediumTest | CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } ApplicationInfo appInfo; int userId = Constants::DEFAULT_USERID; @@ -1159,13 +1128,10 @@ HWTEST_F(ActsBmsKitSystemTest, GetApplicationInfo_0400, Function | MediumTest | bundleMgrProxy->GetApplicationInfo(appName, ApplicationFlag::GET_BASIC_APPLICATION_INFO, userId, appInfo); EXPECT_TRUE(getInfoResult); EXPECT_EQ(appInfo.name, appName); - std::cout << appInfo.description << std::endl; - std::cout << appInfo.iconPath << std::endl; - std::cout << appInfo.supportedModes << std::endl; resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!getInfoResult) { APP_LOGI("GetApplicationInfo_0400 failed - cycle count: %{public}d", i); @@ -1196,7 +1162,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetApplicationInfo_0500, Function | MediumTest | sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } ApplicationInfo appInfo; @@ -1239,17 +1205,17 @@ HWTEST_F(ActsBmsKitSystemTest, GetApplicationInfo_0600, Function | MediumTest | CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success"); + EXPECT_EQ(uninstallResult, "Success"); sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } ApplicationInfo appInfo; int userId = -1; @@ -1289,14 +1255,14 @@ HWTEST_F(ActsBmsKitSystemTest, GetApplicationInfo_0700, Function | MediumTest | Install(bundleFilePath, InstallFlag::NORMAL, resvec); CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; ApplicationInfo appInfo; int userId = Constants::DEFAULT_USERID; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getInfoResult = bundleMgrProxy->GetApplicationInfo(appName, ApplicationFlag::GET_BASIC_APPLICATION_INFO, userId, appInfo); @@ -1306,7 +1272,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetApplicationInfo_0700, Function | MediumTest | resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!getInfoResult) { APP_LOGI("GetApplicationInfo_0700 failed - cycle count: %{public}d", i); break; @@ -1337,7 +1303,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetApplicationInfos_0100, Function | MediumTest | sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string installResult; int userId = Constants::DEFAULT_USERID; @@ -1347,7 +1313,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetApplicationInfos_0100, Function | MediumTest | std::string appName = BASE_BUNDLE_NAME + std::to_string(i - 5); Install(hapFilePath, InstallFlag::NORMAL, resvec); installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; std::vector appInfos; bool getInfoResult = @@ -1356,7 +1322,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetApplicationInfos_0100, Function | MediumTest | resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; bool isSubStrExist = false; for (auto iter = appInfos.begin(); iter != appInfos.end(); iter++) { @@ -1396,7 +1362,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetApplicationInfos_0200, Function | MediumTest | sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::vector appInfos; bool getInfoResult = @@ -1415,7 +1381,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetApplicationInfos_0200, Function | MediumTest | break; } } - EXPECT_EQ(count, 3); + EXPECT_GE(count, 2); if (!getInfoResult) { APP_LOGI("GetApplicationInfos_0200 failed - cycle count: %{public}d", i); @@ -1449,7 +1415,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleArchiveInfo_0100, Function | MediumTest sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getInfoResult = bundleMgrProxy->GetBundleArchiveInfo(hapFilePath, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); @@ -1491,7 +1457,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleArchiveInfo_0200, Function | MediumTest sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getInfoResult = bundleMgrProxy->GetBundleArchiveInfo(hapFilePath, BundleFlag::GET_BUNDLE_WITH_ABILITIES, bundleInfo); @@ -1538,7 +1504,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleArchiveInfo_0300, Function | MediumTest sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string hapFilePath = THIRD_BUNDLE_PATH + "tt.hap"; bool getInfoResult = @@ -1576,7 +1542,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleArchiveInfo_0400, Function | MediumTest sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getInfoResult = bundleMgrProxy->GetBundleArchiveInfo(hapFilePath, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); @@ -1614,7 +1580,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleArchiveInfo_0500, Function | MediumTest sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getInfoResult = bundleMgrProxy->GetBundleArchiveInfo(hapFilePath, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); @@ -1653,11 +1619,11 @@ HWTEST_F(ActsBmsKitSystemTest, GetUidByBundleName_0100, Function | MediumTest | CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } int userId = Constants::DEFAULT_USERID; int uid = bundleMgrProxy->GetUidByBundleName(bundleName, userId); @@ -1666,7 +1632,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetUidByBundleName_0100, Function | MediumTest | resvec.clear(); Uninstall(bundleName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (uid == Constants::INVALID_UID) { APP_LOGI("GetUidByBundleName_0100 failed - cycle count: %{public}d", i); @@ -1701,11 +1667,11 @@ HWTEST_F(ActsBmsKitSystemTest, GetUidByBundleName_0200, Function | MediumTest | CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } int userId = Constants::INVALID_USERID; int uid = bundleMgrProxy->GetUidByBundleName(bundleName, userId); @@ -1713,7 +1679,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetUidByBundleName_0200, Function | MediumTest | resvec.clear(); Uninstall(bundleName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (uid == Constants::INVALID_UID) { APP_LOGI("GetUidByBundleName_0200 failed - cycle count: %{public}d", i); @@ -1749,11 +1715,11 @@ HWTEST_F(ActsBmsKitSystemTest, GetUidByBundleName_0300, Function | MediumTest | CommonTool commonTool; int userId = Constants::DEFAULT_USERID; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bundleName = BASE_BUNDLE_NAME + "e"; int uid = bundleMgrProxy->GetUidByBundleName(bundleName, userId); @@ -1763,7 +1729,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetUidByBundleName_0300, Function | MediumTest | bundleName = BASE_BUNDLE_NAME + "1"; Uninstall(bundleName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (uid != Constants::INVALID_UID) { APP_LOGI("GetUidByBundleName_0300 failed - cycle count: %{public}d", i); @@ -1793,7 +1759,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetUidByBundleName_0400, Function | MediumTest | sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } int userId = Constants::DEFAULT_USERID; @@ -1833,11 +1799,11 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleNameForUid_0100, Function | MediumTest | CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } BundleInfo bundleInfo; bundleMgrProxy->GetBundleInfo(appName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); @@ -1850,7 +1816,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleNameForUid_0100, Function | MediumTest | resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!getInfoResult) { APP_LOGI("GetBundleNameForUid_0100 failed - cycle count: %{public}d", i); @@ -1879,7 +1845,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleNameForUid_0200, Function | MediumTest | sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } BundleInfo bundleInfo; @@ -1920,7 +1886,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleNameForUid_0300, Function | MediumTest | sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } int uid = Constants::INVALID_UID; std::string bundleName; @@ -1960,18 +1926,18 @@ HWTEST_F(ActsBmsKitSystemTest, GetAppType_0100, Function | MediumTest | Level1) CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string appType = bundleMgrProxy->GetAppType(appName); EXPECT_EQ(appType, "third-party"); resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (std::strcmp(appType.c_str(), "third-party") != 0) { APP_LOGI("GetAppType_0100 failed - cycle count: %{public}d", i); @@ -2003,7 +1969,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetAppType_0200, Function | MediumTest | Level1) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string appType = bundleMgrProxy->GetAppType(SYSTEM_SETTINGS_BUNDLE_NAME); EXPECT_EQ(appType, "system"); @@ -2042,18 +2008,18 @@ HWTEST_F(ActsBmsKitSystemTest, GetAppType_0300, Function | MediumTest | Level2) CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string appType = bundleMgrProxy->GetAppType(errName); EXPECT_EQ(appType, Constants::EMPTY_STRING); resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (std::strcmp(appType.c_str(), (Constants::EMPTY_STRING).c_str()) != 0) { APP_LOGI("GetAppType_0300 failed - cycle count: %{public}d", i); @@ -2088,11 +2054,11 @@ HWTEST_F(ActsBmsKitSystemTest, GetAppType_0400, Function | MediumTest | Level2) CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_NE(installResult, "Success"); + EXPECT_NE(installResult, "Success"); sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string appType = bundleMgrProxy->GetAppType(appName); EXPECT_EQ(appType, Constants::EMPTY_STRING); @@ -2130,11 +2096,11 @@ HWTEST_F(ActsBmsKitSystemTest, GetAppType_0500, Function | MediumTest | Level2) CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_NE(installResult, "Success"); + EXPECT_NE(installResult, "Success"); sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string appType = bundleMgrProxy->GetAppType(appName); EXPECT_EQ(appType, Constants::EMPTY_STRING); @@ -2173,18 +2139,18 @@ HWTEST_F(ActsBmsKitSystemTest, GetAbilityLabel_0100, Function | MediumTest | Lev CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string abilityLabel = bundleMgrProxy->GetAbilityLabel(appName, abilityName); EXPECT_NE(abilityLabel, "EMPTY_STRING"); resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (std::strcmp(abilityLabel.c_str(), "EMPTY_STRING") == 0) { APP_LOGI("GetAbilityLabel_0100 failed - cycle count: %{public}d", i); @@ -2218,7 +2184,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetAbilityLabel_0200, Function | MediumTest | Lev sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string abilityLabel = bundleMgrProxy->GetAbilityLabel(appName, abilityName); EXPECT_NE(abilityLabel, "EMPTY_STRING"); @@ -2257,11 +2223,11 @@ HWTEST_F(ActsBmsKitSystemTest, GetAbilityLabel_0300, Function | MediumTest | Lev CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string errAppName = BASE_BUNDLE_NAME + "e"; std::string abilityLabel = bundleMgrProxy->GetAbilityLabel(errAppName, abilityName); @@ -2269,7 +2235,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetAbilityLabel_0300, Function | MediumTest | Lev resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (std::strcmp(abilityLabel.c_str(), (Constants::EMPTY_STRING).c_str()) != 0) { APP_LOGI("GetAbilityLabel_0300 failed - cycle count: %{public}d", i); @@ -2305,18 +2271,18 @@ HWTEST_F(ActsBmsKitSystemTest, GetAbilityLabel_0400, Function | MediumTest | Lev CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string abilityLabel = bundleMgrProxy->GetAbilityLabel(appName, errAbilityName); EXPECT_EQ(abilityLabel, Constants::EMPTY_STRING); resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (std::strcmp(abilityLabel.c_str(), (Constants::EMPTY_STRING).c_str()) != 0) { APP_LOGI("GetAbilityLabel_0400 failed - cycle count: %{public}d", i); @@ -2352,11 +2318,11 @@ HWTEST_F(ActsBmsKitSystemTest, GetAbilityLabel_0500, Function | MediumTest | Lev CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_NE(installResult, "Success"); + EXPECT_NE(installResult, "Success"); sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string abilityLabel = bundleMgrProxy->GetAbilityLabel(appName, abilityName); EXPECT_EQ(abilityLabel, Constants::EMPTY_STRING); @@ -2395,11 +2361,11 @@ HWTEST_F(ActsBmsKitSystemTest, GetAbilityLabel_0600, Function | MediumTest | Lev CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_NE(installResult, "Success"); + EXPECT_NE(installResult, "Success"); sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string abilityLabel = bundleMgrProxy->GetAbilityLabel(appName, abilityName); EXPECT_EQ(abilityLabel, Constants::EMPTY_STRING); @@ -2437,7 +2403,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetHapModuleInfo_0100, Function | MediumTest | Le CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; AbilityInfo abilityInfo; abilityInfo.bundleName = appName; @@ -2446,21 +2412,21 @@ HWTEST_F(ActsBmsKitSystemTest, GetHapModuleInfo_0100, Function | MediumTest | Le sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool queryResult = bundleMgrProxy->GetHapModuleInfo(abilityInfo, hapModuleInfo); EXPECT_TRUE(queryResult); EXPECT_EQ(hapModuleInfo.name, "com.third.hiworld.example.h1"); - EXPECT_EQ(hapModuleInfo.moduleName, "bmsThirdBundle1"); + EXPECT_EQ(hapModuleInfo.moduleName, "testability"); EXPECT_EQ(hapModuleInfo.description, ""); EXPECT_EQ(hapModuleInfo.label, "bmsThirdBundle_A1 Ability"); - std::cout << commonTool.VectorToStr(hapModuleInfo.deviceTypes) << std::endl; + EXPECT_EQ(commonTool.VectorToStr(hapModuleInfo.deviceTypes), "tvcar"); resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!queryResult) { APP_LOGI("GetHapModuleInfo_0100 failed - cycle count: %{public}d", i); @@ -2495,7 +2461,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetHapModuleInfo_0200, Function | MediumTest | Le CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; AbilityInfo abilityInfo; abilityInfo.bundleName = appName; @@ -2504,14 +2470,14 @@ HWTEST_F(ActsBmsKitSystemTest, GetHapModuleInfo_0200, Function | MediumTest | Le sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool queryResult = bundleMgrProxy->GetHapModuleInfo(abilityInfo, hapModuleInfo); EXPECT_TRUE(queryResult); EXPECT_EQ(hapModuleInfo.name, "com.third.hiworld.example.h1"); - EXPECT_EQ(hapModuleInfo.moduleName, "bmsThirdBundle2"); + EXPECT_EQ(hapModuleInfo.moduleName, "testability"); EXPECT_EQ(hapModuleInfo.label, "bmsThirdBundle_A1 Ability"); - std::cout << commonTool.VectorToStr(hapModuleInfo.deviceTypes) << std::endl; + EXPECT_EQ(commonTool.VectorToStr(hapModuleInfo.deviceTypes), "tvcar"); bool isSubStrExist = false; for (int i = 1; i <= 2; i++) { std::string abilityName = "" + std::to_string(i); @@ -2526,7 +2492,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetHapModuleInfo_0200, Function | MediumTest | Le resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!queryResult) { APP_LOGI("GetHapModuleInfo_0200 failed - cycle count: %{public}d", i); @@ -2561,7 +2527,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetHapModuleInfo_0300, Function | MediumTest | Le CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; AbilityInfo abilityInfo; abilityInfo.bundleName = appName; @@ -2570,18 +2536,17 @@ HWTEST_F(ActsBmsKitSystemTest, GetHapModuleInfo_0300, Function | MediumTest | Le sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool queryResult = bundleMgrProxy->GetHapModuleInfo(abilityInfo, hapModuleInfo); EXPECT_TRUE(queryResult); EXPECT_EQ(hapModuleInfo.name, "com.third.hiworld.example.h1"); - EXPECT_EQ(hapModuleInfo.moduleName, "bmsThirdBundle3"); - std::cout << commonTool.VectorToStr(hapModuleInfo.deviceTypes) << std::endl; + EXPECT_EQ(hapModuleInfo.moduleName, "testability"); resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!queryResult) { APP_LOGI("GetHapModuleInfo_0300 failed - cycle count: %{public}d", i); @@ -2616,7 +2581,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetHapModuleInfo_0400, Function | MediumTest | Le CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; AbilityInfo abilityInfo; abilityInfo.bundleName = "error_bundleName"; @@ -2626,14 +2591,14 @@ HWTEST_F(ActsBmsKitSystemTest, GetHapModuleInfo_0400, Function | MediumTest | Le sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool queryResult = bundleMgrProxy->GetHapModuleInfo(abilityInfo, hapModuleInfo); EXPECT_FALSE(queryResult); resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (queryResult) { APP_LOGI("GetHapModuleInfo_0400 failed - cycle count: %{public}d", i); @@ -2669,15 +2634,15 @@ HWTEST_F(ActsBmsKitSystemTest, GetHapModuleInfo_0500, Function | MediumTest | Le sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool queryResult = bundleMgrProxy->GetHapModuleInfo(abilityInfo, hapModuleInfo); EXPECT_TRUE(queryResult); EXPECT_EQ(hapModuleInfo.name, "com.ohos.settings"); - EXPECT_EQ(hapModuleInfo.moduleName, ".MyApplication"); + EXPECT_EQ(hapModuleInfo.moduleName, "entry"); EXPECT_EQ(hapModuleInfo.label, "$string:app_name"); CommonTool commonTool; - std::cout << commonTool.VectorToStr(hapModuleInfo.deviceTypes) << std::endl; + EXPECT_EQ(commonTool.VectorToStr(hapModuleInfo.deviceTypes), "phone"); if (!queryResult) { APP_LOGI("GetHapModuleInfo_0500 failed - cycle count: %{public}d", i); @@ -2712,7 +2677,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetHapModuleInfo_0600, Function | MediumTest | Le CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_NE(installResult, "Success"); + EXPECT_NE(installResult, "Success"); AbilityInfo abilityInfo; abilityInfo.bundleName = appName; @@ -2721,7 +2686,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetHapModuleInfo_0600, Function | MediumTest | Le sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool queryResult = bundleMgrProxy->GetHapModuleInfo(abilityInfo, hapModuleInfo); EXPECT_FALSE(queryResult); @@ -2759,7 +2724,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetHapModuleInfo_0700, Function | MediumTest | Le CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_NE(installResult, "Success") << "install fail!"; + EXPECT_NE(installResult, "Success") << "install fail!"; AbilityInfo abilityInfo; abilityInfo.bundleName = appName; @@ -2768,7 +2733,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetHapModuleInfo_0700, Function | MediumTest | Le sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool queryResult = bundleMgrProxy->GetHapModuleInfo(abilityInfo, hapModuleInfo); EXPECT_FALSE(queryResult); @@ -2807,17 +2772,17 @@ HWTEST_F(ActsBmsKitSystemTest, Callback_0100, Function | MediumTest | Level1) CommonTool commonTool; sptr bundleStatusCallback = (new (std::nothrow) BundleStatusCallbackImpl()); - ASSERT_NE(bundleStatusCallback, nullptr); + EXPECT_NE(bundleStatusCallback, nullptr); bundleStatusCallback->SetBundleName(appName); sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bundleMgrProxy->RegisterBundleStatusCallback(bundleStatusCallback); Install(bundleFilePath, InstallFlag::NORMAL, resvec); std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; bool unRegResult = bundleMgrProxy->UnregisterBundleStatusCallback(); EXPECT_TRUE(unRegResult); @@ -2825,7 +2790,7 @@ HWTEST_F(ActsBmsKitSystemTest, Callback_0100, Function | MediumTest | Level1) resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!unRegResult) { APP_LOGI("Callback_0100 failed - cycle count: %{public}d", i); @@ -2861,17 +2826,17 @@ HWTEST_F(ActsBmsKitSystemTest, Callback_0200, Function | MediumTest | Level1) CommonTool commonTool; sptr bundleStatusCallback = (new (std::nothrow) BundleStatusCallbackImpl()); - ASSERT_NE(bundleStatusCallback, nullptr); + EXPECT_NE(bundleStatusCallback, nullptr); bundleStatusCallback->SetBundleName(appName); sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bundleMgrProxy->RegisterBundleStatusCallback(bundleStatusCallback); Install(bundleFilePath, InstallFlag::NORMAL, resvec); std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_NE(installResult, "Success"); + EXPECT_NE(installResult, "Success"); bool unRegResult = bundleMgrProxy->UnregisterBundleStatusCallback(); EXPECT_TRUE(unRegResult); @@ -2912,29 +2877,29 @@ HWTEST_F(ActsBmsKitSystemTest, Callback_0300, Function | MediumTest | Level1) CommonTool commonTool; sptr bundleStatusCallback = (new (std::nothrow) BundleStatusCallbackImpl()); - ASSERT_NE(bundleStatusCallback, nullptr); + EXPECT_NE(bundleStatusCallback, nullptr); bundleStatusCallback->SetBundleName(appName); sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bundleMgrProxy->RegisterBundleStatusCallback(bundleStatusCallback); Install(firstFilePath, InstallFlag::NORMAL, resvec); std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; resvec.clear(); Install(secondFilePath, InstallFlag::REPLACE_EXISTING, resvec); std::string upgradeResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(upgradeResult, "Success") << "upgrade fail!"; + EXPECT_EQ(upgradeResult, "Success") << "upgrade fail!"; bool unRegResult = bundleMgrProxy->UnregisterBundleStatusCallback(); EXPECT_TRUE(unRegResult); std::vector resvec2; Uninstall(appName, resvec2); std::string uninstallResult = commonTool.VectorToStr(resvec2); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!unRegResult) { APP_LOGI("Callback_0300 failed - cycle count: %{public}d", i); @@ -2973,29 +2938,29 @@ HWTEST_F(ActsBmsKitSystemTest, Callback_0400, Function | MediumTest | Level1) CommonTool commonTool; sptr bundleStatusCallback = (new (std::nothrow) BundleStatusCallbackImpl()); - ASSERT_NE(bundleStatusCallback, nullptr); + EXPECT_NE(bundleStatusCallback, nullptr); bundleStatusCallback->SetBundleName(appName); sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bundleMgrProxy->RegisterBundleStatusCallback(bundleStatusCallback); Install(firstFilePath, InstallFlag::NORMAL, resvec); std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; resvec.clear(); Install(secondFilePath, InstallFlag::REPLACE_EXISTING, resvec); std::string upgradeResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(upgradeResult, "Success") << "upgrade fail!"; + EXPECT_EQ(upgradeResult, "Success") << "upgrade fail!"; bool unRegResult = bundleMgrProxy->UnregisterBundleStatusCallback(); EXPECT_TRUE(unRegResult); std::vector resvec2; Uninstall(appName, resvec2); std::string uninstallResult = commonTool.VectorToStr(resvec2); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!unRegResult) { APP_LOGI("Callback_0400 failed - cycle count: %{public}d", i); @@ -3034,29 +2999,29 @@ HWTEST_F(ActsBmsKitSystemTest, Callback_0500, Function | MediumTest | Level1) CommonTool commonTool; sptr bundleStatusCallback = (new (std::nothrow) BundleStatusCallbackImpl()); - ASSERT_NE(bundleStatusCallback, nullptr); + EXPECT_NE(bundleStatusCallback, nullptr); bundleStatusCallback->SetBundleName(appName); sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bundleMgrProxy->RegisterBundleStatusCallback(bundleStatusCallback); Install(firstFilePath, InstallFlag::NORMAL, resvec); std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; resvec.clear(); Install(secondFilePath, InstallFlag::REPLACE_EXISTING, resvec); std::string upgradeResult = commonTool.VectorToStr(resvec); - ASSERT_NE(upgradeResult, "Success") << "upgrade success!"; + EXPECT_NE(upgradeResult, "Success") << "upgrade success!"; bool unRegResult = bundleMgrProxy->UnregisterBundleStatusCallback(); EXPECT_TRUE(unRegResult); std::vector resvec2; Uninstall(appName, resvec2); std::string uninstallResult = commonTool.VectorToStr(resvec2); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!unRegResult) { APP_LOGI("Callback_0500 failed - cycle count: %{public}d", i); @@ -3092,23 +3057,23 @@ HWTEST_F(ActsBmsKitSystemTest, Callback_0600, Function | MediumTest | Level1) CommonTool commonTool; sptr bundleStatusCallback = (new (std::nothrow) BundleStatusCallbackImpl()); - ASSERT_NE(bundleStatusCallback, nullptr); + EXPECT_NE(bundleStatusCallback, nullptr); bundleStatusCallback->SetBundleName(appName); sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bundleMgrProxy->RegisterBundleStatusCallback(bundleStatusCallback); Install(filePath, InstallFlag::NORMAL, resvec); std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; bool clearResult = bundleMgrProxy->ClearBundleStatusCallback(bundleStatusCallback); EXPECT_TRUE(clearResult); resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!clearResult) { APP_LOGI("Callback_0600 failed - cycle count: %{public}d", i); @@ -3148,26 +3113,26 @@ HWTEST_F(ActsBmsKitSystemTest, Callback_0700, Function | MediumTest | Level1) CommonTool commonTool; sptr firstBundleStatusCallback = (new (std::nothrow) BundleStatusCallbackImpl()); - ASSERT_NE(firstBundleStatusCallback, nullptr); + EXPECT_NE(firstBundleStatusCallback, nullptr); firstBundleStatusCallback->SetBundleName(firstAppName); sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bundleMgrProxy->RegisterBundleStatusCallback(firstBundleStatusCallback); Install(firstFilePath, InstallFlag::NORMAL, resvec); std::string firstinstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(firstinstallResult, "Success") << "install fail!"; + EXPECT_EQ(firstinstallResult, "Success") << "install fail!"; resvec.clear(); sptr secondBundleStatusCallback = (new (std::nothrow) BundleStatusCallbackImpl()); - ASSERT_NE(secondBundleStatusCallback, nullptr); + EXPECT_NE(secondBundleStatusCallback, nullptr); secondBundleStatusCallback->SetBundleName(secondAppName); bundleMgrProxy->RegisterBundleStatusCallback(secondBundleStatusCallback); Install(secondFilePath, InstallFlag::NORMAL, resvec); std::string secondinstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(secondinstallResult, "Success") << "install fail!"; + EXPECT_EQ(secondinstallResult, "Success") << "install fail!"; bool clearResult = bundleMgrProxy->ClearBundleStatusCallback(firstBundleStatusCallback); EXPECT_TRUE(clearResult); @@ -3175,11 +3140,11 @@ HWTEST_F(ActsBmsKitSystemTest, Callback_0700, Function | MediumTest | Level1) std::vector resvec2; Uninstall(firstAppName, resvec2); std::string uninstallResult = commonTool.VectorToStr(resvec2); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; resvec2.clear(); Uninstall(secondAppName, resvec2); uninstallResult = commonTool.VectorToStr(resvec2); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!clearResult) { APP_LOGI("Callback_0700 failed - cycle count: %{public}d", i); @@ -3219,26 +3184,26 @@ HWTEST_F(ActsBmsKitSystemTest, Callback_0800, Function | MediumTest | Level1) CommonTool commonTool; sptr firstBundleStatusCallback = (new (std::nothrow) BundleStatusCallbackImpl()); - ASSERT_NE(firstBundleStatusCallback, nullptr); + EXPECT_NE(firstBundleStatusCallback, nullptr); firstBundleStatusCallback->SetBundleName(firstAppName); sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bundleMgrProxy->RegisterBundleStatusCallback(firstBundleStatusCallback); Install(firstFilePath, InstallFlag::NORMAL, resvec); std::string firstinstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(firstinstallResult, "Success") << "install fail!"; + EXPECT_EQ(firstinstallResult, "Success") << "install fail!"; resvec.clear(); sptr secondBundleStatusCallback = (new (std::nothrow) BundleStatusCallbackImpl()); - ASSERT_NE(secondBundleStatusCallback, nullptr); + EXPECT_NE(secondBundleStatusCallback, nullptr); secondBundleStatusCallback->SetBundleName(secondAppName); bundleMgrProxy->RegisterBundleStatusCallback(secondBundleStatusCallback); Install(secondFilePath, InstallFlag::NORMAL, resvec); std::string secondinstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(secondinstallResult, "Success") << "install fail!"; + EXPECT_EQ(secondinstallResult, "Success") << "install fail!"; bool clearResult = bundleMgrProxy->ClearBundleStatusCallback(secondBundleStatusCallback); EXPECT_TRUE(clearResult); @@ -3246,11 +3211,11 @@ HWTEST_F(ActsBmsKitSystemTest, Callback_0800, Function | MediumTest | Level1) std::vector resvec2; Uninstall(firstAppName, resvec2); std::string uninstallResult = commonTool.VectorToStr(resvec2); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; resvec2.clear(); Uninstall(secondAppName, resvec2); uninstallResult = commonTool.VectorToStr(resvec2); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!clearResult) { APP_LOGI("Callback_0800 failed - cycle count: %{public}d", i); @@ -3291,26 +3256,26 @@ HWTEST_F(ActsBmsKitSystemTest, Callback_0900, Function | MediumTest | Level1) CommonTool commonTool; sptr firstBundleStatusCallback = (new (std::nothrow) BundleStatusCallbackImpl()); - ASSERT_NE(firstBundleStatusCallback, nullptr); + EXPECT_NE(firstBundleStatusCallback, nullptr); firstBundleStatusCallback->SetBundleName(firstAppName); sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bundleMgrProxy->RegisterBundleStatusCallback(firstBundleStatusCallback); Install(firstFilePath, InstallFlag::NORMAL, resvec); std::string firstinstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(firstinstallResult, "Success") << "install fail!"; + EXPECT_EQ(firstinstallResult, "Success") << "install fail!"; resvec.clear(); sptr secondBundleStatusCallback = (new (std::nothrow) BundleStatusCallbackImpl()); - ASSERT_NE(secondBundleStatusCallback, nullptr); + EXPECT_NE(secondBundleStatusCallback, nullptr); secondBundleStatusCallback->SetBundleName(secondAppName); bundleMgrProxy->RegisterBundleStatusCallback(secondBundleStatusCallback); Install(secondFilePath, InstallFlag::NORMAL, resvec); std::string secondinstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(secondinstallResult, "Success") << "install fail!"; + EXPECT_EQ(secondinstallResult, "Success") << "install fail!"; bool clearResult1 = bundleMgrProxy->ClearBundleStatusCallback(firstBundleStatusCallback); EXPECT_TRUE(clearResult1); @@ -3320,11 +3285,11 @@ HWTEST_F(ActsBmsKitSystemTest, Callback_0900, Function | MediumTest | Level1) std::vector resvec2; Uninstall(firstAppName, resvec2); std::string uninstallResult = commonTool.VectorToStr(resvec2); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; resvec2.clear(); Uninstall(secondAppName, resvec2); uninstallResult = commonTool.VectorToStr(resvec2); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!clearResult1 && !clearResult2) { APP_LOGI("Callback_0900 failed - cycle count: %{public}d", i); @@ -3360,30 +3325,36 @@ HWTEST_F(ActsBmsKitSystemTest, CleanBundleCacheFiles_0100, Function | MediumTest CommonTool commonTool; Install(bundleFilePath, InstallFlag::NORMAL, resvec); std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; - - const std::string testCacheFileNamE1 = BUNDLE_DATA_ROOT_PATH + "/" + appName + "/cache/name1.txt"; - const std::string testCacheFileNamE2 = BUNDLE_DATA_ROOT_PATH + "/" + appName + "/cache/name2.txt"; + EXPECT_EQ(installResult, "Success") << "install fail!"; + std::this_thread::sleep_for(5000ms); + system("aa start -a PageAbilityDemo -b com.third.hiworld.example1"); + std::this_thread::sleep_for(1000ms); + const std::string testCacheFileNamE1 = BUNDLE_DATA_ROOT_PATH + appName + "/cache/name1.txt"; + const std::string testCacheFileNamE2 = BUNDLE_DATA_ROOT_PATH + appName + "/cache/name2.txt"; + int name1Exist = access(testCacheFileNamE1.c_str(), F_OK); + EXPECT_EQ(name1Exist, 0); + int name2Exist = access(testCacheFileNamE2.c_str(), F_OK); + EXPECT_EQ(name2Exist, 0); sptr bundleCleanCacheCallback = (new (std::nothrow) CleanCacheCallBackImpl()); - ASSERT_NE(bundleCleanCacheCallback, nullptr); + EXPECT_NE(bundleCleanCacheCallback, nullptr); sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bundleMgrProxy->CleanBundleCacheFiles(appName, bundleCleanCacheCallback); bool cleanCacheResult = bundleCleanCacheCallback->GetSucceededResult(); EXPECT_TRUE(cleanCacheResult); - int name1Exist = access(testCacheFileNamE1.c_str(), F_OK); + name1Exist = access(testCacheFileNamE1.c_str(), F_OK); EXPECT_NE(name1Exist, 0) << "the cache test file1 exists."; - int name2Exist = access(testCacheFileNamE2.c_str(), F_OK); + name2Exist = access(testCacheFileNamE2.c_str(), F_OK); EXPECT_NE(name2Exist, 0) << "the cache test file2 exists."; resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!cleanCacheResult) { APP_LOGI("CleanBundleCacheFiles_0100 failed - cycle count: %{public}d", i); @@ -3419,30 +3390,35 @@ HWTEST_F(ActsBmsKitSystemTest, CleanBundleCacheFiles_0200, Function | MediumTest CommonTool commonTool; Install(bundleFilePath, InstallFlag::NORMAL, resvec); std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; - - const std::string testCacheDiR1 = BUNDLE_DATA_ROOT_PATH + "/" + appName + "/cache/testDir1"; - const std::string testCacheDiR2 = BUNDLE_DATA_ROOT_PATH + "/" + appName + "/cache/testDir2"; - + EXPECT_EQ(installResult, "Success") << "install fail!"; + std::this_thread::sleep_for(5000ms); + system("aa start -a PageAbilityDemo -b com.third.hiworld.example2"); + std::this_thread::sleep_for(1000ms); + const std::string testCacheDiR1 = BUNDLE_DATA_ROOT_PATH + appName + "/cache/testDir1"; + const std::string testCacheDiR2 = BUNDLE_DATA_ROOT_PATH + appName + "/cache/testDir2"; + int name1Exist = access(testCacheDiR1.c_str(), F_OK); + EXPECT_EQ(name1Exist, 0); + int name2Exist = access(testCacheDiR2.c_str(), F_OK); + EXPECT_EQ(name2Exist, 0); sptr bundleCleanCacheCallback = (new (std::nothrow) CleanCacheCallBackImpl()); - ASSERT_NE(bundleCleanCacheCallback, nullptr); + EXPECT_NE(bundleCleanCacheCallback, nullptr); sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bundleMgrProxy->CleanBundleCacheFiles(appName, bundleCleanCacheCallback); bool cleanCacheResult = bundleCleanCacheCallback->GetSucceededResult(); EXPECT_TRUE(cleanCacheResult); - int name1Exist = access(testCacheDiR1.c_str(), F_OK); + name1Exist = access(testCacheDiR1.c_str(), F_OK); EXPECT_NE(name1Exist, 0) << "the cache test dir1 exists."; - int name2Exist = access(testCacheDiR2.c_str(), F_OK); + name2Exist = access(testCacheDiR2.c_str(), F_OK); EXPECT_NE(name2Exist, 0) << "the cache test dir2 exists."; resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!cleanCacheResult) { APP_LOGI("CleanBundleCacheFiles_0200 failed - cycle count: %{public}d", i); @@ -3472,34 +3448,37 @@ HWTEST_F(ActsBmsKitSystemTest, CleanBundleCacheFiles_0300, Function | MediumTest bool result = false; for (int i = 1; i <= stLevel_.BMSLevel; i++) { std::vector resvec; - std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1.hap"; + std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle44.hap"; std::string appName = BASE_BUNDLE_NAME + "1"; CommonTool commonTool; Install(bundleFilePath, InstallFlag::NORMAL, resvec); std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; - - const std::string testCacheFileName = - BUNDLE_DATA_ROOT_PATH + "/" + appName + "/cache/dir1/dir2/dir3/dir4/dir5/dir6/name.txt"; - const std::string testCacheDir = BUNDLE_DATA_ROOT_PATH + "/" + appName + "/cache/dir1"; + EXPECT_EQ(installResult, "Success") << "install fail!"; + std::this_thread::sleep_for(5000ms); + system("aa start -a PageAbilityDemo -b com.third.hiworld.example1"); + std::this_thread::sleep_for(1000ms); + const std::string testCacheFileName = BUNDLE_DATA_ROOT_PATH + appName + "/cache/dir1/dir2/dir3/dir4/dir5/dir6"; + const std::string testCacheDir = BUNDLE_DATA_ROOT_PATH + appName + "/cache/dir1"; + int isExist = access(testCacheDir.c_str(), F_OK); + EXPECT_EQ(isExist, 0); sptr bundleCleanCacheCallback = (new (std::nothrow) CleanCacheCallBackImpl()); - ASSERT_NE(bundleCleanCacheCallback, nullptr); + EXPECT_NE(bundleCleanCacheCallback, nullptr); sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bundleMgrProxy->CleanBundleCacheFiles(appName, bundleCleanCacheCallback); bool cleanCacheResult = bundleCleanCacheCallback->GetSucceededResult(); EXPECT_TRUE(cleanCacheResult); - int isExist = access(testCacheDir.c_str(), F_OK); + isExist = access(testCacheDir.c_str(), F_OK); EXPECT_NE(isExist, 0) << "the cache test dir exists."; resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!cleanCacheResult) { APP_LOGI("CleanBundleCacheFiles_0300 failed - cycle count: %{public}d", i); @@ -3529,38 +3508,43 @@ HWTEST_F(ActsBmsKitSystemTest, CleanBundleCacheFiles_0400, Function | MediumTest bool result = false; for (int i = 1; i <= stLevel_.BMSLevel; i++) { std::vector resvec; - std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle2.hap"; + std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle45.hap"; std::string appName = BASE_BUNDLE_NAME + "1"; CommonTool commonTool; Install(bundleFilePath, InstallFlag::NORMAL, resvec); std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; - - const std::string testCacheFileNamE1 = BUNDLE_DATA_ROOT_PATH + "/" + appName + "/cache/testDir1/name1.txt"; - const std::string testCacheDir1 = BUNDLE_DATA_ROOT_PATH + "/" + appName + "/cache/testDir1"; - const std::string testCacheFileNamE2 = BUNDLE_DATA_ROOT_PATH + "/" + appName + "/cache/testDir2/name2.txt"; - const std::string testCacheDir2 = BUNDLE_DATA_ROOT_PATH + "/" + appName + "/cache/testDir2"; - + EXPECT_EQ(installResult, "Success") << "install fail!"; + std::this_thread::sleep_for(5000ms); + system("aa start -a PageAbilityDemo -b com.third.hiworld.example1"); + std::this_thread::sleep_for(1000ms); + const std::string testCacheFileNamE1 = BUNDLE_DATA_ROOT_PATH + appName + "/cache/testDir1/name1.txt"; + const std::string testCacheDir1 = BUNDLE_DATA_ROOT_PATH + appName + "/cache/testDir1"; + const std::string testCacheFileNamE2 = BUNDLE_DATA_ROOT_PATH + appName + "/cache/testDir2/name2.txt"; + const std::string testCacheDir2 = BUNDLE_DATA_ROOT_PATH + appName + "/cache/testDir2"; + int name1Exist = access(testCacheDir1.c_str(), F_OK); + EXPECT_EQ(name1Exist, 0); + int name2Exist = access(testCacheDir2.c_str(), F_OK); + EXPECT_EQ(name2Exist, 0); sptr bundleCleanCacheCallback = (new (std::nothrow) CleanCacheCallBackImpl()); - ASSERT_NE(bundleCleanCacheCallback, nullptr); + EXPECT_NE(bundleCleanCacheCallback, nullptr); sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bundleMgrProxy->CleanBundleCacheFiles(appName, bundleCleanCacheCallback); bool cleanCacheResult = bundleCleanCacheCallback->GetSucceededResult(); EXPECT_TRUE(cleanCacheResult); - int name1Exist = access(testCacheDir1.c_str(), F_OK); + name1Exist = access(testCacheDir1.c_str(), F_OK); EXPECT_NE(name1Exist, 0) << "the cache test dir1 exists."; - int name2Exist = access(testCacheDir2.c_str(), F_OK); + name2Exist = access(testCacheDir2.c_str(), F_OK); EXPECT_NE(name2Exist, 0) << "the cache test dir2 exists."; resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!cleanCacheResult) { APP_LOGI("CleanBundleCacheFiles_0400 failed - cycle count: %{public}d", i); @@ -3593,13 +3577,13 @@ HWTEST_F(ActsBmsKitSystemTest, CleanBundleCacheFiles_0500, Function | MediumTest CommonTool commonTool; Install(bundleFilePath, InstallFlag::NORMAL, resvec); std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Failure[ERR_INSTALL_PARSE_NO_PROFILE]"); + EXPECT_EQ(installResult, "Failure[ERR_INSTALL_PARSE_NO_PROFILE]"); sptr bundleCleanCacheCallback = (new (std::nothrow) CleanCacheCallBackImpl()); - ASSERT_NE(bundleCleanCacheCallback, nullptr); + EXPECT_NE(bundleCleanCacheCallback, nullptr); sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool cleanCacheResult = bundleMgrProxy->CleanBundleCacheFiles(appName, bundleCleanCacheCallback); EXPECT_FALSE(cleanCacheResult); @@ -3636,14 +3620,14 @@ HWTEST_F(ActsBmsKitSystemTest, CleanBundleCacheFiles_0600, Function | MediumTest CommonTool commonTool; Install(bundleFilePath, InstallFlag::NORMAL, resvec); std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_NE(installResult, "Success"); + EXPECT_NE(installResult, "Success"); sptr bundleCleanCacheCallback = (new (std::nothrow) CleanCacheCallBackImpl()); - ASSERT_NE(bundleCleanCacheCallback, nullptr); + EXPECT_NE(bundleCleanCacheCallback, nullptr); sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool cleanCacheResult = bundleMgrProxy->CleanBundleCacheFiles(appName, bundleCleanCacheCallback); EXPECT_FALSE(cleanCacheResult); @@ -3681,13 +3665,13 @@ HWTEST_F(ActsBmsKitSystemTest, GetLaunchWantForBundle_0100, Function | MediumTes CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; Want want; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool launchWantResult = bundleMgrProxy->GetLaunchWantForBundle(appName, want); EXPECT_TRUE(launchWantResult); @@ -3695,7 +3679,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetLaunchWantForBundle_0100, Function | MediumTes resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!launchWantResult) { APP_LOGI("GetLaunchWantForBundle_0100 failed - cycle count: %{public}d", i); @@ -3730,13 +3714,13 @@ HWTEST_F(ActsBmsKitSystemTest, GetLaunchWantForBundle_0200, Function | MediumTes CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; Want want; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool launchWantResult = bundleMgrProxy->GetLaunchWantForBundle(appName, want); EXPECT_FALSE(launchWantResult); @@ -3744,7 +3728,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetLaunchWantForBundle_0200, Function | MediumTes resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (launchWantResult) { APP_LOGI("GetLaunchWantForBundle_0200 failed - cycle count: %{public}d", i); @@ -3780,7 +3764,7 @@ HWTEST_F(ActsBmsKitSystemTest, QueryAbilityInfo_0100, Function | MediumTest | Le CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; Want want; ElementName name; @@ -3792,7 +3776,7 @@ HWTEST_F(ActsBmsKitSystemTest, QueryAbilityInfo_0100, Function | MediumTest | Le sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool queryResult = bundleMgrProxy->QueryAbilityInfo(want, abilityInfo); EXPECT_TRUE(queryResult); @@ -3802,7 +3786,7 @@ HWTEST_F(ActsBmsKitSystemTest, QueryAbilityInfo_0100, Function | MediumTest | Le resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!queryResult) { APP_LOGI("QueryAbilityInfo_0100 failed - cycle count: %{public}d", i); @@ -3836,7 +3820,7 @@ HWTEST_F(ActsBmsKitSystemTest, QueryAbilityInfo_0200, Function | MediumTest | Le CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; Want want; ElementName name; @@ -3846,7 +3830,7 @@ HWTEST_F(ActsBmsKitSystemTest, QueryAbilityInfo_0200, Function | MediumTest | Le sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool queryResult = bundleMgrProxy->QueryAbilityInfo(want, abilityInfo); EXPECT_FALSE(queryResult); @@ -3854,7 +3838,7 @@ HWTEST_F(ActsBmsKitSystemTest, QueryAbilityInfo_0200, Function | MediumTest | Le resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (queryResult) { APP_LOGI("QueryAbilityInfo_0200 failed - cycle count: %{public}d", i); @@ -3889,7 +3873,7 @@ HWTEST_F(ActsBmsKitSystemTest, QueryAbilityInfo_0300, Function | MediumTest | Le Install(bundleFilePath, InstallFlag::NORMAL, resvec); CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; Want want; ElementName name; @@ -3901,7 +3885,7 @@ HWTEST_F(ActsBmsKitSystemTest, QueryAbilityInfo_0300, Function | MediumTest | Le sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool queryResult = bundleMgrProxy->QueryAbilityInfo(want, abilityInfo); EXPECT_TRUE(queryResult); @@ -3910,7 +3894,7 @@ HWTEST_F(ActsBmsKitSystemTest, QueryAbilityInfo_0300, Function | MediumTest | Le resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!queryResult) { APP_LOGI("QueryAbilityInfo_0300 failed - cycle count: %{public}d", i); break; @@ -3945,7 +3929,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleInfosByMetaData_0100, Function | MediumT CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; std::vector bundleInfos; @@ -3953,7 +3937,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleInfosByMetaData_0100, Function | MediumT sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getResult = bundleMgrProxy->GetBundleInfosByMetaData(metadata, bundleInfos); EXPECT_TRUE(getResult); @@ -3961,7 +3945,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleInfosByMetaData_0100, Function | MediumT resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!getResult) { APP_LOGI("GetBundleInfosByMetaData_0100 failed - cycle count: %{public}d", i); @@ -3992,7 +3976,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundleInfosByMetaData_0200, Function | MediumT sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getResult = bundleMgrProxy->GetBundleInfosByMetaData(metadata, bundleInfos); EXPECT_FALSE(getResult); @@ -4031,7 +4015,7 @@ HWTEST_F(ActsBmsKitSystemTest, AbilityDump_0100, Function | MediumTest | Level0) CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; Want want; ElementName name; @@ -4043,17 +4027,17 @@ HWTEST_F(ActsBmsKitSystemTest, AbilityDump_0100, Function | MediumTest | Level0) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool queryResult = bundleMgrProxy->QueryAbilityInfo(want, abilityInfo); EXPECT_EQ(abilityInfo.name, abilityName); EXPECT_TRUE(queryResult); std::string path = "/data/test/abilityInfo.txt"; - bool isSuccess = CreateFile(path); - ASSERT_TRUE(isSuccess); + std::ofstream file(path); + file.close(); int fd = open(path.c_str(), O_WRONLY | O_CLOEXEC); - ASSERT_NE(fd, -1) << "open file error"; + EXPECT_NE(fd, -1) << "open file error"; std::string prefix = "[ability]"; abilityInfo.Dump(prefix, fd); long length = lseek(fd, 0, SEEK_END); @@ -4063,7 +4047,7 @@ HWTEST_F(ActsBmsKitSystemTest, AbilityDump_0100, Function | MediumTest | Level0) resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!queryResult) { APP_LOGI("AbilityDump_0100 failed - cycle count: %{public}d", i); @@ -4099,14 +4083,14 @@ HWTEST_F(ActsBmsKitSystemTest, ApplicationInfoDump_0100, Function | MediumTest | CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; ApplicationInfo appInfo; int userId = Constants::DEFAULT_USERID; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getInfoResult = bundleMgrProxy->GetApplicationInfo(appName, ApplicationFlag::GET_BASIC_APPLICATION_INFO, userId, appInfo); @@ -4114,10 +4098,10 @@ HWTEST_F(ActsBmsKitSystemTest, ApplicationInfoDump_0100, Function | MediumTest | EXPECT_EQ(appInfo.name, appName); std::string path = "/data/test/appInfo.txt"; - bool isSuccess = CreateFile(path); - ASSERT_TRUE(isSuccess); + std::ofstream file(path); + file.close(); int fd = open(path.c_str(), O_WRONLY | O_CLOEXEC); - ASSERT_NE(fd, -1) << "open file error"; + EXPECT_NE(fd, -1) << "open file error"; std::string prefix = "[appInfo]"; appInfo.Dump(prefix, fd); long length = lseek(fd, 0, SEEK_END); @@ -4127,7 +4111,7 @@ HWTEST_F(ActsBmsKitSystemTest, ApplicationInfoDump_0100, Function | MediumTest | resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!getInfoResult) { APP_LOGI("ApplicationInfoDump_0100 failed - cycle count: %{public}d", i); @@ -4163,7 +4147,7 @@ HWTEST_F(ActsBmsKitSystemTest, Errors_0100, Function | MediumTest | Level1) CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; resvec.clear(); Install(bundleFilePath, InstallFlag::NORMAL, resvec); @@ -4173,7 +4157,7 @@ HWTEST_F(ActsBmsKitSystemTest, Errors_0100, Function | MediumTest | Level1) std::vector resvec2; Uninstall(appName, resvec2); std::string uninstallResult = commonTool.VectorToStr(resvec2); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (std::strcmp(installResult.c_str(), "Success") == 0) { APP_LOGI("Errors_0100 failed - cycle count: %{public}d", i); @@ -4207,18 +4191,18 @@ HWTEST_F(ActsBmsKitSystemTest, Errors_0200, Function | MediumTest | Level1) Install(bundleFilePath, InstallFlag::NORMAL, resvec); CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; resvec.clear(); bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle7.hap"; Install(bundleFilePath, InstallFlag::REPLACE_EXISTING, resvec); installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Failure[ERR_INSTALL_VERSION_DOWNGRADE]"); + EXPECT_EQ(installResult, "Failure[ERR_INSTALL_VERSION_DOWNGRADE]"); std::vector resvec2; Uninstall(bundleName, resvec2); std::string uninstallResult = commonTool.VectorToStr(resvec2); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (std::strcmp(installResult.c_str(), "Success") == 0) { APP_LOGI("Errors_0200 failed - cycle count: %{public}d", i); @@ -4251,12 +4235,12 @@ HWTEST_F(ActsBmsKitSystemTest, Errors_0300, Function | MediumTest | Level1) Install(bundleFilePath, InstallFlag::NORMAL, resvec); CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Failure[ERR_INSTALL_PARSE_PROFILE_MISSING_PROP]"); + EXPECT_EQ(installResult, "Failure[ERR_INSTALL_PARSE_PROFILE_MISSING_PROP]"); resvec.clear(); Install(bundleFilePath, InstallFlag::REPLACE_EXISTING, resvec); installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Failure[ERR_INSTALL_PARSE_PROFILE_MISSING_PROP]"); + EXPECT_EQ(installResult, "Failure[ERR_INSTALL_PARSE_PROFILE_MISSING_PROP]"); std::string bundleName = BASE_BUNDLE_NAME + "14"; @@ -4264,7 +4248,7 @@ HWTEST_F(ActsBmsKitSystemTest, Errors_0300, Function | MediumTest | Level1) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getInfoResult = bundleMgrProxy->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); EXPECT_FALSE(getInfoResult); @@ -4368,7 +4352,7 @@ HWTEST_F(ActsBmsKitSystemTest, Errors_0600, Function | MediumTest | Level1) CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Failure[MSG_ERR_INSTALL_FILE_PATH_INVALID]"); + EXPECT_EQ(installResult, "Failure[MSG_ERR_INSTALL_FILE_PATH_INVALID]"); if (std::strcmp(installResult.c_str(), "Success") == 0) { APP_LOGI("Errors_0600 failed - cycle count: %{public}d", i); break; @@ -4404,19 +4388,19 @@ HWTEST_F(ActsBmsKitSystemTest, Errors_0700, Function | MediumTest | Level1) CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; resvec.clear(); appName = BASE_BUNDLE_NAME + "1"; Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; std::vector resvec2; appName = BASE_BUNDLE_NAME + "e"; Uninstall(appName, resvec2); uninstallResult = commonTool.VectorToStr(resvec2); - ASSERT_EQ(uninstallResult, "Failure[ERR_UNINSTALL_MISSING_INSTALLED_BUNDLE]"); + EXPECT_EQ(uninstallResult, "Failure[ERR_UNINSTALL_MISSING_INSTALLED_BUNDLE]"); if (std::strcmp(uninstallResult.c_str(), "Success") == 0) { APP_LOGI("Errors_0700 failed - cycle count: %{public}d", i); @@ -4453,17 +4437,17 @@ HWTEST_F(ActsBmsKitSystemTest, Errors_0800, Function | MediumTest | Level1) CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; resvec.clear(); Uninstall(appName, resvec); uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Failure[ERR_UNINSTALL_MISSING_INSTALLED_BUNDLE]"); + EXPECT_EQ(uninstallResult, "Failure[ERR_UNINSTALL_MISSING_INSTALLED_BUNDLE]"); if (std::strcmp(uninstallResult.c_str(), "Success") == 0) { APP_LOGI("Errors_0800 failed - cycle count: %{public}d", i); break; @@ -4496,7 +4480,7 @@ HWTEST_F(ActsBmsKitSystemTest, Errors_0900, Function | MediumTest | Level1) Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Failure[MSG_ERR_UNINSTALL_SYSTEM_APP_ERROR]"); + EXPECT_EQ(uninstallResult, "Failure[MSG_ERR_UNINSTALL_SYSTEM_APP_ERROR]"); if (std::strcmp(uninstallResult.c_str(), "Success") == 0) { APP_LOGI("Errors_0900 failed - cycle count: %{public}d", i); break; @@ -4531,14 +4515,14 @@ HWTEST_F(ActsBmsKitSystemTest, ApplicationInfo_0100, Function | MediumTest | Lev CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; ApplicationInfo appInfo; int userId = Constants::DEFAULT_USERID; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getInfoResult = bundleMgrProxy->GetApplicationInfo(appName, ApplicationFlag::GET_BASIC_APPLICATION_INFO, userId, appInfo); @@ -4546,10 +4530,10 @@ HWTEST_F(ActsBmsKitSystemTest, ApplicationInfo_0100, Function | MediumTest | Lev EXPECT_EQ(appInfo.name, appName); ApplicationInfo *pAppInfo = &appInfo; std::string path = "/data/test/pAppInfo_01.txt"; - bool isSuccess = CreateFile(path); - ASSERT_TRUE(isSuccess); + std::ofstream file(path); + file.close(); int fd = open(path.c_str(), O_RDWR); - ASSERT_NE(fd, -1) << "open file error"; + EXPECT_NE(fd, -1) << "open file error"; std::string prefix = "[pAppInfo]"; pAppInfo->Dump(prefix, fd); long length = lseek(fd, 0, SEEK_END); @@ -4566,7 +4550,7 @@ HWTEST_F(ActsBmsKitSystemTest, ApplicationInfo_0100, Function | MediumTest | Lev resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (retVal <= 0) { APP_LOGI("ApplicationInfo_0100 failed - cycle count: %{public}d", i); @@ -4602,10 +4586,10 @@ HWTEST_F(ActsBmsKitSystemTest, ApplicationInfo_0200, Function | MediumTest | Lev ApplicationInfo *pAppInfo = &appInfo; std::string path = "/data/test/pAppInfo_02.txt"; - bool isSuccess = CreateFile(path); - ASSERT_TRUE(isSuccess); + std::ofstream file(path); + file.close(); int fd = open(path.c_str(), O_RDWR | O_CLOEXEC); - ASSERT_NE(fd, -1) << "open file error"; + EXPECT_NE(fd, -1) << "open file error"; std::string prefix = "[pAppInfo]"; pAppInfo->Dump(prefix, fd); long length = lseek(fd, 0, SEEK_END); @@ -4650,12 +4634,12 @@ HWTEST_F(ActsBmsKitSystemTest, QueryKeepAliveBundleInfos_0100, Function | Medium CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGI("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::vector bundleInfos; @@ -4665,7 +4649,7 @@ HWTEST_F(ActsBmsKitSystemTest, QueryKeepAliveBundleInfos_0100, Function | Medium resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; std::cout << "END QueryKeepAliveBundleInfos_0100" << std::endl; } @@ -4686,12 +4670,12 @@ HWTEST_F(ActsBmsKitSystemTest, QueryKeepAliveBundleInfos_0200, Function | Medium CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGI("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::vector bundleInfos; @@ -4701,7 +4685,7 @@ HWTEST_F(ActsBmsKitSystemTest, QueryKeepAliveBundleInfos_0200, Function | Medium resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; std::cout << "END QueryKeepAliveBundleInfos_0100" << std::endl; } @@ -4720,24 +4704,24 @@ HWTEST_F(ActsBmsKitSystemTest, Uninstall_KeepData_0100, Function | MediumTest | sptr installerProxy = GetInstallerProxy(); if (!installerProxy) { APP_LOGE("get bundle installer failed."); - ASSERT_EQ(installerProxy, nullptr); + EXPECT_EQ(installerProxy, nullptr); } InstallParam installParam; installParam.installFlag = InstallFlag::NORMAL; installParam.userId = Constants::DEFAULT_USERID; installParam.isKeepData = false; sptr statusReceiver = (new (std::nothrow) StatusReceiverImpl()); - ASSERT_NE(statusReceiver, nullptr); + EXPECT_NE(statusReceiver, nullptr); installerProxy->Install(bundleFilePath, installParam, statusReceiver); std::string installMsg = statusReceiver->GetResultMsg(); - ASSERT_EQ(installMsg, "Success") << "install fail!"; + EXPECT_EQ(installMsg, "Success") << "install fail!"; std::string appName = BASE_BUNDLE_NAME + "1"; std::vector resvec; Uninstall(appName, resvec); CommonTool commonTool; std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; CheckFileNonExist(appName); std::cout << "END Uninstall_KeepData_0100" << std::endl; } @@ -4757,24 +4741,24 @@ HWTEST_F(ActsBmsKitSystemTest, Uninstall_KeepData_0200, Function | MediumTest | sptr installerProxy = GetInstallerProxy(); if (!installerProxy) { APP_LOGE("get bundle installer failed."); - ASSERT_EQ(installerProxy, nullptr); + EXPECT_EQ(installerProxy, nullptr); } InstallParam installParam; installParam.installFlag = InstallFlag::NORMAL; installParam.userId = Constants::DEFAULT_USERID; installParam.isKeepData = true; sptr statusReceiver = (new (std::nothrow) StatusReceiverImpl()); - ASSERT_NE(statusReceiver, nullptr); + EXPECT_NE(statusReceiver, nullptr); installerProxy->Install(bundleFilePath, installParam, statusReceiver); std::string installMsg = statusReceiver->GetResultMsg(); - ASSERT_EQ(installMsg, "Success") << "install fail!"; + EXPECT_EQ(installMsg, "Success") << "install fail!"; std::string appName = BASE_BUNDLE_NAME + "1"; std::vector resvec; Uninstall(appName, resvec); CommonTool commonTool; std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; CheckFileExist(appName); std::cout << "END Uninstall_KeepData_0200" << std::endl; } @@ -4794,24 +4778,24 @@ HWTEST_F(ActsBmsKitSystemTest, Uninstall_KeepData_0300, Function | MediumTest | sptr installerProxy = GetInstallerProxy(); if (!installerProxy) { APP_LOGE("get bundle installer failed."); - ASSERT_EQ(installerProxy, nullptr); + EXPECT_EQ(installerProxy, nullptr); } InstallParam installParam; installParam.installFlag = InstallFlag::NORMAL; installParam.userId = Constants::DEFAULT_USERID; installParam.isKeepData = false; sptr statusReceiver = (new (std::nothrow) StatusReceiverImpl()); - ASSERT_NE(statusReceiver, nullptr); + EXPECT_NE(statusReceiver, nullptr); installerProxy->Install(bundleFilePath, installParam, statusReceiver); std::string installMsg = statusReceiver->GetResultMsg(); - ASSERT_EQ(installMsg, "Success") << "install fail!"; + EXPECT_EQ(installMsg, "Success") << "install fail!"; bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle4.hap"; sptr statusReceiver2 = (new (std::nothrow) StatusReceiverImpl()); - ASSERT_NE(statusReceiver2, nullptr); + EXPECT_NE(statusReceiver2, nullptr); installerProxy->Install(bundleFilePath, installParam, statusReceiver2); installMsg = statusReceiver2->GetResultMsg(); - ASSERT_EQ(installMsg, "Success") << "install fail!"; + EXPECT_EQ(installMsg, "Success") << "install fail!"; std::string appName = BASE_BUNDLE_NAME + "1"; @@ -4821,12 +4805,12 @@ HWTEST_F(ActsBmsKitSystemTest, Uninstall_KeepData_0300, Function | MediumTest | HapUninstall(bundleName, modulePackage, resvec); CommonTool commonTool; std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall hap fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall hap fail!"; CheckFileNonExist(appName, modulePackage); resvec.clear(); Uninstall(appName, resvec); uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; std::cout << "END Uninstall_KeepData_0300" << std::endl; } @@ -4845,24 +4829,24 @@ HWTEST_F(ActsBmsKitSystemTest, Uninstall_KeepData_0400, Function | MediumTest | sptr installerProxy = GetInstallerProxy(); if (!installerProxy) { APP_LOGE("get bundle installer failed."); - ASSERT_EQ(installerProxy, nullptr); + EXPECT_EQ(installerProxy, nullptr); } InstallParam installParam; installParam.installFlag = InstallFlag::NORMAL; installParam.userId = Constants::DEFAULT_USERID; installParam.isKeepData = true; sptr statusReceiver = (new (std::nothrow) StatusReceiverImpl()); - ASSERT_NE(statusReceiver, nullptr); + EXPECT_NE(statusReceiver, nullptr); installerProxy->Install(bundleFilePath, installParam, statusReceiver); std::string installMsg = statusReceiver->GetResultMsg(); - ASSERT_EQ(installMsg, "Success") << "install fail!"; + EXPECT_EQ(installMsg, "Success") << "install fail!"; bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle4.hap"; sptr statusReceiver2 = (new (std::nothrow) StatusReceiverImpl()); - ASSERT_NE(statusReceiver2, nullptr); + EXPECT_NE(statusReceiver2, nullptr); installerProxy->Install(bundleFilePath, installParam, statusReceiver2); installMsg = statusReceiver2->GetResultMsg(); - ASSERT_EQ(installMsg, "Success") << "install fail!"; + EXPECT_EQ(installMsg, "Success") << "install fail!"; std::string appName = BASE_BUNDLE_NAME + "1"; std::vector resvec; @@ -4871,12 +4855,12 @@ HWTEST_F(ActsBmsKitSystemTest, Uninstall_KeepData_0400, Function | MediumTest | HapUninstall(bundleName, modulePackage, resvec); CommonTool commonTool; std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall hap fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall hap fail!"; CheckFileExist(appName, modulePackage); resvec.clear(); Uninstall(appName, resvec); uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; std::cout << "END Uninstall_KeepData_0400" << std::endl; } @@ -4895,7 +4879,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundlesForUid_0100, Function | MediumTest | Le sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string installResult; CommonTool commonTool; @@ -4925,7 +4909,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundlesForUid_0100, Function | MediumTest | Le std::string appName = BASE_BUNDLE_NAME + std::to_string(i); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; } if (!ret) { APP_LOGI("GetBundlesForUid_0100 failed - cycle count: %{public}d", i); @@ -4955,7 +4939,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundlesForUid_0200, Function | MediumTest | Le sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::vector bundleNames; bool ret = bundleMgrProxy->GetBundlesForUid(Constants::INVALID_UID, bundleNames); @@ -4986,7 +4970,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetBundlesForUid_0300, Function | MediumTest | Le sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string appName = SYSTEM_SETTINGS_BUNDLE_NAME; BundleInfo bundleInfo; @@ -5040,12 +5024,12 @@ HWTEST_F(ActsBmsKitSystemTest, GetNameForUid_0100, Function | MediumTest | Level std::string name2; Install(bundleFilePath1, InstallFlag::NORMAL, resvec); installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; resvec.clear(); sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } BundleInfo bundleInfo1; @@ -5055,16 +5039,16 @@ HWTEST_F(ActsBmsKitSystemTest, GetNameForUid_0100, Function | MediumTest | Level EXPECT_TRUE(ret); Uninstall(appName1, resvec); - ASSERT_EQ(commonTool.VectorToStr(resvec), "Success") << "uninstall fail!"; + EXPECT_EQ(commonTool.VectorToStr(resvec), "Success") << "uninstall fail!"; resvec.clear(); Install(bundleFilePath2, InstallFlag::NORMAL, resvec); installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; resvec.clear(); Install(bundleFilePath1, InstallFlag::NORMAL, resvec); installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; BundleInfo bundleInfo2; bundleMgrProxy->GetBundleInfo(appName1, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo2); @@ -5078,7 +5062,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetNameForUid_0100, Function | MediumTest | Level std::vector resvec2; Uninstall(appName, resvec2); std::string uninstallResult = commonTool.VectorToStr(resvec2); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; } if (!ret) { APP_LOGI("GetNameForUid_0100 failed - cycle count: %{public}d", i); @@ -5113,11 +5097,11 @@ HWTEST_F(ActsBmsKitSystemTest, GetNameForUid_0200, Function | MediumTest | Level std::string appName = BASE_BUNDLE_NAME + '1'; Install(bundleFilePath, InstallFlag::NORMAL, resvec); installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } BundleInfo bundleInfo; bundleMgrProxy->GetBundleInfo(appName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); @@ -5126,7 +5110,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetNameForUid_0200, Function | MediumTest | Level EXPECT_FALSE(ret); resvec.clear(); Uninstall(appName, resvec); - ASSERT_EQ(commonTool.VectorToStr(resvec), "Success") << "uninstall fail!"; + EXPECT_EQ(commonTool.VectorToStr(resvec), "Success") << "uninstall fail!"; if (ret) { APP_LOGI("GetNameForUid_0200 failed - cycle count: %{public}d", i); break; @@ -5154,7 +5138,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetNameForUid_0300, Function | MediumTest | Level sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string appName = SYSTEM_SETTINGS_BUNDLE_NAME; BundleInfo bundleInfo; @@ -5198,18 +5182,18 @@ HWTEST_F(ActsBmsKitSystemTest, GetAbilityIcon_0100, Function | MediumTest | Leve CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string icon = bundleMgrProxy->GetAbilityIcon(appName, abilityName); EXPECT_EQ(icon, "$media:snowball"); resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (icon.compare("$media:snowball") != 0) { APP_LOGI("GetAbilityIcon_0100 failed - cycle count: %{public}d", i); break; @@ -5241,7 +5225,7 @@ HWTEST_F(ActsBmsKitSystemTest, GetAbilityIcon_0200, Function | MediumTest | Leve sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string icon = bundleMgrProxy->GetAbilityIcon(appName, abilityName); EXPECT_EQ(icon, "$media:icon"); @@ -5277,19 +5261,19 @@ HWTEST_F(ActsBmsKitSystemTest, GetAbilityIcon_0300, Function | MediumTest | Leve CommonTool commonTool; Install(bundleFilePath, InstallFlag::NORMAL, resvec); std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; resvec.clear(); std::string appName2 = BASE_BUNDLE_NAME + "2"; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string icon = bundleMgrProxy->GetAbilityIcon(appName2, abilityName); EXPECT_EQ(icon, Constants::EMPTY_STRING); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (icon.compare(Constants::EMPTY_STRING) != 0) { APP_LOGI("GetAbilityIcon_0300 failed - cycle count: %{public}d", i); break; @@ -5323,18 +5307,18 @@ HWTEST_F(ActsBmsKitSystemTest, GetAbilityIcon_0400, Function | MediumTest | Leve CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string icon = bundleMgrProxy->GetAbilityIcon(appName, abilityName); EXPECT_EQ(icon, Constants::EMPTY_STRING); resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (icon.compare(Constants::EMPTY_STRING) != 0) { APP_LOGI("GetAbilityIcon_0400 failed - cycle count: %{public}d", i); break; @@ -5367,12 +5351,12 @@ HWTEST_F(ActsBmsKitSystemTest, SetAbilityEnabled_0100, Function | MediumTest | L Install(bundleFilePath, InstallFlag::NORMAL, resvec); CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; BundleInfo bundleInfo; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool ret = bundleMgrProxy->GetBundleInfo(appName, BundleFlag::GET_BUNDLE_WITH_ABILITIES, bundleInfo); EXPECT_TRUE(ret); @@ -5383,7 +5367,7 @@ HWTEST_F(ActsBmsKitSystemTest, SetAbilityEnabled_0100, Function | MediumTest | L resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!ret) { APP_LOGI("SetAbilityEnabled_0100 failed - cycle count: %{public}d", i); @@ -5418,14 +5402,14 @@ HWTEST_F(ActsBmsKitSystemTest, SetAbilityEnabled_0200, Function | MediumTest | L Install(bundleFilePath, InstallFlag::NORMAL, resvec); CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; AbilityInfo abilityInfo; abilityInfo.bundleName = BASE_BUNDLE_NAME + "2"; abilityInfo.name = "bmsThirdBundle_A1"; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool ret = bundleMgrProxy->SetAbilityEnabled(abilityInfo, false); EXPECT_FALSE(ret); @@ -5434,7 +5418,7 @@ HWTEST_F(ActsBmsKitSystemTest, SetAbilityEnabled_0200, Function | MediumTest | L resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (ret) { APP_LOGI("SetAbilityEnabled_0200 failed - cycle count: %{public}d", i); break; @@ -5463,7 +5447,7 @@ HWTEST_F(ActsBmsKitSystemTest, SetAbilityEnabled_0300, Function | MediumTest | L sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } AbilityInfo abilityInfo; abilityInfo.bundleName = appName; @@ -5507,12 +5491,12 @@ HWTEST_F(ActsBmsKitSystemTest, IsAbilityEnabled_0100, Function | MediumTest | Le Install(bundleFilePath, InstallFlag::NORMAL, resvec); CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; BundleInfo bundleInfo; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool ret = bundleMgrProxy->GetBundleInfo(appName, BundleFlag::GET_BUNDLE_WITH_ABILITIES, bundleInfo); EXPECT_TRUE(ret); @@ -5523,7 +5507,7 @@ HWTEST_F(ActsBmsKitSystemTest, IsAbilityEnabled_0100, Function | MediumTest | Le resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!ret) { APP_LOGI("IsAbilityEnabled_0100 failed - cycle count: %{public}d", i); break; @@ -5556,21 +5540,21 @@ HWTEST_F(ActsBmsKitSystemTest, IsAbilityEnabled_0200, Function | MediumTest | Le Install(bundleFilePath, InstallFlag::NORMAL, resvec); CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; AbilityInfo abilityInfo; abilityInfo.bundleName = BASE_BUNDLE_NAME + "1"; abilityInfo.name = "bmsThirdBundle_A3"; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool ret = bundleMgrProxy->IsAbilityEnabled(abilityInfo); EXPECT_FALSE(ret); resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (ret) { APP_LOGI("IsAbilityEnabled_0200 failed - cycle count: %{public}d", i); @@ -5601,7 +5585,7 @@ HWTEST_F(ActsBmsKitSystemTest, IsAbilityEnabled_0300, Function | MediumTest | Le sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } AbilityInfo abilityInfo; abilityInfo.bundleName = appName; @@ -5648,7 +5632,7 @@ HWTEST_F(ActsBmsKitSystemTest, SetApplicationEnabled_0100, Function | MediumTest sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool ret = bundleMgrProxy->SetApplicationEnabled(appName, false); EXPECT_TRUE(ret); @@ -5659,7 +5643,7 @@ HWTEST_F(ActsBmsKitSystemTest, SetApplicationEnabled_0100, Function | MediumTest std::string appName = BASE_BUNDLE_NAME + std::to_string(i); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; } if (!ret) { APP_LOGI("SetApplicationEnabled_0100 failed - cycle count: %{public}d", i); @@ -5698,7 +5682,7 @@ HWTEST_F(ActsBmsKitSystemTest, SetApplicationEnabled_0200, Function | MediumTest sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string bundleName = BASE_BUNDLE_NAME + "2"; bool ret = bundleMgrProxy->SetApplicationEnabled(bundleName, false); @@ -5707,7 +5691,7 @@ HWTEST_F(ActsBmsKitSystemTest, SetApplicationEnabled_0200, Function | MediumTest EXPECT_FALSE(ret); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (ret) { APP_LOGI("SetApplicationEnabled_0200 failed - cycle count: %{public}d", i); break; @@ -5735,7 +5719,7 @@ HWTEST_F(ActsBmsKitSystemTest, SetApplicationEnabled_0300, Function | MediumTest sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool ret = bundleMgrProxy->SetApplicationEnabled(SYSTEM_SETTINGS_BUNDLE_NAME, false); EXPECT_TRUE(ret); @@ -5775,18 +5759,18 @@ HWTEST_F(ActsBmsKitSystemTest, IsApplicationEnabled_0100, Function | MediumTest Install(bundleFilePath, InstallFlag::NORMAL, resvec); CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool ret = bundleMgrProxy->IsApplicationEnabled(appName); EXPECT_TRUE(ret); resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (!ret) { APP_LOGI("IsApplicationEnabled_0100 failed - cycle count: %{public}d", i); break; @@ -5819,19 +5803,19 @@ HWTEST_F(ActsBmsKitSystemTest, IsApplicationEnabled_0200, Function | MediumTest Install(bundleFilePath, InstallFlag::NORMAL, resvec); CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; std::string appName2 = BASE_BUNDLE_NAME + "2"; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool ret = bundleMgrProxy->IsApplicationEnabled(appName2); EXPECT_FALSE(ret); resvec.clear(); Uninstall(appName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; if (ret) { APP_LOGI("IsApplicationEnabled_0200 failed - cycle count: %{public}d", i); break; @@ -5859,7 +5843,7 @@ HWTEST_F(ActsBmsKitSystemTest, IsApplicationEnabled_0300, Function | MediumTest sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool ret = bundleMgrProxy->IsApplicationEnabled(SYSTEM_SETTINGS_BUNDLE_NAME); EXPECT_TRUE(ret); diff --git a/test/systemtest/common/bms/bms_install_system_test/BUILD.gn b/test/systemtest/common/bms/bms_install_system_test/BUILD.gn index a7b274ab64..0aba582287 100755 --- a/test/systemtest/common/bms/bms_install_system_test/BUILD.gn +++ b/test/systemtest/common/bms/bms_install_system_test/BUILD.gn @@ -49,5 +49,5 @@ ohos_systemtest("BmsInstallSystemTest") { group("systemtest") { testonly = true - deps = [] + deps = [ ":BmsInstallSystemTest" ] } diff --git a/test/systemtest/common/bms/bms_install_system_test/bms_install_system_test.cpp b/test/systemtest/common/bms/bms_install_system_test/bms_install_system_test.cpp index 6fdce038c8..b018a324f7 100755 --- a/test/systemtest/common/bms/bms_install_system_test/bms_install_system_test.cpp +++ b/test/systemtest/common/bms/bms_install_system_test/bms_install_system_test.cpp @@ -199,9 +199,9 @@ void BmsInstallSystemTest::InstallBundle( installParam.userId = userId; } sptr statusReceiver(new (std::nothrow) StatusReceiverImpl()); - ASSERT_NE(statusReceiver, nullptr); + EXPECT_NE(statusReceiver, nullptr); bool installResult = installerProxy->Install(bundleFilePath, installParam, statusReceiver); - ASSERT_TRUE(installResult); + EXPECT_TRUE(installResult); installMsg = statusReceiver->GetResultMsg(); } @@ -215,9 +215,9 @@ void BmsInstallSystemTest::InstallMultiBundle(const std::string bundleFilePath, InstallParam installParam; installParam.installFlag = (InstallFlag)installFlag; sptr statusReceiver(new (std::nothrow) StatusReceiverImpl()); - ASSERT_NE(statusReceiver, nullptr); + EXPECT_NE(statusReceiver, nullptr); bool installResult = installerProxy->Install(bundleFilePath, installParam, statusReceiver); - ASSERT_TRUE(installResult); + EXPECT_TRUE(installResult); APP_LOGI("Install MSG: %{public}s", statusReceiver->GetResultMsg().c_str()); } @@ -232,13 +232,13 @@ void BmsInstallSystemTest::UninstallBundle( } sptr statusReceiver(new (std::nothrow) StatusReceiverImpl()); - ASSERT_NE(statusReceiver, nullptr); + EXPECT_NE(statusReceiver, nullptr); InstallParam installParam; if (userId != 0) { installParam.userId = userId; } bool uninstallResult = installerProxy->Uninstall(bundleName, installParam, statusReceiver); - ASSERT_TRUE(uninstallResult); + EXPECT_TRUE(uninstallResult); uninstallMsg = statusReceiver->GetResultMsg(); } @@ -255,10 +255,10 @@ void BmsInstallSystemTest::CheckBundleInfo(const std::string &version, const std sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool isGetInfoSuccess = bundleMgrProxy->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); - ASSERT_TRUE(isGetInfoSuccess); + EXPECT_TRUE(isGetInfoSuccess); EXPECT_EQ(bundleInfo.name, bundleName); EXPECT_EQ(bundleInfo.versionName, version); } @@ -299,7 +299,7 @@ void BmsInstallSystemTest::CheckInstallIsSuccess( void BmsInstallSystemTest::CheckFileNonExist(const std::string &bundleName) const { int bundleDataExist = access((DATA_ROOT_PATH + bundleName).c_str(), F_OK); - ASSERT_NE(bundleDataExist, 0) << "the bundle data dir exists: " << bundleName; + EXPECT_NE(bundleDataExist, 0) << "the bundle data dir exists: " << bundleName; int codeExist = access((CODE_ROOT_PATH + bundleName).c_str(), F_OK); EXPECT_NE(codeExist, 0) << "the bundle code dir exists: " << bundleName; } @@ -341,7 +341,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_0100, Function | MediumTest | Level1) std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1.hap"; std::string installMsg; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; std::string modulePackage = THIRD_BASE_BUNDLE_NAME + ".h1"; @@ -352,7 +352,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_0100, Function | MediumTest | Level1) std::string uninstallMsg; UninstallBundle(bundleName, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; + EXPECT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; std::cout << "END BMS_Install_0100" << std::endl; } @@ -372,7 +372,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_0200, Function | MediumTest | Level2) std::string installMsg; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!"; + EXPECT_EQ(installMsg, "Success") << "install fail!"; std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; CheckInstallIsSuccess(bundleName, modulePackage, abilityNames); @@ -388,7 +388,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_0200, Function | MediumTest | Level2) std::string uninstallMsg; UninstallBundle(bundleName, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; + EXPECT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; std::cout << "END BMS_Install_0200" << std::endl; } @@ -421,7 +421,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_0300, Function | MediumTest | Level1) std::string uninstallMsg; UninstallBundle(bundleName, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success"); + EXPECT_EQ(uninstallMsg, "Success"); } std::cout << "END BMS_Install_0300" << std::endl; } @@ -439,7 +439,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_0400, Function | MediumTest | Level1) std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle13.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!"; + EXPECT_EQ(installMsg, "Success") << "install fail!"; std::string bundleName = THIRD_BASE_BUNDLE_NAME + "5"; std::string modulePackage = THIRD_BASE_BUNDLE_NAME + ".h1"; @@ -453,7 +453,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_0400, Function | MediumTest | Level1) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGI("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getInfosResult = bundleMgrProxy->GetBundleInfos(BundleFlag::GET_BUNDLE_DEFAULT, bundleInfos); EXPECT_TRUE(getInfosResult); @@ -468,7 +468,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_0400, Function | MediumTest | Level1) EXPECT_TRUE(isSubStrExist); std::string uninstallMsg; UninstallBundle(bundleName, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; + EXPECT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; std::cout << "END BMS_Install_0400" << std::endl; } @@ -487,7 +487,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_0500, Function | MediumTest | Level2) std::string installMsg; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!"; + EXPECT_EQ(installMsg, "Success") << "install fail!"; std::string bundleName = THIRD_BASE_BUNDLE_NAME + "2"; std::string modulePackage = THIRD_BASE_BUNDLE_NAME + ".h2"; @@ -496,12 +496,12 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_0500, Function | MediumTest | Level2) bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle7.hap"; InstallBundle(bundleFilePath, InstallFlag::REPLACE_EXISTING, installMsg); - ASSERT_EQ(installMsg, "Failure[ERR_INSTALL_VERSION_DOWNGRADE]"); + EXPECT_EQ(installMsg, "Failure[ERR_INSTALL_VERSION_DOWNGRADE]"); CheckInstallIsSuccess(bundleName, modulePackage, abilityNames); std::string uninstallMsg; UninstallBundle(bundleName, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; + EXPECT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; std::cout << "END BMS_Install_0500" << std::endl; } @@ -520,7 +520,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_0600, Function | MediumTest | Level1) std::string installMsg; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!"; + EXPECT_EQ(installMsg, "Success") << "install fail!"; std::string bundleName = THIRD_BASE_BUNDLE_NAME + "2"; std::string modulePackage = THIRD_BASE_BUNDLE_NAME + ".h2"; @@ -530,7 +530,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_0600, Function | MediumTest | Level1) std::string bundleReFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle9.hap"; std::this_thread::sleep_for(50ms); InstallBundle(bundleReFilePath, InstallFlag::REPLACE_EXISTING, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!"; + EXPECT_EQ(installMsg, "Success") << "install fail!"; CheckInstallIsSuccess(bundleName, modulePackage, abilityNames); @@ -538,7 +538,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_0600, Function | MediumTest | Level1) CheckBundleInfo(version, bundleName); std::string uninstallMsg; UninstallBundle(bundleName, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; + EXPECT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; std::cout << "END BMS_Install_0600" << std::endl; } @@ -561,7 +561,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_0700, Function | MediumTest | Level2) int32_t size = bundlePaths.size(); for (int i = 0; i < size; i++) { InstallBundle(bundlePaths[i], InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, errorCodes[i]); + EXPECT_EQ(installMsg, errorCodes[i]); CheckFileNonExist(bundleNames[i]); } @@ -569,7 +569,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_0700, Function | MediumTest | Level2) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bundleMgrProxy->GetBundleInfos(BundleFlag::GET_BUNDLE_DEFAULT, bundleInfos); @@ -599,9 +599,9 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_0800, Function | MediumTest | Level2) std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle14.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Failure[ERR_INSTALL_PARSE_PROFILE_MISSING_PROP]"); + EXPECT_EQ(installMsg, "Failure[ERR_INSTALL_PARSE_PROFILE_MISSING_PROP]"); InstallBundle(bundleFilePath, InstallFlag::REPLACE_EXISTING, installMsg); - ASSERT_EQ(installMsg, "Failure[ERR_INSTALL_PARSE_PROFILE_MISSING_PROP]"); + EXPECT_EQ(installMsg, "Failure[ERR_INSTALL_PARSE_PROFILE_MISSING_PROP]"); std::string bundleName = THIRD_BASE_BUNDLE_NAME + "14"; @@ -609,7 +609,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_0800, Function | MediumTest | Level2) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getInfoResult = bundleMgrProxy->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); EXPECT_FALSE(getInfoResult); @@ -628,10 +628,10 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_0900, Function | MediumTest | Level2) std::string installMsg; std::string bundleFilePath = THIRD_BUNDLE_PATH + "notexist.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Failure[MSG_ERR_INSTALL_FILE_PATH_INVALID]"); + EXPECT_EQ(installMsg, "Failure[MSG_ERR_INSTALL_FILE_PATH_INVALID]"); InstallBundle(bundleFilePath, InstallFlag::REPLACE_EXISTING, installMsg); - ASSERT_EQ(installMsg, "Failure[MSG_ERR_INSTALL_FILE_PATH_INVALID]"); + EXPECT_EQ(installMsg, "Failure[MSG_ERR_INSTALL_FILE_PATH_INVALID]"); std::cout << "END BMS_Install_0900" << std::endl; } @@ -648,7 +648,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_1000, Function | MediumTest | Level2) std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundleNoSign.hap"; std::string installMsg; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Failure[ERR_INSTALL_NO_SIGNATURE_INFO]"); + EXPECT_EQ(installMsg, "Failure[ERR_INSTALL_NO_SIGNATURE_INFO]"); std::string bundleName = "com.third.hiworld.example1"; CheckFileNonExist(bundleName); @@ -670,7 +670,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_1100, Function | MediumTest | Level1) std::string installMsg; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; std::string modulePackage = THIRD_BASE_BUNDLE_NAME + ".h2"; std::vector hap2AbilityNames = {"bmsThirdBundle_A1", "bmsThirdBundle_A2"}; @@ -679,7 +679,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_1100, Function | MediumTest | Level1) bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; modulePackage = THIRD_BASE_BUNDLE_NAME + ".h1"; std::vector hap1AbilityNames = {"bmsThirdBundle_A1"}; @@ -689,7 +689,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_1100, Function | MediumTest | Level1) CheckBundleInfo(version, bundleName); std::string uninstallMsg; UninstallBundle(bundleName, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; + EXPECT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; std::cout << "END BMS_Install_1100" << std::endl; } @@ -708,7 +708,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_1200, Function | MediumTest | Level1) InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; std::string modulePackage = THIRD_BASE_BUNDLE_NAME + ".h1"; @@ -719,7 +719,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_1200, Function | MediumTest | Level1) CheckBundleInfo(version, bundleName); std::string uninstallMsg; UninstallBundle(bundleName, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; + EXPECT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; std::cout << "END BMS_Install_1200" << std::endl; } @@ -738,7 +738,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_1300, Function | MediumTest | Level1) InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; std::string modulePackage = THIRD_BASE_BUNDLE_NAME + ".h1"; @@ -749,7 +749,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_1300, Function | MediumTest | Level1) CheckBundleInfo(version, bundleName); std::string uninstallMsg; UninstallBundle(bundleName, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; + EXPECT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; std::cout << "END BMS_Install_1300" << std::endl; } @@ -768,7 +768,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_1400, Function | MediumTest | Level1) InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; std::string modulePackage = THIRD_BASE_BUNDLE_NAME + ".h1"; @@ -779,7 +779,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_1400, Function | MediumTest | Level1) CheckBundleInfo(version, bundleName); std::string uninstallMsg; UninstallBundle(bundleName, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; + EXPECT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; std::cout << "END BMS_Install_1400" << std::endl; } @@ -797,12 +797,12 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_1500, Function | MediumTest | Level1) std::string installMsg; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle42.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success"); + EXPECT_EQ(installMsg, "Success"); std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; std::string modulePackage = THIRD_BASE_BUNDLE_NAME + ".h1"; @@ -813,7 +813,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_1500, Function | MediumTest | Level1) CheckBundleInfo(version, bundleName); std::string uninstallMsg; UninstallBundle(bundleName, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; + EXPECT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; std::cout << "END BMS_Install_1500" << std::endl; } @@ -832,12 +832,12 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_1600, Function | MediumTest | Level1) std::string installMsg; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle4.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; std::string modulePackage = THIRD_BASE_BUNDLE_NAME + ".h1"; @@ -852,7 +852,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_1600, Function | MediumTest | Level1) CheckBundleInfo(version, bundleName); std::string uninstallMsg; UninstallBundle(bundleName, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; + EXPECT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; std::cout << "END BMS_Install_1600" << std::endl; } @@ -871,12 +871,12 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_1700, Function | MediumTest | Level1) std::string installMsg; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle5.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; std::string modulePackage = THIRD_BASE_BUNDLE_NAME + ".h1"; @@ -891,7 +891,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_1700, Function | MediumTest | Level1) CheckBundleInfo(version, bundleName); std::string uninstallMsg; UninstallBundle(bundleName, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; + EXPECT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; std::cout << "END BMS_Install_1700" << std::endl; } @@ -910,12 +910,12 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_1800, Function | MediumTest | Level1) std::string installMsg; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle42.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success"); + EXPECT_EQ(installMsg, "Success"); std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; std::string modulePackage = THIRD_BASE_BUNDLE_NAME + ".h1"; @@ -923,7 +923,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_1800, Function | MediumTest | Level1) CheckInstallIsSuccess(bundleName, modulePackage, hap1AbilityNames); std::string uninstallMsg; UninstallBundle(bundleName, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; + EXPECT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; std::cout << "END BMS_Install_1800" << std::endl; } @@ -941,12 +941,12 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_1900, Function | MediumTest | Level1) std::string installMsg; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle4.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; std::string modulePackage = THIRD_BASE_BUNDLE_NAME + ".h1"; @@ -961,7 +961,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_1900, Function | MediumTest | Level1) CheckBundleInfo(version, bundleName); std::string uninstallMsg; UninstallBundle(bundleName, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; + EXPECT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; std::cout << "END BMS_Install_1900" << std::endl; } @@ -980,12 +980,12 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_2000, Function | MediumTest | Level1) std::string installMsg; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle5.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; std::string modulePackage = THIRD_BASE_BUNDLE_NAME + ".h1"; @@ -1000,7 +1000,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_2000, Function | MediumTest | Level1) CheckBundleInfo(version, bundleName); std::string uninstallMsg; UninstallBundle(bundleName, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; + EXPECT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; std::cout << "END BMS_Install_2000" << std::endl; } @@ -1019,12 +1019,12 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_2100, Function | MediumTest | Level1) std::string installMsg; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle6.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Failure[MSG_ERR_INSTALL_ENTRY_ALREADY_EXIST]"); + EXPECT_EQ(installMsg, "Failure[MSG_ERR_INSTALL_ENTRY_ALREADY_EXIST]"); std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; std::string modulePackage = THIRD_BASE_BUNDLE_NAME + ".h1"; @@ -1035,7 +1035,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_2100, Function | MediumTest | Level1) CheckBundleInfo(version, bundleName); std::string uninstallMsg; UninstallBundle(bundleName, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; + EXPECT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; std::cout << "START BMS_Install_2100" << std::endl; } @@ -1054,12 +1054,12 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_2200, Function | MediumTest | Level1) std::string installMsg; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle4.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; std::string modulePackage = THIRD_BASE_BUNDLE_NAME + ".h1"; @@ -1074,7 +1074,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_2200, Function | MediumTest | Level1) CheckBundleInfo(version, bundleName); std::string uninstallMsg; UninstallBundle(bundleName, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; + EXPECT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; std::cout << "START BMS_Install_2200" << std::endl; } @@ -1092,12 +1092,12 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_2300, Function | MediumTest | Level1) std::string installMsg; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle5.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; std::string modulePackage = THIRD_BASE_BUNDLE_NAME + ".h1"; @@ -1113,7 +1113,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_2300, Function | MediumTest | Level1) std::string uninstallMsg; UninstallBundle(bundleName, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; + EXPECT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; std::cout << "END BMS_Install_2300" << std::endl; } @@ -1131,14 +1131,14 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_2400, Function | MediumTest | Level2) std::string bundleFilePath = THIRD_BUNDLE_PATH + "e23.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Failure[ERR_INSTALL_PARSE_PROFILE_PROP_CHECK_ERROR]"); + EXPECT_EQ(installMsg, "Failure[ERR_INSTALL_PARSE_PROFILE_PROP_CHECK_ERROR]"); std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; BundleInfo bundleInfo; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getInfoResult = bundleMgrProxy->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); EXPECT_FALSE(getInfoResult); @@ -1157,7 +1157,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_2500, Function | MediumTest | Level2) std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1.hap"; std::string installMsg; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; std::string modulePackage = THIRD_BASE_BUNDLE_NAME + ".h1"; @@ -1168,7 +1168,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_2500, Function | MediumTest | Level2) std::string bundleFilePath2 = THIRD_BUNDLE_PATH + "e14.hap"; InstallBundle(bundleFilePath2, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Failure[ERR_INSTALL_PARSE_PROFILE_PROP_CHECK_ERROR]"); + EXPECT_EQ(installMsg, "Failure[ERR_INSTALL_PARSE_PROFILE_PROP_CHECK_ERROR]"); std::string uninstallMsg; UninstallBundle(bundleName, uninstallMsg); @@ -1189,14 +1189,14 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_2600, Function | MediumTest | Level2) std::string bundleFilePath = THIRD_BUNDLE_PATH + "e22.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Failure[ERR_INSTALL_PARSE_PROFILE_PROP_CHECK_ERROR]"); + EXPECT_EQ(installMsg, "Failure[ERR_INSTALL_PARSE_PROFILE_PROP_CHECK_ERROR]"); std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; BundleInfo bundleInfo; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getInfoResult = bundleMgrProxy->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); EXPECT_FALSE(getInfoResult); @@ -1215,7 +1215,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_2700, Function | MediumTest | Level1) std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle41.hap"; std::string installMsg; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; std::string modulePackage = THIRD_BASE_BUNDLE_NAME + ".h1"; @@ -1227,7 +1227,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_2700, Function | MediumTest | Level1) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } BundleInfo bundleInfo; @@ -1268,14 +1268,14 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_2800, Function | MediumTest | Level2) std::string bundleFilePath = THIRD_BUNDLE_PATH + "e3.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Failure[ERR_INSTALL_PARSE_PROFILE_PROP_CHECK_ERROR]"); + EXPECT_EQ(installMsg, "Failure[ERR_INSTALL_PARSE_PROFILE_PROP_CHECK_ERROR]"); std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; BundleInfo bundleInfo; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getInfoResult = bundleMgrProxy->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); EXPECT_FALSE(getInfoResult); @@ -1296,14 +1296,14 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_2900, Function | MediumTest | Level2) std::string bundleFilePath = THIRD_BUNDLE_PATH + "e21.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Failure[ERR_INSTALL_PARSE_PROFILE_PROP_CHECK_ERROR]"); + EXPECT_EQ(installMsg, "Failure[ERR_INSTALL_PARSE_PROFILE_PROP_CHECK_ERROR]"); std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; BundleInfo bundleInfo; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getInfoResult = bundleMgrProxy->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); EXPECT_FALSE(getInfoResult); @@ -1324,17 +1324,17 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_3000, Function | MediumTest | Level2) std::string bundleFilePath = THIRD_BUNDLE_PATH + "e14.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Failure[ERR_INSTALL_PARSE_PROFILE_PROP_CHECK_ERROR]"); + EXPECT_EQ(installMsg, "Failure[ERR_INSTALL_PARSE_PROFILE_PROP_CHECK_ERROR]"); std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; BundleInfo bundleInfo; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getInfoResult = bundleMgrProxy->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); - ASSERT_FALSE(getInfoResult); + EXPECT_FALSE(getInfoResult); std::cout << "END BMS_Install_3000" << std::endl; } @@ -1352,14 +1352,14 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_3100, Function | MediumTest | Level2) std::string bundleFilePath = THIRD_BUNDLE_PATH + "e12.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Failure[ERR_INSTALL_PARSE_PROFILE_PROP_CHECK_ERROR]"); + EXPECT_EQ(installMsg, "Failure[ERR_INSTALL_PARSE_PROFILE_PROP_CHECK_ERROR]"); std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; BundleInfo bundleInfo; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getInfoResult = bundleMgrProxy->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); EXPECT_FALSE(getInfoResult); @@ -1380,7 +1380,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_3200, Function | MediumTest | Level1) std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1.hap"; std::string installMsg; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; std::string modulePackage = THIRD_BASE_BUNDLE_NAME + ".h1"; @@ -1391,7 +1391,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_3200, Function | MediumTest | Level1) bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle7.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; std::string bundleName2 = THIRD_BASE_BUNDLE_NAME + "2"; modulePackage = THIRD_BASE_BUNDLE_NAME + ".h2"; @@ -1425,7 +1425,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_3300, Function | MediumTest | Level2) std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundles1.hap"; std::string installMsg; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Failure[ERR_INSTALL_ALREADY_EXIST]") << "Success!" << bundleFilePath; + EXPECT_EQ(installMsg, "Failure[ERR_INSTALL_ALREADY_EXIST]") << "Success!" << bundleFilePath; std::cout << "END BMS_Install_3300" << std::endl; } @@ -1443,14 +1443,14 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_3400, Function | MediumTest | Level2) std::string bundleFilePath = THIRD_BUNDLE_PATH + "e4.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Failure[ERR_INSTALL_PARSE_PROFILE_PROP_TYPE_ERROR]"); + EXPECT_EQ(installMsg, "Failure[ERR_INSTALL_PARSE_PROFILE_PROP_TYPE_ERROR]"); std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; BundleInfo bundleInfo; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getInfoResult = bundleMgrProxy->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); EXPECT_FALSE(getInfoResult); @@ -1471,14 +1471,14 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_3500, Function | MediumTest | Level2) std::string bundleFilePath = THIRD_BUNDLE_PATH + "e5.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Failure[ERR_INSTALL_PARSE_PROFILE_PROP_CHECK_ERROR]"); + EXPECT_EQ(installMsg, "Failure[ERR_INSTALL_PARSE_PROFILE_PROP_CHECK_ERROR]"); std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; BundleInfo bundleInfo; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getInfoResult = bundleMgrProxy->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); EXPECT_FALSE(getInfoResult); @@ -1499,14 +1499,14 @@ HWTEST_F(BmsInstallSystemTest, BMS_Install_3600, Function | MediumTest | Level2) std::string bundleFilePath = THIRD_BUNDLE_PATH + "e6.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Failure[ERR_INSTALL_PARSE_BAD_PROFILE]"); + EXPECT_EQ(installMsg, "Failure[ERR_INSTALL_PARSE_BAD_PROFILE]"); std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; BundleInfo bundleInfo; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getInfoResult = bundleMgrProxy->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); EXPECT_FALSE(getInfoResult); @@ -1525,7 +1525,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_InstallProgressInfo_0100, Function | MediumTe std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1.hap"; std::string installMsg; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; std::string modulePackage = THIRD_BASE_BUNDLE_NAME + ".h1"; @@ -1575,7 +1575,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_MultiHapInstall_0100, Function | MediumTest | sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getInfosResult = bundleMgrProxy->GetBundleInfos(BundleFlag::GET_BUNDLE_DEFAULT, bundleInfos); EXPECT_TRUE(getInfosResult); @@ -1718,7 +1718,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_SystemAppInstall_0300, Function | MediumTest sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::vector bundleInfos; @@ -1765,7 +1765,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Upgrade_0100, Function | MediumTest | Level1) std::string installMsg; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success"); + EXPECT_EQ(installMsg, "Success"); std::string bundleName = THIRD_BASE_BUNDLE_NAME + "2"; std::string modulePackage = THIRD_BASE_BUNDLE_NAME + ".h2"; @@ -1775,7 +1775,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Upgrade_0100, Function | MediumTest | Level1) std::this_thread::sleep_for(50ms); bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle9.hap"; InstallBundle(bundleFilePath, InstallFlag::REPLACE_EXISTING, installMsg); - ASSERT_EQ(installMsg, "Success"); + EXPECT_EQ(installMsg, "Success"); std::string version = "3.0"; hap1AbilityNames = {"bmsThirdBundle_A1"}; @@ -1802,7 +1802,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Upgrade_0200, Function | MediumTest | Level1) std::string installMsg; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success"); + EXPECT_EQ(installMsg, "Success"); std::string bundleName = THIRD_BASE_BUNDLE_NAME + "2"; std::string modulePackage = THIRD_BASE_BUNDLE_NAME + ".h2"; @@ -1812,7 +1812,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Upgrade_0200, Function | MediumTest | Level1) std::this_thread::sleep_for(50ms); bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle10.hap"; InstallBundle(bundleFilePath, InstallFlag::REPLACE_EXISTING, installMsg); - ASSERT_EQ(installMsg, "Success"); + EXPECT_EQ(installMsg, "Success"); std::string version = "1.0"; CheckBundleInfo(version, bundleName); @@ -1838,7 +1838,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Upgrade_0300, Function | MediumTest | Level2) std::string installMsg; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success"); + EXPECT_EQ(installMsg, "Success"); std::string bundleName = THIRD_BASE_BUNDLE_NAME + "2"; std::string modulePackage = THIRD_BASE_BUNDLE_NAME + ".h2"; @@ -1847,7 +1847,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Upgrade_0300, Function | MediumTest | Level2) bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle7.hap"; InstallBundle(bundleFilePath, InstallFlag::REPLACE_EXISTING, installMsg); - ASSERT_EQ(installMsg, "Failure[ERR_INSTALL_VERSION_DOWNGRADE]"); + EXPECT_EQ(installMsg, "Failure[ERR_INSTALL_VERSION_DOWNGRADE]"); std::string version = "3.0"; CheckBundleInfo(version, bundleName); @@ -1874,7 +1874,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Upgrade_0400, Function | MediumTest | Level1) std::string installMsg; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success"); + EXPECT_EQ(installMsg, "Success"); std::string bundleName = THIRD_BASE_BUNDLE_NAME + "2"; std::string modulePackage = THIRD_BASE_BUNDLE_NAME + ".h2"; @@ -1888,7 +1888,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_Upgrade_0400, Function | MediumTest | Level1) std::this_thread::sleep_for(50ms); bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle9.hap"; InstallBundle(bundleFilePath, InstallFlag::REPLACE_EXISTING, installMsg); - ASSERT_EQ(installMsg, "Success"); + EXPECT_EQ(installMsg, "Success"); CheckInstallIsSuccess(bundleName, modulePackage, hap1AbilityNames); std::string uninstallMsg; @@ -1994,7 +1994,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_BundleDataStorage_0100, Function | MediumTest InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!"; + EXPECT_EQ(installMsg, "Success") << "install fail!"; std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; std::string modulePackage = THIRD_BASE_BUNDLE_NAME + ".h1"; @@ -2004,7 +2004,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_BundleDataStorage_0100, Function | MediumTest sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } BundleInfo bundleInfo; bool isGetInfoSuccess = bundleMgrProxy->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); @@ -2038,14 +2038,14 @@ HWTEST_F(BmsInstallSystemTest, BMS_BundleDataStorage_0200, Function | MediumTest sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string installMsg; std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle2.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success"); + EXPECT_EQ(installMsg, "Success"); std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; std::string modulePackage = THIRD_BASE_BUNDLE_NAME + ".h1"; @@ -2053,7 +2053,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_BundleDataStorage_0200, Function | MediumTest CheckInstallIsSuccess(bundleName, modulePackage, hap1AbilityNames); bool isGetInfoSuccess = bundleMgrProxy->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); - ASSERT_TRUE(isGetInfoSuccess); + EXPECT_TRUE(isGetInfoSuccess); EXPECT_EQ(bundleInfo.name, "com.third.hiworld.example1"); EXPECT_EQ(bundleInfo.vendor, "example"); @@ -2066,7 +2066,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_BundleDataStorage_0200, Function | MediumTest bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle11.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Failure[ERR_INSTALL_PARSE_NO_PROFILE]"); + EXPECT_EQ(installMsg, "Failure[ERR_INSTALL_PARSE_NO_PROFILE]"); std::string eBundleName = THIRD_BASE_BUNDLE_NAME + "11"; CheckFileNonExist(eBundleName); @@ -2095,22 +2095,22 @@ HWTEST_F(BmsInstallSystemTest, BMS_Broadcasting_0100, Function | MediumTest | Le CommonEventSubscribeInfo subscriberInfo(matchingSkillsObj); std::shared_ptr subScriber = std::make_shared(subscriberInfo); bool isSubscribeSuccess = CommonEventManager::SubscribeCommonEvent(subScriber); - ASSERT_TRUE(isSubscribeSuccess); + EXPECT_TRUE(isSubscribeSuccess); std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle2.hap"; std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; std::string installMsg; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!"; + EXPECT_EQ(installMsg, "Success") << "install fail!"; std::string subScriberResult = subScriber->GetSubscriberResultMsg(); EXPECT_EQ(subScriberResult, CommonEventSupport::COMMON_EVENT_PACKAGE_ADDED); bool isUnSubscribeSuccess = CommonEventManager::UnSubscribeCommonEvent(subScriber); - ASSERT_TRUE(isUnSubscribeSuccess); + EXPECT_TRUE(isUnSubscribeSuccess); std::string uninstallMsg; UninstallBundle(bundleName, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallMsg, "Success") << "uninstall fail!"; std::cout << "END BMS_Broadcasting_0100" << std::endl; } @@ -2129,26 +2129,26 @@ HWTEST_F(BmsInstallSystemTest, BMS_Broadcasting_0200, Function | MediumTest | Le CommonEventSubscribeInfo subScriberInfo(matchingSkillsObj); std::shared_ptr subScriber = std::make_shared(subScriberInfo); bool isSubscribeSuccess = CommonEventManager::SubscribeCommonEvent(subScriber); - ASSERT_TRUE(isSubscribeSuccess); + EXPECT_TRUE(isSubscribeSuccess); std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle7.hap"; std::string installMsg; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!"; + EXPECT_EQ(installMsg, "Success") << "install fail!"; std::string bundleName = THIRD_BASE_BUNDLE_NAME + "2"; std::string bundleReFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle9.hap"; std::this_thread::sleep_for(50ms); InstallBundle(bundleReFilePath, InstallFlag::REPLACE_EXISTING, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!"; + EXPECT_EQ(installMsg, "Success") << "install fail!"; std::string subScriberResult = subScriber->GetSubscriberResultMsg(); EXPECT_EQ(subScriberResult, CommonEventSupport::COMMON_EVENT_PACKAGE_CHANGED); std::string uninstallMsg; UninstallBundle(bundleName, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallMsg, "Success") << "uninstall fail!"; bool isUnSubscribeSuccess = CommonEventManager::UnSubscribeCommonEvent(subScriber); - ASSERT_TRUE(isUnSubscribeSuccess); + EXPECT_TRUE(isUnSubscribeSuccess); std::cout << "END BMS_Broadcasting_0200" << std::endl; } @@ -2167,21 +2167,21 @@ HWTEST_F(BmsInstallSystemTest, BMS_Broadcasting_0300, Function | MediumTest | Le CommonEventSubscribeInfo subscriberInfo(matchingSkillsObj); std::shared_ptr subScriber = std::make_shared(subscriberInfo); bool isSubscribeSuccess = CommonEventManager::SubscribeCommonEvent(subScriber); - ASSERT_TRUE(isSubscribeSuccess); + EXPECT_TRUE(isSubscribeSuccess); std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle2.hap"; std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; std::string installMsg; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!"; + EXPECT_EQ(installMsg, "Success") << "install fail!"; std::string uninstallMsg; UninstallBundle(bundleName, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallMsg, "Success") << "uninstall fail!"; std::string subScriberResult = subScriber->GetSubscriberResultMsg(); EXPECT_EQ(subScriberResult, CommonEventSupport::COMMON_EVENT_PACKAGE_REMOVED); bool isUnSubscribeSuccess = CommonEventManager::UnSubscribeCommonEvent(subScriber); - ASSERT_TRUE(isUnSubscribeSuccess); + EXPECT_TRUE(isUnSubscribeSuccess); std::cout << "END BMS_Broadcasting_0300" << std::endl; } @@ -2203,15 +2203,15 @@ HWTEST_F(BmsInstallSystemTest, BMS_Permission_0100, Function | MediumTest | Leve sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundlePermission1.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundlePermission2.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; std::string bundleName = "com.third.hiworld.example2"; std::string modulePackage = "com.third.hiworld.example.h2"; @@ -2220,12 +2220,12 @@ HWTEST_F(BmsInstallSystemTest, BMS_Permission_0100, Function | MediumTest | Leve std::string bundleName2 = "com.third.hiworld.example3"; std::string permissionName = "com.example.permission"; bool isGetInfoSuccess = bundleMgrProxy->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); - ASSERT_TRUE(isGetInfoSuccess); + EXPECT_TRUE(isGetInfoSuccess); EXPECT_EQ(commonTool.VectorToStr(bundleInfo.defPermissions), permissionName); CheckInstallIsSuccess(bundleName2, modulePackage, abilityNames); isGetInfoSuccess = bundleMgrProxy->GetBundleInfo(bundleName2, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); - ASSERT_TRUE(isGetInfoSuccess); + EXPECT_TRUE(isGetInfoSuccess); bool ret = bundleMgrProxy->CanRequestPermission(bundleName2, permissionName, userid); EXPECT_TRUE(ret); @@ -2234,9 +2234,9 @@ HWTEST_F(BmsInstallSystemTest, BMS_Permission_0100, Function | MediumTest | Leve std::string uninstallMsg; UninstallBundle(bundleName, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallMsg, "Success") << "uninstall fail!"; UninstallBundle(bundleName2, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallMsg, "Success") << "uninstall fail!"; std::cout << "END BMS_Permission_0100" << std::endl; } @@ -2258,15 +2258,15 @@ HWTEST_F(BmsInstallSystemTest, BMS_Permission_0200, Function | MediumTest | Leve sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle7.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle8.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; std::string bundleName = "com.third.hiworld.example2"; std::string modulePackage = "com.third.hiworld.example.h2"; @@ -2275,12 +2275,12 @@ HWTEST_F(BmsInstallSystemTest, BMS_Permission_0200, Function | MediumTest | Leve std::string bundleName2 = "com.third.hiworld.example3"; std::string permissionName = "com.example.permission"; bool isGetInfoSuccess = bundleMgrProxy->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); - ASSERT_TRUE(isGetInfoSuccess); + EXPECT_TRUE(isGetInfoSuccess); EXPECT_EQ(commonTool.VectorToStr(bundleInfo.defPermissions), permissionName); CheckInstallIsSuccess(bundleName2, modulePackage, abilityNames); isGetInfoSuccess = bundleMgrProxy->GetBundleInfo(bundleName2, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); - ASSERT_TRUE(isGetInfoSuccess); + EXPECT_TRUE(isGetInfoSuccess); bool ret = bundleMgrProxy->CanRequestPermission(bundleName2, permissionName, userid); EXPECT_FALSE(ret); ret = bundleMgrProxy->RequestPermissionFromUser(bundleName2, permissionName, userid); @@ -2290,9 +2290,9 @@ HWTEST_F(BmsInstallSystemTest, BMS_Permission_0200, Function | MediumTest | Leve std::string uninstallMsg; UninstallBundle(bundleName, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallMsg, "Success") << "uninstall fail!"; UninstallBundle(bundleName2, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallMsg, "Success") << "uninstall fail!"; std::cout << "END BMS_Permission_0200" << std::endl; } @@ -2311,15 +2311,15 @@ HWTEST_F(BmsInstallSystemTest, BMS_Permission_0300, Function | MediumTest | Leve sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundlePermission1.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundlePermission2.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; std::string bundleName = "com.third.hiworld.example2"; std::string modulePackage = "com.third.hiworld.example.h2"; @@ -2336,9 +2336,9 @@ HWTEST_F(BmsInstallSystemTest, BMS_Permission_0300, Function | MediumTest | Leve std::string uninstallMsg; UninstallBundle(bundleName, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; + EXPECT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; UninstallBundle(bundleName2, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; + EXPECT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; std::cout << "END BMS_Permission_0300" << std::endl; } @@ -2373,7 +2373,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_DFX_0200, Function | MediumTest | Level2) std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1.hap"; std::string installMsg; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; std::string modulePackage = THIRD_BASE_BUNDLE_NAME + ".h1"; @@ -2384,7 +2384,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_DFX_0200, Function | MediumTest | Level2) UninstallBundle(bundleName, uninstallMsg, Constants::INVALID_USERID); EXPECT_EQ(uninstallMsg, "Failure[ERR_UNINSTALL_PARAM_ERROR]"); UninstallBundle(bundleName, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(uninstallMsg, "Success") << "install fail!" << bundleFilePath; std::cout << "END BMS_DFX_0200" << std::endl; } @@ -2402,7 +2402,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_DFX_0300, Function | MediumTest | Level2) std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1.hap"; std::string installMsg; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath; std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; std::string errBundleName = ""; @@ -2414,7 +2414,7 @@ HWTEST_F(BmsInstallSystemTest, BMS_DFX_0300, Function | MediumTest | Level2) UninstallBundle(errBundleName, uninstallMsg); EXPECT_EQ(uninstallMsg, "Failure[ERR_UNINSTALL_INVALID_NAME]"); UninstallBundle(bundleName, uninstallMsg); - ASSERT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; + EXPECT_EQ(uninstallMsg, "Success") << "uninstall fail!" << bundleFilePath; std::cout << "END BMS_DFX_0300" << std::endl; } @@ -2432,14 +2432,14 @@ HWTEST_F(BmsInstallSystemTest, BMS_DFX_0400, Function | MediumTest | Level2) std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle43.hap"; InstallBundle(bundleFilePath, InstallFlag::NORMAL, installMsg); - ASSERT_EQ(installMsg, "Failure[ERR_INSTALL_INVALID_HAP_SIZE]"); + EXPECT_EQ(installMsg, "Failure[ERR_INSTALL_INVALID_HAP_SIZE]"); std::string bundleName = THIRD_BASE_BUNDLE_NAME + "big"; BundleInfo bundleInfo; sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getInfoResult = bundleMgrProxy->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); EXPECT_FALSE(getInfoResult); diff --git a/test/systemtest/common/bms/bms_launcher_service_system_test/BUILD.gn b/test/systemtest/common/bms/bms_launcher_service_system_test/BUILD.gn new file mode 100644 index 0000000000..c672c8b6a0 --- /dev/null +++ b/test/systemtest/common/bms/bms_launcher_service_system_test/BUILD.gn @@ -0,0 +1,65 @@ +# Copyright (c) 2021 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/appexecfwk/standard/appexecfwk.gni") +module_output_path = "appexecfwk_standard/bundlemgrsst" + +ohos_systemtest("BmsLauncherServiceSystemTest") { + module_out_path = module_output_path + + configs = [ "${libs_path}/libeventhandler:libeventhandler_config" ] + + include_dirs = [ + "//foundation/aafwk/standard/interfaces/innerkits/want/include/ohos/aafwk/content/", + "${services_path}/bundlemgr/include", + ] + + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${common_path}:libappexecfwk_common", + "${libs_path}/libeventhandler:libeventhandler_target", + "${services_path}/bundlemgr:libbms", + "${services_path}/test/moduletest/utils:tool_common", + "//base/security/appverify/interfaces/innerkits/appverify:libhapverify", + "//base/security/permission/interfaces/innerkits/permission_standard/permissionsdk:libpermissionsdk_standard", + "//foundation/aafwk/standard/interfaces/innerkits/ability_manager:ability_manager", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/distributeddatamgr/distributeddatamgr/interfaces/innerkits/distributeddata:distributeddata_inner", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + ] + sources = [ "bms_launcher_service_system_test.cpp" ] + + defines = [ "APP_LOG_TAG = \"BundleMgrTool\"" ] + + external_deps = [ + "ces_standard:cesfwk_innerkits", + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("systemtest") { + testonly = true + + deps = [ ":BmsLauncherServiceSystemTest" ] +} diff --git a/test/systemtest/common/bms/bms_launcher_service_system_test/bms_launcher_service_system_test.cpp b/test/systemtest/common/bms/bms_launcher_service_system_test/bms_launcher_service_system_test.cpp new file mode 100644 index 0000000000..e503c647a4 --- /dev/null +++ b/test/systemtest/common/bms/bms_launcher_service_system_test/bms_launcher_service_system_test.cpp @@ -0,0 +1,1301 @@ +/* + * Copyright (c) 2021 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 +#include +#include +#include + +#include "app_log_wrapper.h" +#include "bundle_constants.h" +#include "bundle_installer_interface.h" +#include "bundle_mgr_interface.h" +#include "iservice_registry.h" +#include "status_receiver_host.h" +#include "system_ability_definition.h" +#include "operation_builder.h" +#include "common_tool.h" +#include "launcher_ability_info.h" +#include "launcher_service.h" + +namespace { +const std::string THIRD_BUNDLE_PATH = "/data/test/bms_bundle/"; +const std::string THIRD_BASE_BUNDLE_NAME = "com.example.third"; +const std::string SYSTEM_BASE_BUNDLE_NAME = "com.example.system"; +const std::string CAMERA = "ohos.permission.CAMERA"; +const std::string RESOURCE_ROOT_PATH = "/data/test/"; +const std::string MSG_SUCCESS = "[SUCCESS]"; +const std::string OPERATION_FAILED = "Failure"; +const std::string OPERATION_SUCCESS = "Success"; +const std::string BUNDLE_ADD = "Bundle Add Success"; +const std::string BUNDLE_UPDATE = "Bundle Update Success"; +const std::string BUNDLE_REMOVE = "Bundle Remove Success"; +const unsigned TWO = 2; + +} // namespace +using OHOS::AAFwk::Want; +using namespace testing::ext; +using namespace std::chrono_literals; +namespace OHOS { +namespace AppExecFwk { +class StatusReceiverImpl : public StatusReceiverHost { +public: + StatusReceiverImpl(); + virtual ~StatusReceiverImpl(); + virtual void OnStatusNotify(const int progress) override; + virtual void OnFinished(const int32_t resultCode, const std::string &resultMsg) override; + std::string GetResultMsg() const; + +private: + mutable std::promise resultMsgSignal_; + + DISALLOW_COPY_AND_MOVE(StatusReceiverImpl); +}; +class BmsLauncherServiceSystemTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + static void Install(const std::string &bundleFilePath, const InstallFlag installFlag, std::string &installMessage); + static void Uninstall(const std::string &bundleName, std::string &installMessage); + static sptr GetBundleMgrProxy(); + static sptr GetInstallerProxy(); + static void Complete(const std::string message); + static bool Wait(const std::string message); + +private: + static std::mutex mutex_; + static std::condition_variable cv_; + static std::string message_; +}; +std::string BmsLauncherServiceSystemTest::message_ = ""; +std::condition_variable BmsLauncherServiceSystemTest::cv_ = std::condition_variable(); +std::mutex BmsLauncherServiceSystemTest::mutex_ = std::mutex(); +void BmsLauncherServiceSystemTest::Complete(const std::string message) +{ + std::this_thread::sleep_for(500ms); + std::unique_lock lock(mutex_); + if (message_.empty()) { + GTEST_LOG_(INFO) << "Message empty."; + message_ = message; + return; + } + if (message_.compare(message) == 0) { + GTEST_LOG_(INFO) << "Complete."; + cv_.notify_all(); + message_ = ""; + return; + } + GTEST_LOG_(INFO) << "Can't Complete." << message_; + return; +} + +bool BmsLauncherServiceSystemTest::Wait(const std::string message) +{ + GTEST_LOG_(INFO) << "Wait start."; + std::unique_lock lock(mutex_); + if (!message_.empty()) { + GTEST_LOG_(INFO) << "Message is not empty." << message_; + bool ret = (message_ == message); + message_ = ""; + return ret; + } + message_ = message; + if (cv_.wait_for(lock, std::chrono::seconds(5)) == std::cv_status::timeout) { + GTEST_LOG_(INFO) << "Time out."; + message_ = ""; + return false; + } + GTEST_LOG_(INFO) << "Wait done."; + return true; +} + +sptr BmsLauncherServiceSystemTest::GetBundleMgrProxy() +{ + sptr systemAbilityManager = + SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (!systemAbilityManager) { + APP_LOGE("fail to get system ability mgr."); + return nullptr; + } + + sptr remoteObject = systemAbilityManager->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID); + if (!remoteObject) { + APP_LOGE("fail to get bundle manager proxy."); + return nullptr; + } + + APP_LOGI("get bundle manager proxy success."); + return iface_cast(remoteObject); +} + +sptr BmsLauncherServiceSystemTest::GetInstallerProxy() +{ + sptr bundleMgrProxy = GetBundleMgrProxy(); + if (!bundleMgrProxy) { + APP_LOGE("bundle mgr proxy is nullptr."); + return nullptr; + } + + sptr installerProxy = bundleMgrProxy->GetBundleInstaller(); + if (!installerProxy) { + APP_LOGE("fail to get bundle installer proxy"); + return nullptr; + } + + APP_LOGI("get bundle installer proxy success."); + return installerProxy; +} + +void BmsLauncherServiceSystemTest::Install( + const std::string &bundleFilePath, const InstallFlag installFlag, std::string &installMessage) +{ + sptr installerProxy = GetInstallerProxy(); + if (!installerProxy) { + APP_LOGE("get bundle installer failed."); + installMessage = OPERATION_FAILED; + return; + } + InstallParam installParam; + installParam.installFlag = installFlag; + installParam.userId = Constants::DEFAULT_USERID; + sptr statusReceiver = (new (std::nothrow) StatusReceiverImpl()); + EXPECT_NE(statusReceiver, nullptr); + installerProxy->Install(bundleFilePath, installParam, statusReceiver); + installMessage = statusReceiver->GetResultMsg(); +} + +void BmsLauncherServiceSystemTest::Uninstall(const std::string &bundleName, std::string &uninstallMessage) +{ + sptr installerProxy = GetInstallerProxy(); + if (!installerProxy) { + APP_LOGE("get bundle installer failed."); + uninstallMessage = OPERATION_FAILED; + return; + } + + if (bundleName.empty()) { + APP_LOGE("bundelname is null."); + uninstallMessage = OPERATION_FAILED; + } else { + InstallParam installParam; + installParam.userId = Constants::DEFAULT_USERID; + sptr statusReceiver = (new (std::nothrow) StatusReceiverImpl()); + EXPECT_NE(statusReceiver, nullptr); + installerProxy->Uninstall(bundleName, installParam, statusReceiver); + uninstallMessage = statusReceiver->GetResultMsg(); + } +} + +void BmsLauncherServiceSystemTest::SetUpTestCase() +{} +void BmsLauncherServiceSystemTest::TearDownTestCase() +{} +void BmsLauncherServiceSystemTest::SetUp() +{} +void BmsLauncherServiceSystemTest::TearDown() +{} + +class TestBundleStatusCallback : public IBundleStatusCallback { +public: + TestBundleStatusCallback() = default; + ~TestBundleStatusCallback() = default; + virtual void OnBundleStateChanged(const uint8_t installType, const int32_t resultCode, const std::string &resultMsg, + const std::string &bundleName) override; + virtual void OnBundleAdded(const std::string &bundleName, const int userId) override; + virtual void OnBundleUpdated(const std::string &bundleName, const int userId) override; + virtual void OnBundleRemoved(const std::string &bundleName, const int userId) override; + virtual sptr AsObject() override; +}; + +void TestBundleStatusCallback::OnBundleStateChanged( + const uint8_t installType, const int32_t resultCode, const std::string &resultMsg, const std::string &bundleName) +{ + GTEST_LOG_(INFO) << "OnBundleStateChanged " << resultMsg << " bundle name is " << bundleName; +} +void TestBundleStatusCallback::OnBundleAdded(const std::string &bundleName, const int userId) +{ + GTEST_LOG_(INFO) << "OnBundleAdded bundle name " << bundleName << "is exist"; + GTEST_LOG_(INFO) << "bundle name is " << bundleName << "is exist"; + BmsLauncherServiceSystemTest::Complete(BUNDLE_ADD); +} + +void TestBundleStatusCallback::OnBundleUpdated(const std::string &bundleName, const int userId) +{ + GTEST_LOG_(INFO) << "OnBundleUpdated bundle name " << bundleName << "is exist"; + GTEST_LOG_(INFO) << "bundle name is " << bundleName << "is exist"; + BmsLauncherServiceSystemTest::Complete(BUNDLE_UPDATE); +} + +void TestBundleStatusCallback::OnBundleRemoved(const std::string &bundleName, const int userId) +{ + GTEST_LOG_(INFO) << "OnBundleRemoved bundle name " << bundleName << "is exist"; + GTEST_LOG_(INFO) << "bundle name is " << bundleName << "is exist"; + BmsLauncherServiceSystemTest::Complete(BUNDLE_REMOVE); +} + +sptr TestBundleStatusCallback::AsObject() +{ + return nullptr; +} + +StatusReceiverImpl::StatusReceiverImpl() +{ + APP_LOGI("create status receiver instance"); +} + +StatusReceiverImpl::~StatusReceiverImpl() +{ + APP_LOGI("destroy status receiver instance"); +} +void StatusReceiverImpl::OnStatusNotify(const int progress) +{ + APP_LOGI("OnStatusNotify"); +} +void StatusReceiverImpl::OnFinished(const int32_t resultCode, const std::string &resultMsg) +{ + APP_LOGD("on finished result is %{public}d, %{public}s", resultCode, resultMsg.c_str()); + resultMsgSignal_.set_value(resultMsg); +} + +std::string StatusReceiverImpl::GetResultMsg() const +{ + auto future = resultMsgSignal_.get_future(); + future.wait(); + std::string resultMsg = future.get(); + if (resultMsg == MSG_SUCCESS) { + return OPERATION_SUCCESS; + } else { + return OPERATION_FAILED + resultMsg; + } +} +/** + * @tc.number: BMS_Register_0100 + * @tc.name: test launcher service RegisterCallback + * @tc.desc: register callback and listen for add events + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_Register_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "START BMS_Register_0100"; + std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1.hap"; + std::string bundleName = "com.example.third1"; + std::string message; + std::shared_ptr launcherservice = std::make_shared(); + sptr callback = new TestBundleStatusCallback(); + launcherservice->RegisterCallback(callback); + Install(bundleFilePath, InstallFlag::NORMAL, message); + EXPECT_EQ(message, "Success") << "install fail!"; + EXPECT_TRUE(Wait(BUNDLE_ADD)); + launcherservice->UnRegisterCallback(); + Uninstall(bundleName, message); + EXPECT_EQ(message, "Success") << "uninstall fail!"; + GTEST_LOG_(INFO) << "END BMS_Register_0100"; +} +/** + * @tc.number: BMS_Register_0200 + * @tc.name: test launcher service RegisterCallback + * @tc.desc: register callback and listen for remove events + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_Register_0200, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "START BMS_Register_0200"; + std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1.hap"; + std::string bundleName = "com.example.third1"; + std::string message; + std::shared_ptr launcherservice = std::make_shared(); + sptr callback = new TestBundleStatusCallback(); + launcherservice->RegisterCallback(callback); + Install(bundleFilePath, InstallFlag::NORMAL, message); + EXPECT_EQ(message, "Success") << "install fail!"; + Uninstall(bundleName, message); + EXPECT_TRUE(Wait(BUNDLE_REMOVE)); + EXPECT_EQ(message, "Success") << "uninstall fail!"; + launcherservice->UnRegisterCallback(); + GTEST_LOG_(INFO) << "END BMS_Register_0200"; +} +/** + * @tc.number: BMS_Register_0300 + * @tc.name: test launcher service RegisterCallback + * @tc.desc: register callback and listen for update events + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_Register_0300, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "START BMS_Register_0300"; + std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; + std::string bundleFilePath1 = THIRD_BUNDLE_PATH + "bmsThirdBundle1.hap"; + std::string bundleFilePath2 = THIRD_BUNDLE_PATH + "bmsThirdBundle4.hap"; + std::string message; + std::shared_ptr launcherservice = std::make_shared(); + sptr callback = new TestBundleStatusCallback(); + launcherservice->RegisterCallback(callback); + Install(bundleFilePath1, InstallFlag::NORMAL, message); + EXPECT_EQ(message, "Success") << "install fail!"; + EXPECT_TRUE(Wait(BUNDLE_ADD)); + Install(bundleFilePath2, InstallFlag::REPLACE_EXISTING, message); + EXPECT_EQ(message, "Success") << "install fail!"; + EXPECT_TRUE(Wait(BUNDLE_UPDATE)); + launcherservice->UnRegisterCallback(); + Uninstall(bundleName, message); + EXPECT_EQ(message, "Success") << "uninstall fail!"; + GTEST_LOG_(INFO) << "END BMS_Register_0300"; +} +/** + * @tc.number: BMS_Register_0400 + * @tc.name: test launcher service RegisterCallback + * @tc.desc: unregister callback and listen for events + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_Register_0400, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "START BMS_Register_0400"; + std::string bundleName = THIRD_BASE_BUNDLE_NAME + "2"; + std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle2.hap"; + std::string message; + std::shared_ptr launcherservice = std::make_shared(); + sptr callback = new TestBundleStatusCallback(); + launcherservice->RegisterCallback(callback); + launcherservice->UnRegisterCallback(); + Install(bundleFilePath, InstallFlag::NORMAL, message); + EXPECT_EQ(message, "Success") << "install fail!"; + EXPECT_FALSE(Wait(BUNDLE_ADD)); + Uninstall(bundleName, message); + EXPECT_EQ(message, "Success") << "uninstall fail!"; + GTEST_LOG_(INFO) << "END BMS_Register_0400"; +} +/** + * @tc.number: BMS_GetAbilityList_0100 + * @tc.name: test GetAbilityList by LauncherService + * @tc.desc: 1.install a normal hap + * 2.get ability info of the installed hap by bundleName + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_GetAbilityList_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "START BMS_GetAbilityList_0100"; + std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1.hap"; + std::string bundleName = "com.example.third1"; + std::string abilityName = "com.example.third1.MainAbility"; + std::string message; + int userId = Constants::DEFAULT_USERID; + Install(bundleFilePath, InstallFlag::NORMAL, message); + EXPECT_EQ(message, "Success") << "install fail!"; + + std::shared_ptr launcherservice = std::make_shared(); + std::vector launcherAbilityInfos; + if (!launcherservice) { + APP_LOGE("launcher service is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + bool result = launcherservice->GetAbilityList(bundleName, userId, launcherAbilityInfos); + EXPECT_TRUE(result) << "Get ability list failed"; + EXPECT_FALSE(launcherAbilityInfos.empty()) << "Launcher ability infos is empty"; + EXPECT_EQ(launcherAbilityInfos[0].name, abilityName); + + Uninstall(bundleName, message); + EXPECT_EQ(message, "Success") << "uninstall fail!"; + GTEST_LOG_(INFO) << "END BMS_GetAbilityList_0100"; +} +/** + * @tc.number: BMS_GetAbilityList_0200 + * @tc.name: test GetAbilityList by LauncherService + * @tc.desc: 1.install a low version hap + * 2.install a high version hap + * 3.get the ability info of the high version hap by bundleName + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_GetAbilityList_0200, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "START BMS_GetAbilityList_0200"; + std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; + std::string bundleFilePath1 = THIRD_BUNDLE_PATH + "bmsThirdBundle1.hap"; + std::string bundleFilePath2 = THIRD_BUNDLE_PATH + "bmsThirdBundle4.hap"; + std::string abilityName = "com.example.third4.MainAbility"; + std::string message; + int userId = Constants::DEFAULT_USERID; + + Install(bundleFilePath1, InstallFlag::NORMAL, message); + EXPECT_EQ(message, "Success") << "install fail!"; + Install(bundleFilePath2, InstallFlag::REPLACE_EXISTING, message); + EXPECT_EQ(message, "Success") << "install fail!"; + + std::shared_ptr launcherservice = std::make_shared(); + std::vector launcherAbilityInfos; + if (!launcherservice) { + APP_LOGE("launcher service is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + bool result = launcherservice->GetAbilityList(bundleName, userId, launcherAbilityInfos); + EXPECT_TRUE(result) << "Get ability list failed"; + EXPECT_FALSE(launcherAbilityInfos.empty()) << "Launcher ability infos is empty"; + EXPECT_EQ(launcherAbilityInfos[0].name, abilityName); + + Uninstall(bundleName, message); + EXPECT_EQ(message, "Success") << "uninstall fail!"; + GTEST_LOG_(INFO) << "END BMS_GetAbilityList_0200"; +} +/** + * @tc.number: BMS_GetAbilityList_0300 + * @tc.name: test GetAbilityList by LauncherService + * @tc.desc: 1.install a normal hap with two abilty + * 2.get ability info of the installed hap by bundleName + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_GetAbilityList_0300, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "START BMS_GetAbilityList_0300"; + std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle5.hap"; + std::string bundleName = "com.example.third5"; + std::string abilityName1 = "com.example.third5A.MainAbility"; + std::string abilityName2 = "com.example.third5B.MainAbility"; + std::string message; + int userId = Constants::DEFAULT_USERID; + Install(bundleFilePath, InstallFlag::NORMAL, message); + EXPECT_EQ(message, "Success") << "install fail!"; + std::vector launcherAbilityInfos; + std::shared_ptr launcherservice = std::make_shared(); + if (!launcherservice) { + APP_LOGE("launcher service is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + bool result = launcherservice->GetAbilityList(bundleName, userId, launcherAbilityInfos); + EXPECT_TRUE(result) << "Get ability list failed"; + EXPECT_FALSE(launcherAbilityInfos.empty()) << "Launcher ability infos is empty"; + EXPECT_EQ(launcherAbilityInfos.size(), TWO); + EXPECT_EQ(launcherAbilityInfos[0].name, abilityName1); + EXPECT_EQ(launcherAbilityInfos[1].name, abilityName2); + Uninstall(bundleName, message); + EXPECT_EQ(message, "Success") << "uninstall fail!"; + GTEST_LOG_(INFO) << "END BMS_GetAbilityList_0300"; +} +/** + * @tc.number: BMS_GetAbilityList_0400 + * @tc.name: test GetAbilityList by LauncherService + * @tc.desc: 1.install a hap with moduletype of entry + * 2.install a hap with moduletype of feature + * 2.get ability informations of two types of haps + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_GetAbilityList_0400, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "START BMS_GetAbilityList_0400"; + std::string bundleFilePath1 = THIRD_BUNDLE_PATH + "bmsThirdBundle1.hap"; + std::string bundleFilePath2 = THIRD_BUNDLE_PATH + "bmsThirdBundle3.hap"; + std::string abilityName1 = "com.example.third1.MainAbility"; + std::string abilityName2 = "com.example.third1F.MainAbility"; + std::string bundleName = "com.example.third1"; + std::string message; + + int userId = Constants::DEFAULT_USERID; + Install(bundleFilePath1, InstallFlag::NORMAL, message); + EXPECT_EQ(message, "Success") << "install fail!"; + Install(bundleFilePath2, InstallFlag::NORMAL, message); + EXPECT_EQ(message, "Success") << "install fail!"; + std::vector launcherAbilityInfos; + std::shared_ptr launcherservice = std::make_shared(); + if (!launcherservice) { + APP_LOGE("launcher service is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + bool result = launcherservice->GetAbilityList(bundleName, userId, launcherAbilityInfos); + EXPECT_TRUE(result) << "Get ability list failed"; + EXPECT_FALSE(launcherAbilityInfos.empty()) << "Launcher ability infos is empty"; + EXPECT_EQ(launcherAbilityInfos.size(), TWO); + EXPECT_EQ(launcherAbilityInfos[0].name, abilityName1); + EXPECT_EQ(launcherAbilityInfos[1].name, abilityName2); + Uninstall(bundleName, message); + EXPECT_EQ(message, "Success") << "uninstall fail!"; + GTEST_LOG_(INFO) << "END BMS_GetAbilityList_0400"; +} +/** + * @tc.number: BMS_GetAbilityList_0500 + * @tc.name: test GetAbilityList by LauncherService + * @tc.desc: get ability info by wrong bundleName + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_GetAbilityList_0500, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "START BMS_GetAbilityList_0500"; + std::string bundleName = ""; + int userId = Constants::DEFAULT_USERID; + + std::vector launcherAbilityInfos; + std::shared_ptr launcherservice = std::make_shared(); + if (!launcherservice) { + APP_LOGE("launcher service is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + bool result = launcherservice->GetAbilityList(bundleName, userId, launcherAbilityInfos); + EXPECT_FALSE(result); + GTEST_LOG_(INFO) << "END BMS_GetAbilityList_0500"; +} +/** + * @tc.number: BMS_GetAbilityList_0600 + * @tc.name: test GetAbilityList by LauncherService + * @tc.desc: 1.install a normal hap + * 2.get ability info of this hap by bundleName + * 2.get ability info after uninstalling the hap + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_GetAbilityList_0600, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "START BMS_GetAbilityList_0600"; + std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1.hap"; + std::string bundleName = "com.example.third1"; + std::string abilityName = "com.example.third1.MainAbility"; + std::string message; + int userId = Constants::DEFAULT_USERID; + Install(bundleFilePath, InstallFlag::NORMAL, message); + EXPECT_EQ(message, "Success") << "install fail!"; + + std::shared_ptr launcherservice = std::make_shared(); + std::vector launcherAbilityInfos; + if (!launcherservice) { + APP_LOGE("launcher service is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + bool result1 = launcherservice->GetAbilityList(bundleName, userId, launcherAbilityInfos); + EXPECT_TRUE(result1) << "Get ability list failed"; + EXPECT_FALSE(launcherAbilityInfos.empty()) << "Launcher ability infos is empty"; + EXPECT_EQ(launcherAbilityInfos[0].name, abilityName); + + Uninstall(bundleName, message); + EXPECT_EQ(message, "Success") << "uninstall fail!"; + + bool result2 = launcherservice->GetAbilityList(bundleName, userId, launcherAbilityInfos); + EXPECT_FALSE(result2); + GTEST_LOG_(INFO) << "END BMS_GetAbilityList_0600"; +} +/** + * @tc.number: BMS_GetAbilityList_0700 + * @tc.name: test GetAbilityList by LauncherService + * @tc.desc: 1.get the ability info of system app + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_GetAbilityList_0700, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "START BMS_GetAbilityList_0700"; + std::string bundleName = SYSTEM_BASE_BUNDLE_NAME + "1"; + std::string abilityName = "com.example.system1.MainAbility"; + int userId = Constants::DEFAULT_USERID; + + std::vector launcherAbilityInfos; + std::shared_ptr launcherservice = std::make_shared(); + if (!launcherservice) { + APP_LOGE("launcher service is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + bool result = launcherservice->GetAbilityList(bundleName, userId, launcherAbilityInfos); + EXPECT_TRUE(result); + EXPECT_FALSE(launcherAbilityInfos.empty()) << "Launcher ability infos is empty"; + EXPECT_EQ(launcherAbilityInfos[0].name, abilityName); + + GTEST_LOG_(INFO) << "END BMS_GetAbilityList_0700"; +} +/** + * @tc.number: BMS_GetAbilityInfo_0100 + * @tc.name: test GetAbilityInfo by LauncherService + * @tc.desc: 1.install a normal hap with an ability + * 2.get the ability info by want + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_GetAbilityInfo_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "START GetAbilityInfo_0100"; + std::string message; + std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1.hap"; + std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; + std::string abilityName = "com.example.third1.MainAbility"; + int userId = Constants::DEFAULT_USERID; + + Install(bundleFilePath, InstallFlag::NORMAL, message); + EXPECT_EQ(message, "Success") << "install fail!"; + + Want want; + ElementName name; + name.SetAbilityName(abilityName); + name.SetBundleName(bundleName); + want.SetElement(name); + + LauncherAbilityInfo launcherAbilityInfo; + std::shared_ptr launcherservice = std::make_shared(); + if (!launcherservice) { + APP_LOGE("launcherservice is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + bool Result = launcherservice->GetAbilityInfo(want, userId, launcherAbilityInfo); + EXPECT_TRUE(Result); + EXPECT_EQ(launcherAbilityInfo.name, abilityName); + + Uninstall(bundleName, message); + EXPECT_EQ(message, "Success") << "uninstall fail!"; + GTEST_LOG_(INFO) << "END GetAbilityInfo_0100"; +} +/** + * @tc.number: BMS_GetAbilityInfo_0200 + * @tc.name: test GetAbilityInfo by LauncherService + * @tc.desc: 1.install a normal hap with two ability + * 2.get one ability info of the abilities by want + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_GetAbilityInfo_0200, Function | MediumTest | Level2) +{ + std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle5.hap"; + std::string bundleName = "com.example.third5"; + std::string abilityName = "com.example.third5B.MainAbility"; + std::string message; + int userId = Constants::DEFAULT_USERID; + Install(bundleFilePath, InstallFlag::NORMAL, message); + EXPECT_EQ(message, "Success") << "install fail!"; + + Want want; + ElementName name; + name.SetAbilityName(abilityName); + name.SetBundleName(bundleName); + want.SetElement(name); + + LauncherAbilityInfo launcherAbilityInfos; + std::shared_ptr launcherservice = std::make_shared(); + if (!launcherservice) { + APP_LOGE("launcher service is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + bool result = launcherservice->GetAbilityInfo(want, userId, launcherAbilityInfos); + EXPECT_TRUE(result) << "Get ability list failed"; + EXPECT_EQ(launcherAbilityInfos.name, abilityName); + Uninstall(bundleName, message); + EXPECT_EQ(message, "Success") << "uninstall fail!"; + GTEST_LOG_(INFO) << "END GetAbilityInfo_0200"; +} +/** + * @tc.number: BMS_GetAbilityInfo_0300 + * @tc.name: test GetAbilityInfo by LauncherService + * @tc.desc: 1.install a normal hap with an ability + * 2.get ability info after uninstalling the hap + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_GetAbilityInfo_0300, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "START GetAbilityInfo_0300"; + std::string message; + std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1.hap"; + std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; + std::string abilityName = "com.example.third1.MainAbility"; + int userId = Constants::DEFAULT_USERID; + + Install(bundleFilePath, InstallFlag::NORMAL, message); + EXPECT_EQ(message, "Success") << "install fail!"; + + Uninstall(bundleName, message); + EXPECT_EQ(message, "Success") << "uninstall fail!"; + + Want want; + ElementName name; + name.SetAbilityName(abilityName); + name.SetBundleName(bundleName); + want.SetElement(name); + LauncherAbilityInfo launcherAbilityInfo; + std::shared_ptr launcherservice = std::make_shared(); + if (!launcherservice) { + APP_LOGE("launcherservice is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + bool result = launcherservice->GetAbilityInfo(want, userId, launcherAbilityInfo); + EXPECT_FALSE(result); + GTEST_LOG_(INFO) << "END GetAbilityInfo_0300"; +} +/** + * @tc.number: BMS_GetAbilityInfo_0400 + * @tc.name: test GetAbilityInfo by LauncherService + * @tc.desc: 1.get the ability info of system app by want + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_GetAbilityInfo_0400, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "START GetAbilityInfo_0400"; + std::string bundleName = SYSTEM_BASE_BUNDLE_NAME + "1"; + std::string abilityName = "com.example.system1.MainAbility"; + int userId = Constants::DEFAULT_USERID; + Want want; + ElementName name; + name.SetAbilityName(abilityName); + name.SetBundleName(bundleName); + want.SetElement(name); + + LauncherAbilityInfo launcherAbilityInfo; + std::shared_ptr launcherservice = std::make_shared(); + if (!launcherservice) { + APP_LOGE("launcherservice is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + bool Result = launcherservice->GetAbilityInfo(want, userId, launcherAbilityInfo); + EXPECT_TRUE(Result); + EXPECT_EQ(launcherAbilityInfo.name, abilityName); + + GTEST_LOG_(INFO) << "END GetAbilityInfo_0400"; +} +/** + * @tc.number: BMS_GetAbilityInfo_0500 + * @tc.name: test GetAbilityInfo by LauncherService + * @tc.desc: 1.install a low version hap + * 2.install a high version hap + * 3.get the ability info of the high version hap by want + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_GetAbilityInfo_0500, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "START GetAbilityInfo_0500"; + std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; + std::string bundleFilePath1 = THIRD_BUNDLE_PATH + "bmsThirdBundle1.hap"; + std::string bundleFilePath2 = THIRD_BUNDLE_PATH + "bmsThirdBundle4.hap"; + std::string abilityName = "com.example.third4.MainAbility"; + std::string message; + int userId = Constants::DEFAULT_USERID; + + Install(bundleFilePath1, InstallFlag::NORMAL, message); + EXPECT_EQ(message, "Success") << "install fail!"; + Install(bundleFilePath2, InstallFlag::REPLACE_EXISTING, message); + EXPECT_EQ(message, "Success") << "install fail!"; + + Want want; + ElementName name; + name.SetAbilityName(abilityName); + name.SetBundleName(bundleName); + want.SetElement(name); + + LauncherAbilityInfo launcherAbilityInfos; + std::shared_ptr launcherservice = std::make_shared(); + if (!launcherservice) { + APP_LOGE("launcher service is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + bool result = launcherservice->GetAbilityInfo(want, userId, launcherAbilityInfos); + EXPECT_TRUE(result); + EXPECT_EQ(launcherAbilityInfos.name, abilityName); + Uninstall(bundleName, message); + EXPECT_EQ(message, "Success") << "uninstall fail!"; + GTEST_LOG_(INFO) << "END GetAbilityInfo_0500"; +} +/** + * @tc.number: BMS_GetApplicationInfo_0100 + * @tc.name: test GetApplicationInfo by LauncherService + * @tc.desc: get the application info of third app by bundleName + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_GetApplicationInfo_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "START BMS_GetApplicationInfo_0100"; + std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1.hap"; + std::string bundleName = "com.example.third1"; + std::string message; + int userId = Constants::DEFAULT_USERID; + Install(bundleFilePath, InstallFlag::NORMAL, message); + EXPECT_EQ(message, "Success") << "install fail!"; + std::shared_ptr launcherservice = std::make_shared(); + if (!launcherservice) { + APP_LOGE("launcher service is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + ApplicationInfo appInfo; + ApplicationFlag flag = ApplicationFlag::GET_BASIC_APPLICATION_INFO; + bool result = launcherservice->GetApplicationInfo(bundleName, flag, userId, appInfo); + EXPECT_TRUE(result); + EXPECT_EQ(appInfo.name, bundleName); + Uninstall(bundleName, message); + EXPECT_EQ(message, "Success") << "uninstall fail!"; + GTEST_LOG_(INFO) << "END BMS_GetApplicationInfo_0100"; +} +/** + * @tc.number: BMS_GetApplicationInfo_0200 + * @tc.name: test GetApplicationInfo by LauncherService + * @tc.desc: get the application info with perms of third app by bundleName + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_GetApplicationInfo_0200, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "START GetApplicationInfo_0200"; + std::string message; + std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle6.hap"; + std::string bundleName = THIRD_BASE_BUNDLE_NAME + "6"; + int userId = Constants::DEFAULT_USERID; + + Install(bundleFilePath, InstallFlag::NORMAL, message); + EXPECT_EQ(message, "Success") << "install fail!"; + + std::shared_ptr launcherservice = std::make_shared(); + if (!launcherservice) { + APP_LOGE("launcherservice is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + ApplicationInfo applicationInfo; + bool Result = launcherservice->GetApplicationInfo( + bundleName, ApplicationFlag::GET_APPLICATION_INFO_WITH_PERMS, userId, applicationInfo); + EXPECT_TRUE(Result); + + CommonTool commonTool; + std::string permissions = commonTool.VectorToStr(applicationInfo.permissions); + EXPECT_EQ(permissions, CAMERA); + EXPECT_EQ(applicationInfo.name, bundleName); + Uninstall(bundleName, message); + EXPECT_EQ(message, "Success") << "uninstall fail!"; + GTEST_LOG_(INFO) << "END GetApplicationInfo_0200"; +} +/** + * @tc.number: BMS_GetApplicationInfo_0300 + * @tc.name: test GetApplicationInfo by LauncherService + * @tc.desc: get the application info of system app by bundleName + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_GetApplicationInfo_0300, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "START GetApplicationInfo_0300"; + std::string bundleName = SYSTEM_BASE_BUNDLE_NAME + "1"; + int userId = Constants::DEFAULT_USERID; + + std::shared_ptr launcherservice = std::make_shared(); + if (!launcherservice) { + APP_LOGE("launcherservice is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + ApplicationInfo applicationInfo; + bool Result = launcherservice->GetApplicationInfo( + bundleName, ApplicationFlag::GET_BASIC_APPLICATION_INFO, userId, applicationInfo); + EXPECT_TRUE(Result); + EXPECT_EQ(applicationInfo.name, bundleName); + GTEST_LOG_(INFO) << "END GetApplicationInfo_0300"; +} +/** + * @tc.number: BMS_GetApplicationInfo_0400 + * @tc.name: test GetAbilityInfo by LauncherService + * @tc.desc: 1.install a low version hap + * 2.install a high version hap + * 3.get the application info of the high version hap by bundleName + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_GetApplicationInfo_0400, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "START BMS_GetApplicationInfo_0400"; + std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; + std::string bundleFilePath1 = THIRD_BUNDLE_PATH + "bmsThirdBundle1.hap"; + std::string bundleFilePath2 = THIRD_BUNDLE_PATH + "bmsThirdBundle4.hap"; + std::string message; + int userId = Constants::DEFAULT_USERID; + + Install(bundleFilePath1, InstallFlag::NORMAL, message); + EXPECT_EQ(message, "Success") << "install fail!"; + Install(bundleFilePath2, InstallFlag::REPLACE_EXISTING, message); + EXPECT_EQ(message, "Success") << "install fail!"; + + std::shared_ptr launcherservice = std::make_shared(); + if (!launcherservice) { + APP_LOGE("launcher service is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + ApplicationInfo applicationInfo; + bool Result = launcherservice->GetApplicationInfo( + bundleName, ApplicationFlag::GET_BASIC_APPLICATION_INFO, userId, applicationInfo); + EXPECT_TRUE(Result); + EXPECT_EQ(applicationInfo.name, bundleName); + Uninstall(bundleName, message); + EXPECT_EQ(message, "Success") << "uninstall fail!"; + GTEST_LOG_(INFO) << "END BMS_GetApplicationInfo_0400"; +} +/** + * @tc.number: BMS_GetApplicationInfo_0500 + * @tc.name: test GetApplicationInfo by LauncherService + * @tc.desc: get the application info after uninstalling the hap + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_GetApplicationInfo_0500, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "START BMS_GetApplicationInfo_0500"; + std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1.hap"; + std::string bundleName = "com.example.third1"; + std::string message; + int userId = Constants::DEFAULT_USERID; + Install(bundleFilePath, InstallFlag::NORMAL, message); + EXPECT_EQ(message, "Success") << "install fail!"; + Uninstall(bundleName, message); + EXPECT_EQ(message, "Success") << "uninstall fail!"; + + std::shared_ptr launcherservice = std::make_shared(); + if (!launcherservice) { + APP_LOGE("launcher service is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + ApplicationInfo appInfo; + bool result = + launcherservice->GetApplicationInfo(bundleName, ApplicationFlag::GET_BASIC_APPLICATION_INFO, userId, appInfo); + EXPECT_FALSE(result); + GTEST_LOG_(INFO) << "END BMS_GetApplicationInfo_0500"; +} +/** + * @tc.number: BMS_GetApplicationInfo_0600 + * @tc.name: test GetApplicationInfo by LauncherService + * @tc.desc: get the application info by invalid bundleName + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_GetApplicationInfo_0600, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "START BMS_GetApplicationInfo_0600"; + std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1.hap"; + std::string bundleName = ""; + int userId = Constants::DEFAULT_USERID; + + std::shared_ptr launcherservice = std::make_shared(); + if (!launcherservice) { + APP_LOGE("launcher service is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + ApplicationInfo appInfo; + bool result = + launcherservice->GetApplicationInfo(bundleName, ApplicationFlag::GET_BASIC_APPLICATION_INFO, userId, appInfo); + EXPECT_FALSE(result); + GTEST_LOG_(INFO) << "END BMS_GetApplicationInfo_0600"; +} +/** + * @tc.number: BMS_IsAbilityEnabled_0100 + * @tc.name: test IsAbilityEnabled by LauncherService + * @tc.desc: check weather the ability of third hap can be enabled by abilityinfo + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_IsAbilityEnabled_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "START BMS_IsAbilityEnabled_0100"; + std::string message; + std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1.hap"; + std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; + std::string abilityName = "com.example.third1.MainAbility"; + Install(bundleFilePath, InstallFlag::NORMAL, message); + EXPECT_EQ(message, "Success") << "install fail!"; + AbilityInfo abilityInfo; + abilityInfo.bundleName = bundleName; + abilityInfo.name = abilityName; + std::shared_ptr launcherservice = std::make_shared(); + if (!launcherservice) { + APP_LOGE("launcherservice is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + bool result = launcherservice->IsAbilityEnabled(abilityInfo); + EXPECT_TRUE(result); + Uninstall(bundleName, message); + EXPECT_EQ(message, "Success") << "uninstall fail!"; + GTEST_LOG_(INFO) << "END BMS_IsAbilityEnabled_0100"; +} +/** + * @tc.number: BMS_IsAbilityEnabled_0200 + * @tc.name: test IsAbilityEnabled by LauncherService + * @tc.desc: check weather the ability of system hap can be enabled by abilityinfo + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_IsAbilityEnabled_0200, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "START BMS_IsAbilityEnabled_0200"; + std::string bundleName = SYSTEM_BASE_BUNDLE_NAME + "1"; + std::string abilityName = "com.example.system1.MainAbility"; + AbilityInfo abilityInfo; + abilityInfo.bundleName = bundleName; + abilityInfo.name = abilityName; + sptr bundleMgrProxy = GetBundleMgrProxy(); + if (!bundleMgrProxy) { + APP_LOGE("bundle mgr proxy is nullptr."); + EXPECT_EQ(bundleMgrProxy, nullptr); + } + std::shared_ptr launcherservice = std::make_shared(); + if (!launcherservice) { + APP_LOGE("launcherservice is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + bool result = launcherservice->IsAbilityEnabled(abilityInfo); + EXPECT_TRUE(result); + GTEST_LOG_(INFO) << "END BMS_IsAbilityEnabled_0200"; +} +/** + * @tc.number: BMS_IsAbilityEnabled_0300 + * @tc.name: test IsAbilityEnabled by LauncherService + * @tc.desc: check weather the ability of hap can be enabled by invalid abilityName + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_IsAbilityEnabled_0300, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "START BMS_IsAbilityEnabled_0300"; + std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; + std::string abilityName = "com.example.wrong.MainAbility"; + AbilityInfo abilityInfo; + abilityInfo.bundleName = bundleName; + abilityInfo.name = abilityName; + std::shared_ptr launcherservice = std::make_shared(); + if (!launcherservice) { + APP_LOGE("launcherservice is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + bool result = launcherservice->IsAbilityEnabled(abilityInfo); + EXPECT_FALSE(result); + GTEST_LOG_(INFO) << "END BMS_IsAbilityEnabled_0300"; +} +/** + * @tc.number: BMS_IsAbilityEnabled_0400 + * @tc.name: test IsAbilityEnabled by LauncherService + * @tc.desc: 1.set ability enabled true + * 2.check weather the ability enabled is true by abilityinfo + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_IsAbilityEnabled_0400, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "START BMS_IsAbilityEnabled_0400"; + std::string message; + std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1.hap"; + std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; + std::string abilityName = "com.example.third1.MainAbility"; + Install(bundleFilePath, InstallFlag::NORMAL, message); + EXPECT_EQ(message, "Success") << "install fail!"; + AbilityInfo abilityInfo; + abilityInfo.bundleName = bundleName; + abilityInfo.name = abilityName; + sptr bundleMgrProxy = GetBundleMgrProxy(); + if (!bundleMgrProxy) { + APP_LOGE("bundle mgr proxy is nullptr."); + EXPECT_EQ(bundleMgrProxy, nullptr); + } + bool ret = bundleMgrProxy->SetAbilityEnabled(abilityInfo, true); + EXPECT_TRUE(ret); + std::shared_ptr launcherservice = std::make_shared(); + if (!launcherservice) { + APP_LOGE("launcherservice is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + bool result = launcherservice->IsAbilityEnabled(abilityInfo); + EXPECT_TRUE(result); + Uninstall(bundleName, message); + EXPECT_EQ(message, "Success") << "uninstall fail!"; + GTEST_LOG_(INFO) << "END BMS_IsAbilityEnabled_0400"; +} +/** + * @tc.number: BMS_IsBundleEnabled_0100 + * @tc.name: test IsBundleEnabled by LauncherService + * @tc.desc: check weather the application of third hap can be enabled by bundleName + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_IsBundleEnabled_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "START BMS_IsBundleEnabled_0100"; + std::string message; + std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1.hap"; + std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; + Install(bundleFilePath, InstallFlag::NORMAL, message); + EXPECT_EQ(message, "Success") << "install fail!"; + std::shared_ptr launcherservice = std::make_shared(); + if (!launcherservice) { + APP_LOGE("launcherservice is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + bool result = launcherservice->IsBundleEnabled(bundleName); + EXPECT_TRUE(result); + Uninstall(bundleName, message); + EXPECT_EQ(message, "Success") << "uninstall fail!"; + GTEST_LOG_(INFO) << "END BMS_IsBundleEnabled_0100"; +} +/** + * @tc.number: BMS_IsBundleEnabled_0100 + * @tc.name: test IsBundleEnabled by LauncherService + * @tc.desc: 1.set application enabled false + * 2.check the application enabled is false by bundleName + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_IsBundleEnabled_0200, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "START BMS_IsBundleEnabled_0200"; + std::string message; + std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1.hap"; + std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; + Install(bundleFilePath, InstallFlag::NORMAL, message); + EXPECT_EQ(message, "Success") << "install fail!"; + std::shared_ptr launcherservice = std::make_shared(); + sptr bundleMgrProxy = GetBundleMgrProxy(); + if (!launcherservice) { + APP_LOGE("launcherservice is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + bool ret = bundleMgrProxy->SetApplicationEnabled(bundleName, false); + EXPECT_TRUE(ret); + bool result = launcherservice->IsBundleEnabled(bundleName); + EXPECT_FALSE(result); + Uninstall(bundleName, message); + EXPECT_EQ(message, "Success") << "uninstall fail!"; + GTEST_LOG_(INFO) << "END BMS_IsBundleEnabled_0200"; +} +/** + * @tc.number: BMS_IsBundleEnabled_0300 + * @tc.name: test IsBundleEnabled by LauncherService + * @tc.desc: check weather the application of system hap can be enabled by bundleName + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_IsBundleEnabled_0300, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "START BMS_IsBundleEnabled_0300"; + std::string bundleName = SYSTEM_BASE_BUNDLE_NAME + "1"; + std::shared_ptr launcherservice = std::make_shared(); + if (!launcherservice) { + APP_LOGE("launcherservice is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + bool result = launcherservice->IsBundleEnabled(bundleName); + EXPECT_TRUE(result); + GTEST_LOG_(INFO) << "END BMS_IsBundleEnabled_0300"; +} +/** + * @tc.number: BMS_IsBundleEnabled_0400 + * @tc.name: test IsBundleEnabled by LauncherService + * @tc.desc: check weather the application of hap can be enabled by invalid bundleName + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_IsBundleEnabled_0400, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "START BMS_IsBundleEnabled_0400"; + std::string bundleName = ""; + std::shared_ptr launcherservice = std::make_shared(); + if (!launcherservice) { + APP_LOGE("launcherservice is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + bool result = launcherservice->IsBundleEnabled(bundleName); + EXPECT_FALSE(result); + GTEST_LOG_(INFO) << "END BMS_IsBundleEnabled_0400"; +} +/** + * @tc.number: BMS_GetShortcutInfos_0100 + * @tc.name: test GetShortcutInfos by LauncherService + * @tc.desc: get the shortcut information of a normal hap + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_GetShortcutInfos_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "START BMS_GetShortcutInfos_0100"; + std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1.hap"; + std::string bundleName = "com.example.third1"; + std::string shortcutId = "id.third1"; + std::string message; + + Install(bundleFilePath, InstallFlag::NORMAL, message); + EXPECT_EQ(message, "Success") << "install fail!"; + std::vector launcherShortcutInfo; + std::shared_ptr launcherservice = std::make_shared(); + if (!launcherservice) { + APP_LOGE("launcher service is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + bool result = launcherservice->GetShortcutInfos(bundleName, launcherShortcutInfo); + EXPECT_TRUE(result) << "Get shortcut info failed"; + EXPECT_FALSE(launcherShortcutInfo.empty()) << "Launcher shortcut infos is empty"; + EXPECT_EQ(launcherShortcutInfo[0].bundleName, bundleName); + EXPECT_EQ(launcherShortcutInfo[0].shortcutid, shortcutId); + Uninstall(bundleName, message); + EXPECT_EQ(message, "Success") << "uninstall fail!"; + GTEST_LOG_(INFO) << "END BMS_GetShortcutInfos_0100"; +} +/** + * @tc.number: BMS_GetShortcutInfos_0200 + * @tc.name: test GetShortcutInfos by LauncherService + * @tc.desc: 1.install a hap with moduletype of entry + * 2.install a hap with moduletype of feature + * 3.get the shortcut information of two types of haps + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_GetShortcutInfos_0200, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "START BMS_GetShortcutInfos_0200"; + std::string bundleFilePath1 = THIRD_BUNDLE_PATH + "bmsThirdBundle1.hap"; + std::string bundleFilePath2 = THIRD_BUNDLE_PATH + "bmsThirdBundle3.hap"; + std::string bundleName = "com.example.third1"; + std::string shortcutId1 = "id.third1"; + std::string shortcutId2 = "id.third3"; + std::string message; + + Install(bundleFilePath1, InstallFlag::NORMAL, message); + EXPECT_EQ(message, "Success") << "install fail!"; + Install(bundleFilePath2, InstallFlag::NORMAL, message); + EXPECT_EQ(message, "Success") << "install fail!"; + std::vector launcherShortcutInfo; + std::shared_ptr launcherservice = std::make_shared(); + if (!launcherservice) { + APP_LOGE("launcher service is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + bool result = launcherservice->GetShortcutInfos(bundleName, launcherShortcutInfo); + EXPECT_TRUE(result) << "Get shortcut info failed"; + EXPECT_FALSE(launcherShortcutInfo.empty()) << "Launcher shortcut infos is empty"; + EXPECT_EQ(launcherShortcutInfo.size(), TWO); + EXPECT_EQ(launcherShortcutInfo[0].shortcutid, shortcutId1); + EXPECT_EQ(launcherShortcutInfo[1].shortcutid, shortcutId2); + Uninstall(bundleName, message); + EXPECT_EQ(message, "Success") << "uninstall fail!"; + GTEST_LOG_(INFO) << "END BMS_GetShortcutInfos_0200"; +} +/** + * @tc.number: BMS_GetShortcutInfos_0300 + * @tc.name: test GetShortcutInfos by LauncherService + * @tc.desc: get the shortcut information of a hap without shortcut in config.json + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_GetShortcutInfos_0300, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "START BMS_GetShortcutInfos_0300"; + std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle2.hap"; + std::string bundleName = "com.example.third2"; + std::string message; + + Install(bundleFilePath, InstallFlag::NORMAL, message); + EXPECT_EQ(message, "Success") << "install fail!"; + std::vector launcherShortcutInfo; + std::shared_ptr launcherservice = std::make_shared(); + if (!launcherservice) { + APP_LOGE("launcher service is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + bool result = launcherservice->GetShortcutInfos(bundleName, launcherShortcutInfo); + EXPECT_FALSE(result); + EXPECT_TRUE(launcherShortcutInfo.empty()); + Uninstall(bundleName, message); + EXPECT_EQ(message, "Success") << "uninstall fail!"; + GTEST_LOG_(INFO) << "END BMS_GetShortcutInfos_0300"; +} +/** + * @tc.number: BMS_GetShortcutInfos_0400 + * @tc.name: test GetShortcutInfos by LauncherService + * @tc.desc: get the shortcut information of a hap by invalid bundleName + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_GetShortcutInfos_0400, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "START BMS_GetShortcutInfos_0400"; + std::string bundleName = ""; + std::vector launcherShortcutInfo; + std::shared_ptr launcherservice = std::make_shared(); + if (!launcherservice) { + APP_LOGE("launcher service is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + bool result = launcherservice->GetShortcutInfos(bundleName, launcherShortcutInfo); + EXPECT_FALSE(result); + GTEST_LOG_(INFO) << "END BMS_GetShortcutInfos_0400"; +} +/** + * @tc.number: BMS_GetShortcutInfos_0500 + * @tc.name: test GetShortcutInfos by LauncherService + * @tc.desc: 1.install a low version hap + * 2.install a high version hap + * 3.get the shortcut info of the high version hap by want + */ +HWTEST_F(BmsLauncherServiceSystemTest, BMS_GetShortcutInfos_0500, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "START BMS_GetShortcutInfos_0500"; + std::string bundleName = THIRD_BASE_BUNDLE_NAME + "1"; + std::string bundleFilePath1 = THIRD_BUNDLE_PATH + "bmsThirdBundle1.hap"; + std::string bundleFilePath2 = THIRD_BUNDLE_PATH + "bmsThirdBundle4.hap"; + std::string shortcutId = "id.third4"; + std::string message; + + Install(bundleFilePath1, InstallFlag::NORMAL, message); + EXPECT_EQ(message, "Success") << "install fail!"; + Install(bundleFilePath2, InstallFlag::REPLACE_EXISTING, message); + EXPECT_EQ(message, "Success") << "install fail!"; + + std::vector launcherShortcutInfo; + std::shared_ptr launcherservice = std::make_shared(); + if (!launcherservice) { + APP_LOGE("launcher service is nullptr."); + EXPECT_EQ(launcherservice, nullptr); + } + bool result = launcherservice->GetShortcutInfos(bundleName, launcherShortcutInfo); + EXPECT_TRUE(result); + EXPECT_FALSE(launcherShortcutInfo.empty()) << "Launcher shortcut info is empty"; + EXPECT_EQ(launcherShortcutInfo[0].bundleName, bundleName); + EXPECT_EQ(launcherShortcutInfo[0].shortcutid, shortcutId); + Uninstall(bundleName, message); + EXPECT_EQ(message, "Success") << "uninstall fail!"; + GTEST_LOG_(INFO) << "END BMS_GetShortcutInfos_0500"; +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/test/systemtest/common/bms/bms_search_system_test/bms_search_system_test.cpp b/test/systemtest/common/bms/bms_search_system_test/bms_search_system_test.cpp index b13b31d33b..3ed774b217 100644 --- a/test/systemtest/common/bms/bms_search_system_test/bms_search_system_test.cpp +++ b/test/systemtest/common/bms/bms_search_system_test/bms_search_system_test.cpp @@ -14,6 +14,7 @@ */ #include +#include #include #include @@ -51,6 +52,9 @@ public: virtual ~BundleStatusCallbackImpl() override; virtual void OnBundleStateChanged(const uint8_t installType, const int32_t resultCode, const std::string &resultMsg, const std::string &bundleName) override; + virtual void OnBundleAdded(const std::string &bundleName, const int userId) override{}; + virtual void OnBundleUpdated(const std::string &bundleName, const int userId) override{}; + virtual void OnBundleRemoved(const std::string &bundleName, const int userId) override{}; private: DISALLOW_COPY_AND_MOVE(BundleStatusCallbackImpl); @@ -170,7 +174,6 @@ public: static sptr GetBundleMgrProxy(); static sptr GetInstallerProxy(); bool QueryJsonFile(const std::string &bundleName) const; - bool CreateFile(const std::string &path) const; }; void BmsSearchSystemTest::SetUpTestCase() @@ -183,10 +186,10 @@ void BmsSearchSystemTest::SetUpTestCase() sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install bmsThirdBundle1.hap fail!"; + EXPECT_EQ(installResult, "Success") << "install bmsThirdBundle1.hap fail!"; } void BmsSearchSystemTest::TearDownTestCase() @@ -256,40 +259,6 @@ bool BmsSearchSystemTest::QueryJsonFile(const std::string &bundleName) const return true; } -bool BmsSearchSystemTest::CreateFile(const std::string &path) const -{ - if (path.size() > PATH_MAX) { - APP_LOGE("CreateFile the length of path is too long"); - return false; - } - - std::string realPath; - realPath.reserve(PATH_MAX); - realPath.resize(PATH_MAX - 1); - - if (realpath(path.c_str(), &(realPath[0])) != nullptr) { - APP_LOGW("CreateFile-translate:%{public}s already exist path", realPath.c_str()); - return true; - } - - mode_t mode = 0666; - int fd = open(realPath.c_str(), O_RDWR | O_CREAT, mode); - if (fd == -1) { - APP_LOGE("CreateFile-open:%{public}s error", realPath.c_str()); - return false; - } - if (close(fd) != 0) { - APP_LOGW("CreateFile-close:%{public}s error", realPath.c_str()); - return false; - } - - if (access(realPath.c_str(), F_OK) != 0) { - APP_LOGE("CreateFile-checkFile:%{public}s not exist", realPath.c_str()); - return false; - } - return true; -} - void BmsSearchSystemTest::Install( const std::string &bundleFilePath, const InstallFlag installFlag, std::vector &resvec) { @@ -303,7 +272,7 @@ void BmsSearchSystemTest::Install( installParam.installFlag = installFlag; installParam.userId = Constants::DEFAULT_USERID; sptr statusReceiver = (new (std::nothrow) StatusReceiverImpl()); - ASSERT_NE(statusReceiver, nullptr); + EXPECT_NE(statusReceiver, nullptr); installerProxy->Install(bundleFilePath, installParam, statusReceiver); resvec.push_back(statusReceiver->GetResultMsg()); } @@ -324,7 +293,7 @@ void BmsSearchSystemTest::Uninstall(const std::string &bundleName, std::vector statusReceiver = (new (std::nothrow) StatusReceiverImpl()); - ASSERT_NE(statusReceiver, nullptr); + EXPECT_NE(statusReceiver, nullptr); installerProxy->Uninstall(bundleName, installParam, statusReceiver); resvec.push_back(statusReceiver->GetResultMsg()); } @@ -345,7 +314,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_0100, Function | MediumTest | Level1) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } BundleInfo bundleInfo; @@ -379,7 +348,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_0200, Function | MediumTest | Level1) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } BundleInfo bundleInfo; @@ -412,7 +381,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_0300, Function | MediumTest | Level2) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } appName = BASE_BUNDLE_NAME + "e"; @@ -437,7 +406,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_0400, Function | MediumTest | Level1) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } ApplicationInfo appInfo; @@ -465,7 +434,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_0500, Function | MediumTest | Level1) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } ApplicationInfo appInfo; @@ -494,7 +463,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_0600, Function | MediumTest | Level2) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } ApplicationInfo appInfo; @@ -524,7 +493,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_0700, Function | MediumTest | Level1) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getInfoResult = bundleMgrProxy->GetBundleArchiveInfo(hapFilePath, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); EXPECT_TRUE(getInfoResult); @@ -548,7 +517,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_0800, Function | MediumTest | Level1) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getInfoResult = bundleMgrProxy->GetBundleArchiveInfo(hapFilePath, BundleFlag::GET_BUNDLE_WITH_ABILITIES, bundleInfo); @@ -583,7 +552,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_0900, Function | MediumTest | Level2) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } hapFilePath = THIRD_BUNDLE_PATH + "tt.hap"; bool getInfoResult = bundleMgrProxy->GetBundleArchiveInfo(hapFilePath, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); @@ -607,7 +576,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_1000, Function | MediumTest | Level1) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } int userId = Constants::DEFAULT_USERID; @@ -632,7 +601,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_1100, Function | MediumTest | Level2) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } int userId = Constants::DEFAULT_USERID; @@ -658,7 +627,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_1200, Function | MediumTest | Level1) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } BundleInfo bundleInfo; @@ -689,14 +658,14 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_1300, Function | MediumTest | Level1) Install(bundleFilePath, InstallFlag::NORMAL, resvec); std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success"); + EXPECT_EQ(installResult, "Success"); resvec.clear(); bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle8.hap"; Install(bundleFilePath, InstallFlag::NORMAL, resvec); installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success"); + EXPECT_EQ(installResult, "Success"); std::string bundleName = BASE_BUNDLE_NAME + "3"; std::string appPermission = "com.example.permission"; @@ -704,7 +673,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_1300, Function | MediumTest | Level1) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } int result = bundleMgrProxy->CheckPermission(bundleName, appPermission); EXPECT_EQ(result, 0); @@ -712,12 +681,12 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_1300, Function | MediumTest | Level1) std::vector resvec2; Uninstall(bundleName, resvec2); std::string uninstallResult = commonTool.VectorToStr(resvec2); - ASSERT_EQ(uninstallResult, "Success"); + EXPECT_EQ(uninstallResult, "Success"); resvec2.clear(); bundleName = BASE_BUNDLE_NAME + "2"; Uninstall(bundleName, resvec2); uninstallResult = commonTool.VectorToStr(resvec2); - ASSERT_EQ(uninstallResult, "Success"); + EXPECT_EQ(uninstallResult, "Success"); std::cout << "END BMS_SEARCH_1300" << std::endl; } @@ -737,7 +706,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_1400, Function | MediumTest | Level1) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } int result = bundleMgrProxy->CheckPermission(bundleName, appPermission); @@ -760,7 +729,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_1500, Function | MediumTest | Level1) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string installResult; for (int i = 7; i < 9; i++) { @@ -768,7 +737,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_1500, Function | MediumTest | Level1) std::string hapFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle" + std::to_string(i) + ".hap"; Install(hapFilePath, InstallFlag::NORMAL, resvec); installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; } std::vector bundleInfos; @@ -802,7 +771,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_1600, Function | MediumTest | Level1) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::vector bundleInfos; bool getInfoResult = bundleMgrProxy->GetBundleInfos(BundleFlag::GET_BUNDLE_DEFAULT, bundleInfos); @@ -824,7 +793,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_1700, Function | MediumTest | Level1) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string installResult; int userId = Constants::DEFAULT_USERID; @@ -834,7 +803,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_1700, Function | MediumTest | Level1) std::string appName = BASE_BUNDLE_NAME + std::to_string(i - 5); bool queryResult = QueryJsonFile(appName); - ASSERT_TRUE(queryResult); + EXPECT_TRUE(queryResult); std::vector appInfos; bool getInfoResult = @@ -865,7 +834,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_1800, Function | MediumTest | Level1) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::vector appInfos; bool getInfoResult = @@ -888,7 +857,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_1900, Function | MediumTest | Level1) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } int userId = Constants::DEFAULT_USERID; @@ -912,7 +881,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_2000, Function | MediumTest | Level1) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool queryResult = QueryJsonFile(bundleName); @@ -942,14 +911,14 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_2100, Function | MediumTest | Level1) std::string firstBundleName = BASE_BUNDLE_NAME + "2"; bool queryResult = QueryJsonFile(firstBundleName); - ASSERT_TRUE(queryResult); + EXPECT_TRUE(queryResult); resvec.clear(); std::string hapFilePath2 = THIRD_BUNDLE_PATH + "bmsThirdBundle8.hap"; std::string secondBundleName = BASE_BUNDLE_NAME + "3"; queryResult = QueryJsonFile(secondBundleName); - ASSERT_TRUE(queryResult); + EXPECT_TRUE(queryResult); bundleMgrProxy->CheckPublicKeys(firstBundleName, secondBundleName); for (int32_t i = 2; i <= 3; i++) { @@ -979,7 +948,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_2200, Function | MediumTest | Level1) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } Want want; ElementName name; @@ -1101,7 +1070,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_2800, Function | MediumTest | Level1) CommonTool commonTool; sptr bundleMgrProxy = GetBundleMgrProxy(); std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; bool queryResult = QueryJsonFile(appName); EXPECT_TRUE(queryResult); @@ -1221,7 +1190,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_3300, Function | MediumTest | Level1) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } BundleInfo bundleInfo; @@ -1233,7 +1202,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_3300, Function | MediumTest | Level1) EXPECT_EQ(commonTool.VectorToStr(bundleInfo.modulePublicDirs), "/data/accounts/account_0/appdata/com.third.hiworld.example1/com.third.hiworld.example.h1"); EXPECT_EQ(commonTool.VectorToStr(bundleInfo.hapModuleNames), "com.third.hiworld.example.h1"); - EXPECT_EQ(commonTool.VectorToStr(bundleInfo.moduleNames), "bmsThirdBundle1"); + EXPECT_EQ(commonTool.VectorToStr(bundleInfo.moduleNames), "testability"); std::cout << "END BMS_Search_3300" << std::endl; } @@ -1253,7 +1222,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_3400, Function | MediumTest | Level1) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } ApplicationInfo appInfo; @@ -1291,7 +1260,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_3500, Function | MediumTest | Level1) bool queryResult = bundleMgrProxy->GetHapModuleInfo(abilityInfo, hapModuleInfo); EXPECT_EQ(hapModuleInfo.name, "com.third.hiworld.example.h1"); - EXPECT_EQ(hapModuleInfo.moduleName, "bmsThirdBundle1"); + EXPECT_EQ(hapModuleInfo.moduleName, "testability"); EXPECT_TRUE(queryResult); std::cout << "END BMS_SEARCH_3500" << std::endl; } @@ -1311,7 +1280,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_3600, Function | MediumTest | Level1) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::vector resvec; std::string bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle7.hap"; @@ -1319,14 +1288,14 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_3600, Function | MediumTest | Level1) CommonTool commonTool; sptr bundleStatusCallback = (new (std::nothrow) BundleStatusCallbackImpl()); - ASSERT_NE(bundleStatusCallback, nullptr); + EXPECT_NE(bundleStatusCallback, nullptr); bundleStatusCallback->SetBundleName(appName); bundleMgrProxy->RegisterBundleStatusCallback(bundleStatusCallback); Install(bundleFilePath, InstallFlag::NORMAL, resvec); std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; bool queryResult = QueryJsonFile(appName); - ASSERT_TRUE(queryResult); + EXPECT_TRUE(queryResult); Uninstall(appName, resvec); std::cout << "END BMS_SEARCH_3600" << std::endl; bundleMgrProxy->UnregisterBundleStatusCallback(); @@ -1347,7 +1316,7 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_3700, Function | MediumTest | Level1) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::vector resvec; std::string firstFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle8.hap"; @@ -1357,21 +1326,21 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_3700, Function | MediumTest | Level1) CommonTool commonTool; sptr firstBundleStatusCallback = (new (std::nothrow) BundleStatusCallbackImpl()); - ASSERT_NE(firstBundleStatusCallback, nullptr); + EXPECT_NE(firstBundleStatusCallback, nullptr); firstBundleStatusCallback->SetBundleName(firstAppName); bundleMgrProxy->RegisterBundleStatusCallback(firstBundleStatusCallback); Install(firstFilePath, InstallFlag::NORMAL, resvec); std::string firstinstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(firstinstallResult, "Success") << "install fail!"; + EXPECT_EQ(firstinstallResult, "Success") << "install fail!"; resvec.clear(); sptr secondBundleStatusCallback = (new (std::nothrow) BundleStatusCallbackImpl()); - ASSERT_NE(secondBundleStatusCallback, nullptr); + EXPECT_NE(secondBundleStatusCallback, nullptr); secondBundleStatusCallback->SetBundleName(secondAppName); bundleMgrProxy->RegisterBundleStatusCallback(secondBundleStatusCallback); Install(secondFilePath, InstallFlag::NORMAL, resvec); std::string secondinstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(secondinstallResult, "Success") << "install fail!"; + EXPECT_EQ(secondinstallResult, "Success") << "install fail!"; bundleMgrProxy->ClearBundleStatusCallback(firstBundleStatusCallback); for (int32_t i = 2; i <= 3; i++) { @@ -1397,24 +1366,28 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_3800, Function | MediumTest | Level1) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string appName = BASE_BUNDLE_NAME + "1"; - const std::string testCacheFileNamE1 = BUNDLE_DATA_ROOT_PATH + "/" + appName + "/cache/name1.txt"; - const std::string testCacheFileNamE2 = BUNDLE_DATA_ROOT_PATH + "/" + appName + "/cache/name2.txt"; - bool isSuccess = CreateFile(testCacheFileNamE1); - ASSERT_TRUE(isSuccess); - isSuccess = CreateFile(testCacheFileNamE2); - ASSERT_TRUE(isSuccess); + const std::string testCacheFileNamE1 = BUNDLE_DATA_ROOT_PATH + appName + "/cache/name1.txt"; + const std::string testCacheFileNamE2 = BUNDLE_DATA_ROOT_PATH + appName + "/cache/name2.txt"; + std::ofstream file1(testCacheFileNamE1); + std::ofstream file2(testCacheFileNamE2); + file1.close(); + file2.close(); + int name1Exist = access(testCacheFileNamE1.c_str(), F_OK); + EXPECT_EQ(name1Exist, 0); + int name2Exist = access(testCacheFileNamE2.c_str(), F_OK); + EXPECT_EQ(name2Exist, 0); sptr bundleCleanCacheCallback = (new (std::nothrow) CleanCacheCallBackImpl()); - ASSERT_NE(bundleCleanCacheCallback, nullptr); + EXPECT_NE(bundleCleanCacheCallback, nullptr); bundleMgrProxy->CleanBundleCacheFiles(appName, bundleCleanCacheCallback); EXPECT_TRUE(bundleCleanCacheCallback->GetSucceededResult()); - int name1Exist = access(testCacheFileNamE1.c_str(), F_OK); + name1Exist = access(testCacheFileNamE1.c_str(), F_OK); EXPECT_NE(name1Exist, 0) << "the cache test file1 exists."; - int name2Exist = access(testCacheFileNamE2.c_str(), F_OK); + name2Exist = access(testCacheFileNamE2.c_str(), F_OK); EXPECT_NE(name2Exist, 0) << "the cache test file2 exists."; std::cout << "END BMS_SEARCH_3800" << std::endl; } @@ -1432,22 +1405,26 @@ HWTEST_F(BmsSearchSystemTest, BMS_Search_3900, Function | MediumTest | Level1) sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } std::string appName = BASE_BUNDLE_NAME + "1"; - const std::string testCacheFileNamE1 = BUNDLE_DATA_ROOT_PATH + "/" + appName + "/files/name1.txt"; - const std::string testCacheFileNamE2 = BUNDLE_DATA_ROOT_PATH + "/" + appName + "/files/name2.txt"; - bool isSuccess = CreateFile(testCacheFileNamE1); - ASSERT_TRUE(isSuccess); - isSuccess = CreateFile(testCacheFileNamE2); - ASSERT_TRUE(isSuccess); - bundleMgrProxy->CleanBundleDataFiles(appName); + const std::string testCacheFileNamE1 = BUNDLE_DATA_ROOT_PATH + appName + "/files/name1.txt"; + const std::string testCacheFileNamE2 = BUNDLE_DATA_ROOT_PATH + appName + "/files/name2.txt"; + std::ofstream file1(testCacheFileNamE1); + std::ofstream file2(testCacheFileNamE2); + file1.close(); + file2.close(); int name1Exist = access(testCacheFileNamE1.c_str(), F_OK); - ASSERT_NE(name1Exist, 0) << "the test file1 exists."; + EXPECT_EQ(name1Exist, 0) << "the test file1 exists."; int name2Exist = access(testCacheFileNamE2.c_str(), F_OK); - ASSERT_NE(name2Exist, 0) << "the test file2 exists."; + EXPECT_EQ(name2Exist, 0) << "the test file2 exists."; + bundleMgrProxy->CleanBundleDataFiles(appName); + name1Exist = access(testCacheFileNamE1.c_str(), F_OK); + EXPECT_NE(name1Exist, 0) << "the test file1 exists."; + name2Exist = access(testCacheFileNamE2.c_str(), F_OK); + EXPECT_NE(name2Exist, 0) << "the test file2 exists."; std::cout << "END BMS_SEARCH_3900" << std::endl; } diff --git a/test/systemtest/common/bms/bms_uninstall_system_test/bms_uninstall_system_test.cpp b/test/systemtest/common/bms/bms_uninstall_system_test/bms_uninstall_system_test.cpp index cff6800366..aff2267f59 100755 --- a/test/systemtest/common/bms/bms_uninstall_system_test/bms_uninstall_system_test.cpp +++ b/test/systemtest/common/bms/bms_uninstall_system_test/bms_uninstall_system_test.cpp @@ -188,11 +188,11 @@ void BmsUninstallSystemTest::CheckBundleInfo(const std::string &version, const s sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getInfoRresult = bundleMgrProxy->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); - ASSERT_TRUE(getInfoRresult); + EXPECT_TRUE(getInfoRresult); EXPECT_EQ(bundleInfo.name, bundleName); EXPECT_EQ(bundleInfo.versionName, version); } @@ -282,7 +282,7 @@ void BmsUninstallSystemTest::Install( installParam.installFlag = installFlag; installParam.userId = Constants::DEFAULT_USERID; sptr statusReceiver = (new (std::nothrow) StatusReceiverImpl()); - ASSERT_NE(statusReceiver, nullptr); + EXPECT_NE(statusReceiver, nullptr); installerProxy->Install(bundleFilePath, installParam, statusReceiver); resvec.push_back(statusReceiver->GetResultMsg()); } @@ -303,7 +303,7 @@ void BmsUninstallSystemTest::Uninstall(const std::string &bundleName, std::vecto InstallParam installParam; installParam.userId = Constants::DEFAULT_USERID; sptr statusReceiver = (new (std::nothrow) StatusReceiverImpl()); - ASSERT_NE(statusReceiver, nullptr); + EXPECT_NE(statusReceiver, nullptr); installerProxy->Uninstall(bundleName, installParam, statusReceiver); resvec.push_back(statusReceiver->GetResultMsg()); } @@ -326,7 +326,7 @@ void BmsUninstallSystemTest::HapUninstall( InstallParam installParam; installParam.userId = Constants::DEFAULT_USERID; sptr statusReceiver = (new (std::nothrow) StatusReceiverImpl()); - ASSERT_NE(statusReceiver, nullptr); + EXPECT_NE(statusReceiver, nullptr); installerProxy->Uninstall(bundleName, modulePackage, installParam, statusReceiver); resvec.push_back(statusReceiver->GetResultMsg()); } @@ -348,7 +348,7 @@ void BmsUninstallSystemTest::UninstallWithoutResvec(const std::string &bundleNam } else { InstallParam installParam; sptr statusReceiver = (new (std::nothrow) StatusReceiverImpl()); - ASSERT_NE(statusReceiver, nullptr); + EXPECT_NE(statusReceiver, nullptr); installerProxy->Uninstall(bundleName, installParam, statusReceiver); resvec.push_back(statusReceiver->GetResultMsg()); } @@ -371,11 +371,11 @@ HWTEST_F(BmsUninstallSystemTest, BMS_Uninstall_0100, Function | MediumTest | Lev CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; std::string bundleName = BASE_BUNDLE_NAME + "1"; bool isInstallSucceed = CheckInstallIsSuccess(bundleName); - ASSERT_TRUE(isInstallSucceed); + EXPECT_TRUE(isInstallSucceed); std::string version = "1.0"; CheckBundleInfo(version, bundleName); @@ -383,7 +383,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_Uninstall_0100, Function | MediumTest | Lev resvec.clear(); Uninstall(bundleName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; bool isUninstallSucceed = CheckUninstallIsSuccess(bundleName); EXPECT_TRUE(isUninstallSucceed); @@ -409,7 +409,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_Uninstall_0200, Function | MediumTest | Lev CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; std::string bundleName = BASE_BUNDLE_NAME + "1"; bool isInstallSucceed = CheckInstallIsSuccess(bundleName); @@ -425,7 +425,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_Uninstall_0200, Function | MediumTest | Lev resvec.clear(); Uninstall(bundleName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; bool isUninstallSucceed = CheckUninstallIsSuccess(bundleName); EXPECT_TRUE(isUninstallSucceed); @@ -448,7 +448,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_Uninstall_0300, Function | MediumTest | Lev CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; std::string bundleName = BASE_BUNDLE_NAME + "1"; bool isInstallSucceed = CheckInstallIsSuccess(bundleName); @@ -464,7 +464,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_Uninstall_0300, Function | MediumTest | Lev bundleName = BASE_BUNDLE_NAME + "1"; Uninstall(bundleName, resvec); uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; std::cout << "BMS_Uninstall_0300 end" << std::endl; } @@ -489,7 +489,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_Uninstall_0400, Function | MediumTest | Lev Install(bundleFilePath, InstallFlag::NORMAL, resvec); std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; std::string bundleName = BASE_BUNDLE_NAME + "1"; bool isInstallSucceed = CheckInstallIsSuccess(bundleName); @@ -498,7 +498,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_Uninstall_0400, Function | MediumTest | Lev resvec.clear(); Uninstall(bundleName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; bool isUninstallSucceed = CheckUninstallIsSuccess(bundleName); EXPECT_TRUE(isUninstallSucceed); @@ -523,7 +523,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_Uninstall_0500, Function | MediumTest | Lev CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; std::string bundleName = BASE_BUNDLE_NAME + "1"; bool isInstallSucceed = CheckInstallIsSuccess(bundleName); @@ -557,7 +557,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_Uninstall_0600, Function | MediumTest | Lev Install(bundleFilePath, InstallFlag::NORMAL, resvec); std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; } std::vector> futureVec; @@ -581,7 +581,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_Uninstall_0600, Function | MediumTest | Lev sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getInfoRresult = bundleMgrProxy->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); EXPECT_FALSE(getInfoRresult); @@ -665,7 +665,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_Uninstall_0900, Function | MediumTest | Lev CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; std::string bundleName = BASE_BUNDLE_NAME + "1"; std::string modulePackage = BASE_MODULE_PACKAGE + ".h1"; @@ -675,7 +675,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_Uninstall_0900, Function | MediumTest | Lev resvec.clear(); HapUninstall(bundleName, modulePackage, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; bool isUninstallSucceed = CheckUninstallIsSuccess(bundleName); EXPECT_TRUE(isUninstallSucceed); @@ -706,18 +706,18 @@ HWTEST_F(BmsUninstallSystemTest, BMS_Uninstall_1000, Function | MediumTest | Lev sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } Install(bundleFilePath, InstallFlag::NORMAL, resvec); std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; resvec.clear(); bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle4.hap"; Install(bundleFilePath, InstallFlag::NORMAL, resvec); installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; bool checkResult = CheckAppDirExist(bundleName, modulePackage1); EXPECT_TRUE(checkResult); @@ -727,7 +727,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_Uninstall_1000, Function | MediumTest | Lev resvec.clear(); HapUninstall(bundleName, modulePackage2, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; checkResult = CheckAppDirExist(bundleName, modulePackage1); EXPECT_TRUE(checkResult); @@ -765,7 +765,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_Uninstall_1100, Function | MediumTest | Lev CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; std::string bundleName = BASE_BUNDLE_NAME + "5"; bool isInstallSucceed = CheckInstallIsSuccess(bundleName); @@ -774,7 +774,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_Uninstall_1100, Function | MediumTest | Lev resvec.clear(); Uninstall(bundleName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; bool isUninstallSucceed = CheckUninstallIsSuccess(bundleName); EXPECT_TRUE(isUninstallSucceed); @@ -797,12 +797,12 @@ HWTEST_F(BmsUninstallSystemTest, BMS_Uninstall_1200, Function | MediumTest | Lev sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } Install(bundleFilePath, InstallFlag::NORMAL, resvec); CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; std::string bundleName = BASE_BUNDLE_NAME + "5"; bool isInstallSucceed = CheckInstallIsSuccess(bundleName); EXPECT_TRUE(isInstallSucceed); @@ -812,7 +812,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_Uninstall_1200, Function | MediumTest | Lev bool result = bundleMgrProxy->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); EXPECT_FALSE(result); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; bool isUninstallSucceed = CheckUninstallIsSuccess(bundleName); EXPECT_TRUE(isUninstallSucceed); std::cout << "BMS_Uninstall_1200 end" << std::endl; @@ -840,18 +840,18 @@ HWTEST_F(BmsUninstallSystemTest, BMS_Uninstall_1300, Function | MediumTest | Lev sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } Install(bundleFilePath, InstallFlag::NORMAL, resvec); std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; resvec.clear(); bundleFilePath = THIRD_BUNDLE_PATH + "bmsThirdBundle4.hap"; Install(bundleFilePath, InstallFlag::NORMAL, resvec); installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; bool checkResult = CheckAppDirExist(bundleName, modulePackage1); EXPECT_TRUE(checkResult); @@ -861,7 +861,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_Uninstall_1300, Function | MediumTest | Lev resvec.clear(); HapUninstall(bundleName, modulePackage1, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; checkResult = CheckAppDirExist(bundleName, modulePackage2); EXPECT_TRUE(checkResult); @@ -900,7 +900,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_BundleInfoDeletion_0100, Function | MediumT CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; std::string bundleName = BASE_BUNDLE_NAME + "1"; bool isInstallSucceed = CheckInstallIsSuccess(bundleName); @@ -909,7 +909,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_BundleInfoDeletion_0100, Function | MediumT resvec.clear(); Uninstall(bundleName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; bool isUninstallSucceed = CheckUninstallIsSuccess(bundleName); EXPECT_TRUE(isUninstallSucceed); @@ -918,7 +918,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_BundleInfoDeletion_0100, Function | MediumT sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool result = bundleMgrProxy->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); EXPECT_FALSE(result); @@ -942,7 +942,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_BundleInfoDeletion_0200, Function | MediumT CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; std::string bundleName = BASE_BUNDLE_NAME + "1"; bool isInstallSucceed = CheckInstallIsSuccess(bundleName); @@ -951,7 +951,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_BundleInfoDeletion_0200, Function | MediumT resvec.clear(); Uninstall(bundleName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; bool isUninstallSucceed = CheckUninstallIsSuccess(bundleName); EXPECT_TRUE(isUninstallSucceed); @@ -961,7 +961,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_BundleInfoDeletion_0200, Function | MediumT sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool result = bundleMgrProxy->CheckPermission(bundleName, permission); EXPECT_TRUE(result); @@ -985,7 +985,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_BundleInfoDeletion_0300, Function | MediumT CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; std::string bundleName = BASE_BUNDLE_NAME + "1"; bool isInstallSucceed = CheckInstallIsSuccess(bundleName); @@ -996,7 +996,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_BundleInfoDeletion_0300, Function | MediumT resvec.clear(); Uninstall(bundleName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; bool isUninstallSucceed = CheckUninstallIsSuccess(bundleName); EXPECT_TRUE(isUninstallSucceed); @@ -1005,7 +1005,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_BundleInfoDeletion_0300, Function | MediumT sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } int result = bundleMgrProxy->GetUidByBundleName(bundleName, userId); EXPECT_EQ(result, -1); @@ -1029,7 +1029,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_BundleInfoDeletion_0400, Function | MediumT CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; std::string bundleName = BASE_BUNDLE_NAME + "1"; bool isInstallSucceed = CheckInstallIsSuccess(bundleName); @@ -1038,7 +1038,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_BundleInfoDeletion_0400, Function | MediumT sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool infoResult = bundleMgrProxy->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); EXPECT_TRUE(infoResult); @@ -1054,7 +1054,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_BundleInfoDeletion_0400, Function | MediumT resvec.clear(); Uninstall(bundleName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; bool isUninstallSucceed = CheckUninstallIsSuccess(bundleName); EXPECT_TRUE(isUninstallSucceed); @@ -1088,7 +1088,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_DirDeletion_0100, Function | MediumTest | L CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; std::string bundleName = BASE_BUNDLE_NAME + "1"; bool isInstallSucceed = CheckInstallIsSuccess(bundleName); @@ -1103,7 +1103,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_DirDeletion_0100, Function | MediumTest | L resvec.clear(); Uninstall(bundleName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; bool isUninstallSucceed = CheckUninstallIsSuccess(bundleName); EXPECT_TRUE(isUninstallSucceed); @@ -1130,7 +1130,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_DirDeletion_0200, Function | MediumTest | L CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; std::string bundleName = BASE_BUNDLE_NAME + "1"; bool isInstallSucceed = CheckInstallIsSuccess(bundleName); @@ -1139,7 +1139,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_DirDeletion_0200, Function | MediumTest | L resvec.clear(); Uninstall(bundleName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; bool isUninstallSucceed = CheckUninstallIsSuccess(bundleName); EXPECT_TRUE(isUninstallSucceed); @@ -1166,7 +1166,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_DirDeletion_0300, Function | MediumTest | L CommonTool commonTool; std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; std::string bundleName = BASE_BUNDLE_NAME + "1"; bool isInstallSucceed = CheckInstallIsSuccess(bundleName); @@ -1190,7 +1190,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_DirDeletion_0300, Function | MediumTest | L resvec.clear(); Uninstall(bundleName, resvec); uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallResult, "Success") << "uninstall fail!"; std::cout << "BMS_DirDeletion_0300 end" << std::endl; } @@ -1212,7 +1212,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_UidTest_0100, Function | MediumTest | Level Install(bundleFilePath, InstallFlag::NORMAL, resvec); std::string installResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(installResult, "Success") << "install fail!"; + EXPECT_EQ(installResult, "Success") << "install fail!"; std::string bundleName = BASE_BUNDLE_NAME + std::to_string(i - 5); bool isInstallSucceed = CheckInstallIsSuccess(bundleName); EXPECT_TRUE(isInstallSucceed); @@ -1221,7 +1221,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_UidTest_0100, Function | MediumTest | Level sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } int uid = bundleMgrProxy->GetUidByBundleName(bundleName, userId); EXPECT_GE(uid, Constants::BASE_APP_UID); @@ -1245,7 +1245,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_UidTest_0100, Function | MediumTest | Level sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } bool getInfoRresult = bundleMgrProxy->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); EXPECT_FALSE(getInfoRresult); @@ -1273,7 +1273,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_UidTest_0200, Function | MediumTest | Level sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } int uid = bundleMgrProxy->GetUidByBundleName(bundleName, userId); EXPECT_GE(uid, Constants::BASE_SYS_VEN_UID); @@ -1306,7 +1306,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_UidTest_0300, Function | MediumTest | Level sptr bundleMgrProxy = GetBundleMgrProxy(); if (!bundleMgrProxy) { APP_LOGE("bundle mgr proxy is nullptr."); - ASSERT_EQ(bundleMgrProxy, nullptr); + EXPECT_EQ(bundleMgrProxy, nullptr); } int uid = bundleMgrProxy->GetUidByBundleName(bundleName, userId); EXPECT_GE(uid, Constants::BASE_SYS_UID); @@ -1314,7 +1314,7 @@ HWTEST_F(BmsUninstallSystemTest, BMS_UidTest_0300, Function | MediumTest | Level Uninstall(bundleName, resvec); std::string uninstallResult = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallResult, "Failure[MSG_ERR_UNINSTALL_SYSTEM_APP_ERROR]"); + EXPECT_EQ(uninstallResult, "Failure[MSG_ERR_UNINSTALL_SYSTEM_APP_ERROR]"); bool isUninstallSucceed = CheckUninstallIsSuccess(bundleName); EXPECT_FALSE(isUninstallSucceed); @@ -1343,30 +1343,30 @@ HWTEST_F(BmsUninstallSystemTest, BMS_DFX_0500, Function | MediumTest | Level2) CommonTool commonTool; Install(bundleFilePath1, InstallFlag::NORMAL, resvec); installMsg = commonTool.VectorToStr(resvec); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath1; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath1; resvec.clear(); std::string bundleFilePath2 = THIRD_BUNDLE_PATH + "bmsThirdBundle4.hap"; Install(bundleFilePath2, InstallFlag::NORMAL, resvec); installMsg = commonTool.VectorToStr(resvec); - ASSERT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath2; + EXPECT_EQ(installMsg, "Success") << "install fail!" << bundleFilePath2; resvec.clear(); std::string bundleName = BASE_BUNDLE_NAME + "1"; HapUninstall(bundleName, modulePackage1, resvec); std::string uninstallMsg = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallMsg, "Success") << "unistall fail!"; + EXPECT_EQ(uninstallMsg, "Success") << "unistall fail!"; resvec.clear(); HapUninstall(bundleName, modulePackage1, resvec); uninstallMsg = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallMsg, "Failure[ERR_UNINSTALL_MISSING_INSTALLED_MODULE]"); + EXPECT_EQ(uninstallMsg, "Failure[ERR_UNINSTALL_MISSING_INSTALLED_MODULE]"); resvec.clear(); HapUninstall(bundleName, modulePackage2, resvec); uninstallMsg = commonTool.VectorToStr(resvec); - ASSERT_EQ(uninstallMsg, "Success") << "uninstall fail!"; + EXPECT_EQ(uninstallMsg, "Success") << "uninstall fail!"; std::cout << "END BMS_DFX_0500" << std::endl; } diff --git a/test/systemtest/common/task_dispatcher/BUILD.gn b/test/systemtest/common/task_dispatcher/BUILD.gn index c3cfdbf7e4..d381007b93 100755 --- a/test/systemtest/common/task_dispatcher/BUILD.gn +++ b/test/systemtest/common/task_dispatcher/BUILD.gn @@ -34,7 +34,7 @@ ohos_systemtest("task_dispatcher_test") { include_dirs = [ "//foundation/distributedschedule/safwk/services/safwk/include", "//foundation/appexecfwk/standard/test/systemtest/common/task_dispatcher/include", - + "//third_party/jsoncpp/include", "//foundation/appexecfwk/standard/test/systemtest/common/ams/tool/include", "//base/notification/ces_standard/test/systemtest/common/resource", ] @@ -71,7 +71,7 @@ ohos_systemtest("task_dispatcher_test") { "//foundation/distributedschedule/dmsfwk/interfaces/innerkits/uri:zuri", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", "//third_party/googletest:gtest_main", - "//utils/native/base:utils", + "//third_party/jsoncpp:jsoncpp", "//utils/native/base:utils", ] diff --git a/tools/bm/include/bundle_command.h b/tools/bm/include/bundle_command.h index e66f79976d..6657bec859 100644 --- a/tools/bm/include/bundle_command.h +++ b/tools/bm/include/bundle_command.h @@ -89,8 +89,8 @@ private: std::string DumpBundleInfo() const; std::string DumpBundleInfos() const; - int32_t InstallOperation(const std::string bundlePath, const InstallFlag installFlag) const; - int32_t UninstallOperation(const std::string bundleName, const std::string moduleName) const; + int32_t InstallOperation(const std::string &bundlePath, InstallParam &installParam) const; + int32_t UninstallOperation(const std::string &bundleName, const std::string &moduleName) const; sptr bundleMgrProxy_; sptr bundleInstallerProxy_; diff --git a/tools/bm/src/bundle_command.cpp b/tools/bm/src/bundle_command.cpp index 570559b917..913e70e6bb 100644 --- a/tools/bm/src/bundle_command.cpp +++ b/tools/bm/src/bundle_command.cpp @@ -30,11 +30,12 @@ namespace AppExecFwk { namespace { const std::string BUNDLE_NAME_EMPTY = ""; -const std::string SHORT_OPTIONS = "hp:rn:m:ai"; +const std::string SHORT_OPTIONS = "hp:rfn:m:ai"; const struct option LONG_OPTIONS[] = { {"help", no_argument, nullptr, 'h'}, {"bundle-path", required_argument, nullptr, 'p'}, {"replace", no_argument, nullptr, 'r'}, + {"force", no_argument, nullptr, 'f'}, {"bundle-name", required_argument, nullptr, 'n'}, {"module-name", required_argument, nullptr, 'm'}, {"all", no_argument, nullptr, 'a'}, @@ -321,7 +322,9 @@ ErrCode BundleManagerShellCommand::RunAsHelpCommand() ErrCode BundleManagerShellCommand::RunAsInstallCommand() { int result = OHOS::ERR_OK; + InstallFlag installFlag = InstallFlag::NORMAL; + bool noCheckSignature = false; int option = -1; int counter = 0; @@ -419,6 +422,12 @@ ErrCode BundleManagerShellCommand::RunAsInstallCommand() installFlag = InstallFlag::REPLACE_EXISTING; break; } + case 'f': { + // 'bm install -f' + // 'bm install -f' + noCheckSignature = true; + break; + } case 0: { break; } @@ -441,7 +450,11 @@ ErrCode BundleManagerShellCommand::RunAsInstallCommand() if (result != OHOS::ERR_OK) { resultReceiver_.append(HELP_MSG_INSTALL); } else { - int32_t installResult = InstallOperation(bundlePath, installFlag); + InstallParam installParam; + installParam.installFlag = installFlag; + installParam.noCheckSignature = noCheckSignature; + + int32_t installResult = InstallOperation(bundlePath, installParam); if (installResult == OHOS::ERR_OK) { resultReceiver_ = STRING_INSTALL_BUNDLE_OK + "\n"; } else { @@ -745,7 +758,7 @@ std::string BundleManagerShellCommand::DumpBundleInfo() const return dumpResults; } -int32_t BundleManagerShellCommand::InstallOperation(const std::string bundlePath, const InstallFlag installFlag) const +int32_t BundleManagerShellCommand::InstallOperation(const std::string &bundlePath, InstallParam &installParam) const { std::string absoluteBundlePath = ""; if (bundlePath.size() > 0) { @@ -769,17 +782,16 @@ int32_t BundleManagerShellCommand::InstallOperation(const std::string bundlePath APP_LOGI("bundlePath: %{public}s", bundlePath.c_str()); APP_LOGI("absoluteBundlePath: %{public}s", absoluteBundlePath.c_str()); - sptr statusReceiver(new StatusReceiverImpl()); - InstallParam installParam; - installParam.installFlag = installFlag; installParam.userId = 0; + sptr statusReceiver(new StatusReceiverImpl()); bundleInstallerProxy_->Install(absoluteBundlePath, installParam, statusReceiver); return statusReceiver->GetResultCode(); } -int32_t BundleManagerShellCommand::UninstallOperation(const std::string bundleName, const std::string moduleName) const +int32_t BundleManagerShellCommand::UninstallOperation( + const std::string &bundleName, const std::string &moduleName) const { sptr statusReceiver(new StatusReceiverImpl()); InstallParam installParam; diff --git a/tools/test/mock/mock_bundle_mgr_host.h b/tools/test/mock/mock_bundle_mgr_host.h index 9df3ac8d90..648aeb1ef8 100644 --- a/tools/test/mock/mock_bundle_mgr_host.h +++ b/tools/test/mock/mock_bundle_mgr_host.h @@ -40,6 +40,7 @@ public: MOCK_METHOD1(CheckIsSystemAppByUid, bool(const int uid)); MOCK_METHOD2(GetBundleInfosByMetaData, bool(const std::string &metaData, std::vector &bundleInfos)); MOCK_METHOD2(QueryAbilityInfo, bool(const Want &want, AbilityInfo &abilityInfo)); + MOCK_METHOD2(QueryAbilityInfos, bool(const Want &want, std::vector &abilityInfos)); MOCK_METHOD2(QueryAbilityInfoByUri, bool(const std::string &abilityUri, AbilityInfo &abilityInfo)); MOCK_METHOD1(QueryKeepAliveBundleInfos, bool(std::vector &bundleInfos)); MOCK_METHOD2(GetAbilityLabel, std::string(const std::string &bundleName, const std::string &className)); @@ -86,6 +87,9 @@ public: MOCK_METHOD3(GetFormsInfoByModule, bool(const std::string &bundleName, const std::string &moduleName, std::vector &formInfos)); MOCK_METHOD2(GetShortcutInfos, bool(const std::string &bundleName, std::vector &shortcutInfos)); + MOCK_METHOD2(GetModuleUsageRecords, + bool(const int32_t number, std::vector &moduleUsageRecords)); + MOCK_METHOD3(NotifyActivityLifeStatus, bool(const std::string &bundleName, const std::string &abilityName, const int64_t launchTime)); }; } // namespace AppExecFwk diff --git a/tools/test/moduletest/bm/BUILD.gn b/tools/test/moduletest/bm/BUILD.gn index 980925444e..6ba04f9cab 100644 --- a/tools/test/moduletest/bm/BUILD.gn +++ b/tools/test/moduletest/bm/BUILD.gn @@ -9,7 +9,7 @@ # 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. +# limitations under the License. import("//build/test.gni") import("//foundation/appexecfwk/standard/appexecfwk.gni") @@ -58,6 +58,7 @@ ohos_moduletest("bundle_command_dump_module_test") { "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", "${appexecfwk_path}/services/bundlemgr:libbms", + "//foundation/distributeddatamgr/distributeddatamgr/interfaces/innerkits/distributeddata:distributeddata_inner", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", "//third_party/googletest:gmock_main", "//third_party/googletest:gtest_main", @@ -65,6 +66,7 @@ ohos_moduletest("bundle_command_dump_module_test") { ] external_deps = [ + "ces_standard:cesfwk_innerkits", "hiviewdfx_hilog_native:libhilog", "ipc:ipc_core", ] @@ -96,6 +98,7 @@ ohos_moduletest("bundle_command_install_module_test") { "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", "${appexecfwk_path}/services/bundlemgr:libbms", + "//foundation/distributeddatamgr/distributeddatamgr/interfaces/innerkits/distributeddata:distributeddata_inner", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", "//third_party/googletest:gmock_main", "//third_party/googletest:gtest_main", @@ -103,6 +106,7 @@ ohos_moduletest("bundle_command_install_module_test") { ] external_deps = [ + "ces_standard:cesfwk_innerkits", "hiviewdfx_hilog_native:libhilog", "ipc:ipc_core", ] @@ -134,6 +138,7 @@ ohos_moduletest("bundle_command_uninstall_module_test") { "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", "${appexecfwk_path}/services/bundlemgr:libbms", + "//foundation/distributeddatamgr/distributeddatamgr/interfaces/innerkits/distributeddata:distributeddata_inner", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", "//third_party/googletest:gmock_main", "//third_party/googletest:gtest_main", @@ -141,6 +146,7 @@ ohos_moduletest("bundle_command_uninstall_module_test") { ] external_deps = [ + "ces_standard:cesfwk_innerkits", "hiviewdfx_hilog_native:libhilog", "ipc:ipc_core", ] diff --git a/tools/test/systemtest/bm/BUILD.gn b/tools/test/systemtest/bm/BUILD.gn old mode 100644 new mode 100755 index 858d7bb250..f0157df584 --- a/tools/test/systemtest/bm/BUILD.gn +++ b/tools/test/systemtest/bm/BUILD.gn @@ -19,7 +19,10 @@ module_output_path = "appexecfwk_standard/tools" ohos_systemtest("bundle_command_install_system_test") { module_out_path = module_output_path - include_dirs = [ "${aafwk_path}/tools/test/systemtest/aa" ] + include_dirs = [ + "${aafwk_path}/tools/test/systemtest/aa", + "//third_party/jsoncpp/include", + ] sources = [ "${aafwk_path}/tools/test/systemtest/aa/tool_system_test.cpp", @@ -36,6 +39,7 @@ ohos_systemtest("bundle_command_install_system_test") { deps = [ "${aafwk_path}/tools/aa:tools_aa_source_set", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", ] external_deps = [ @@ -47,7 +51,10 @@ ohos_systemtest("bundle_command_install_system_test") { ohos_systemtest("bundle_command_uninstall_system_test") { module_out_path = module_output_path - include_dirs = [ "${aafwk_path}/tools/test/systemtest/aa" ] + include_dirs = [ + "${aafwk_path}/tools/test/systemtest/aa", + "//third_party/jsoncpp/include", + ] sources = [ "${aafwk_path}/tools/test/systemtest/aa/tool_system_test.cpp", @@ -64,6 +71,7 @@ ohos_systemtest("bundle_command_uninstall_system_test") { deps = [ "${aafwk_path}/tools/aa:tools_aa_source_set", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", ] external_deps = [ @@ -75,7 +83,10 @@ ohos_systemtest("bundle_command_uninstall_system_test") { ohos_systemtest("bundle_command_dump_system_test") { module_out_path = module_output_path - include_dirs = [ "${aafwk_path}/tools/test/systemtest/aa" ] + include_dirs = [ + "${aafwk_path}/tools/test/systemtest/aa", + "//third_party/jsoncpp/include", + ] sources = [ "${aafwk_path}/tools/test/systemtest/aa/tool_system_test.cpp", @@ -92,6 +103,7 @@ ohos_systemtest("bundle_command_dump_system_test") { deps = [ "${aafwk_path}/tools/aa:tools_aa_source_set", "//third_party/googletest:gtest_main", + "//third_party/jsoncpp:jsoncpp", ] external_deps = [ diff --git a/tools/test/systemtest/bm/bundle_command_install_system_test.cpp b/tools/test/systemtest/bm/bundle_command_install_system_test.cpp index 8b256dde93..8bafccc461 100644 --- a/tools/test/systemtest/bm/bundle_command_install_system_test.cpp +++ b/tools/test/systemtest/bm/bundle_command_install_system_test.cpp @@ -28,6 +28,8 @@ namespace { const std::string STRING_BUNDLE_PATH = "/data/test/resource/bm/pageAbilityBundleForInstall.hap"; const std::string STRING_BUNDLE_PATH_INVALID = STRING_BUNDLE_PATH + ".invalid"; const std::string STRING_BUNDLE_NAME = "com.ohos.tools.pageAbilityBundleForInstall"; + +const std::string STRING_BUNDLE_PATH_NO_SIGNATURE = "/data/test/resource/bm/pageAbilityBundleForInstallNoSignature.hap"; } // namespace class BmCommandInstallSystemTest : public ::testing::Test { @@ -106,3 +108,43 @@ HWTEST_F(BmCommandInstallSystemTest, Bm_Command_Install_SystemTest_0300, Functio // uninstall the bundle ToolSystemTest::UninstallBundle(STRING_BUNDLE_NAME); } + +/** + * @tc.number: Bm_Command_Install_SystemTest_0400 + * @tc.name: ExecCommand + * @tc.desc: Verify the "bm install -p " command. + */ +HWTEST_F(BmCommandInstallSystemTest, Bm_Command_Install_SystemTest_0400, Function | MediumTest | Level1) +{ + // uninstall the bundle + ToolSystemTest::UninstallBundle(STRING_BUNDLE_NAME); + + // install a valid bundle with no signature + std::string command = "bm install -p " + STRING_BUNDLE_PATH_NO_SIGNATURE; + std::string commandResult = ToolSystemTest::ExecuteCommand(command); + + EXPECT_NE(commandResult, STRING_INSTALL_BUNDLE_OK + "\n"); + + // uninstall the bundle + ToolSystemTest::UninstallBundle(STRING_BUNDLE_NAME); +} + +/** + * @tc.number: Bm_Command_Install_SystemTest_0500 + * @tc.name: ExecCommand + * @tc.desc: Verify the "bm install -p -f" command. + */ +HWTEST_F(BmCommandInstallSystemTest, Bm_Command_Install_SystemTest_0500, Function | MediumTest | Level1) +{ + // uninstall the bundle + ToolSystemTest::UninstallBundle(STRING_BUNDLE_NAME); + + // install a valid bundle with no signature + std::string command = "bm install -p " + STRING_BUNDLE_PATH_NO_SIGNATURE + " -f"; + std::string commandResult = ToolSystemTest::ExecuteCommand(command); + + EXPECT_EQ(commandResult, STRING_INSTALL_BUNDLE_OK + "\n"); + + // uninstall the bundle + ToolSystemTest::UninstallBundle(STRING_BUNDLE_NAME); +} diff --git a/tools/test/unittest/bm/BUILD.gn b/tools/test/unittest/bm/BUILD.gn index 871dd3ba95..3f010a2d43 100644 --- a/tools/test/unittest/bm/BUILD.gn +++ b/tools/test/unittest/bm/BUILD.gn @@ -60,6 +60,7 @@ ohos_unittest("bundle_command_dump_test") { "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", "${appexecfwk_path}/services/bundlemgr:libbms", + "//foundation/distributeddatamgr/distributeddatamgr/interfaces/innerkits/distributeddata:distributeddata_inner", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", "//third_party/googletest:gmock_main", "//third_party/googletest:gtest_main", @@ -67,6 +68,7 @@ ohos_unittest("bundle_command_dump_test") { ] external_deps = [ + "ces_standard:cesfwk_innerkits", "hiviewdfx_hilog_native:libhilog", "ipc:ipc_core", ] @@ -102,6 +104,7 @@ ohos_unittest("bundle_command_install_test") { "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", "${appexecfwk_path}/services/bundlemgr:libbms", + "//foundation/distributeddatamgr/distributeddatamgr/interfaces/innerkits/distributeddata:distributeddata_inner", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", "//third_party/googletest:gmock_main", "//third_party/googletest:gtest_main", @@ -109,6 +112,7 @@ ohos_unittest("bundle_command_install_test") { ] external_deps = [ + "ces_standard:cesfwk_innerkits", "hiviewdfx_hilog_native:libhilog", "ipc:ipc_core", ] @@ -144,6 +148,7 @@ ohos_unittest("bundle_command_test") { "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", "${appexecfwk_path}/services/bundlemgr:libbms", + "//foundation/distributeddatamgr/distributeddatamgr/interfaces/innerkits/distributeddata:distributeddata_inner", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", "//third_party/googletest:gmock_main", "//third_party/googletest:gtest_main", @@ -151,6 +156,7 @@ ohos_unittest("bundle_command_test") { ] external_deps = [ + "ces_standard:cesfwk_innerkits", "hiviewdfx_hilog_native:libhilog", "ipc:ipc_core", ] @@ -186,6 +192,7 @@ ohos_unittest("bundle_command_uninstall_test") { "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", "${appexecfwk_path}/services/bundlemgr:libbms", + "//foundation/distributeddatamgr/distributeddatamgr/interfaces/innerkits/distributeddata:distributeddata_inner", "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", "//third_party/googletest:gmock_main", "//third_party/googletest:gtest_main", @@ -193,6 +200,7 @@ ohos_unittest("bundle_command_uninstall_test") { ] external_deps = [ + "ces_standard:cesfwk_innerkits", "hiviewdfx_hilog_native:libhilog", "ipc:ipc_core", ] diff --git a/tools/test/unittest/bm/bundle_command_install_test.cpp b/tools/test/unittest/bm/bundle_command_install_test.cpp index 482e281c2b..0d77c76c30 100644 --- a/tools/test/unittest/bm/bundle_command_install_test.cpp +++ b/tools/test/unittest/bm/bundle_command_install_test.cpp @@ -391,3 +391,55 @@ HWTEST_F(BmCommandInstallTest, Bm_Command_Install_1300, Function | MediumTest | EXPECT_EQ(cmd.ExecCommand(), STRING_INSTALL_BUNDLE_OK + "\n"); } + +/** + * @tc.number: Bm_Command_Install_1400 + * @tc.name: ExecCommand + * @tc.desc: Verify the "bm install -p -f" command. + */ +HWTEST_F(BmCommandInstallTest, Bm_Command_Install_1400, Function | MediumTest | Level1) +{ + // install a bundle + char *argv[] = { + (char *)TOOL_NAME.c_str(), + (char *)cmd_.c_str(), + (char *)"-p", + (char *)STRING_BUNDLE_PATH.c_str(), + (char *)"-f", + (char *)"", + }; + int argc = sizeof(argv) / sizeof(argv[0]) - 1; + + BundleManagerShellCommand cmd(argc, argv); + + // set the mock objects + SetMockObjects(cmd); + + EXPECT_EQ(cmd.ExecCommand(), STRING_INSTALL_BUNDLE_OK + "\n"); +} + +/** + * @tc.number: Bm_Command_Install_1500 + * @tc.name: ExecCommand + * @tc.desc: Verify the "bm install -f -p " command. + */ +HWTEST_F(BmCommandInstallTest, Bm_Command_Install_1500, Function | MediumTest | Level1) +{ + // install a bundle + char *argv[] = { + (char *)TOOL_NAME.c_str(), + (char *)cmd_.c_str(), + (char *)"-f", + (char *)"-p", + (char *)STRING_BUNDLE_PATH.c_str(), + (char *)"", + }; + int argc = sizeof(argv) / sizeof(argv[0]) - 1; + + BundleManagerShellCommand cmd(argc, argv); + + // set the mock objects + SetMockObjects(cmd); + + EXPECT_EQ(cmd.ExecCommand(), STRING_INSTALL_BUNDLE_OK + "\n"); +} -- Gitee

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 diff --git a/test/resource/ams/ams_page_ability_bundle/amsSystemTestQ.hap b/test/resource/ams/ams_page_ability_bundle/amsSystemTestQ.hap index ccc3098085a02b578204fc26a241f6a8e1599eb6..48227ff4f4d8e6a93ab73314d69eade4c989a8db 100644 GIT binary patch delta 114721 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�Z@P7Na=5Yl8b=B-dZ&Zqsb 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%0D|A_u^ODj=cN=~!D>bUIO-TxaB`jnD+X=L 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