From cd77f12946ae2e1812efc73b172092533ff21017 Mon Sep 17 00:00:00 2001 From: mamingshuai Date: Wed, 2 Jun 2021 00:05:29 +0800 Subject: [PATCH] update OpenHarmony 2.0 Canary --- .gitattributes | 15 + BUILD.gn | 47 + LICENSE | 177 + OAT.xml | 70 + README.en.md | 36 - README.md | 37 - README_zh.md | 96 + appexecfwk.gni | 27 + common/BUILD.gn | 50 + common/log/README.md | 54 + common/log/include/app_log_wrapper.h | 74 + common/log/src/app_log_wrapper.cpp | 44 + common/perf/include/perf_profile.h | 125 + common/perf/src/perf_profile.cpp | 311 + common/test/BUILD.gn | 30 + .../common_appexecfwk_log_test/BUILD.gn | 40 + .../appexecfwk_log_test.cpp | 97 + .../common_perf_profile_test/BUILD.gn | 47 + .../common_perf_profile_test.cpp | 751 + figures/appexecfwk.png | Bin 0 -> 31029 bytes interfaces/innerkits/BUILD.gn | 24 + interfaces/innerkits/appexecfwk_base/BUILD.gn | 63 + .../appexecfwk_base_header.gni | 30 + .../appexecfwk_base/include/ability_info.h | 86 + .../include/app_process_info.h | 65 + .../include/appexecfwk_errors.h | 106 + .../include/application_info.h | 69 + .../include/bundle_constants.h | 116 + .../appexecfwk_base/include/bundle_info.h | 83 + .../appexecfwk_base/include/element_name.h | 85 + .../appexecfwk_base/include/hap_module_info.h | 48 + .../appexecfwk_base/include/install_param.h | 54 + .../appexecfwk_base/include/json_serializer.h | 40 + .../appexecfwk_base/include/module_info.h | 38 + .../appexecfwk_base/include/parcel_macro.h | 45 + .../appexecfwk_base/include/permission_def.h | 43 + .../include/running_process_info.h | 40 + .../appexecfwk_base/src/ability_info.cpp | 261 + .../appexecfwk_base/src/app_process_info.cpp | 71 + .../appexecfwk_base/src/application_info.cpp | 210 + .../appexecfwk_base/src/bundle_info.cpp | 270 + .../appexecfwk_base/src/element_name.cpp | 115 + .../appexecfwk_base/src/hap_module_info.cpp | 97 + .../appexecfwk_base/src/install_param.cpp | 63 + .../appexecfwk_base/src/module_info.cpp | 67 + .../appexecfwk_base/src/permission_def.cpp | 65 + .../src/running_process_info.cpp | 67 + interfaces/innerkits/appexecfwk_core/BUILD.gn | 100 + .../appexecfwk_core/appexecfwk_headers.gni | 29 + .../include/appmgr/ams_mgr_interface.h | 124 + .../include/appmgr/ams_mgr_proxy.h | 115 + .../include/appmgr/ams_mgr_stub.h | 55 + .../include/appmgr/app_launch_data.h | 149 + .../include/appmgr/app_mgr_client.h | 148 + .../include/appmgr/app_mgr_constants.h | 56 + .../include/appmgr/app_mgr_interface.h | 140 + .../include/appmgr/app_mgr_proxy.h | 126 + .../include/appmgr/app_mgr_stub.h | 57 + .../include/appmgr/app_process_data.h | 59 + .../include/appmgr/app_record_id.h | 34 + .../include/appmgr/app_scheduler_host.h | 57 + .../include/appmgr/app_scheduler_interface.h | 144 + .../include/appmgr/app_scheduler_proxy.h | 132 + .../include/appmgr/app_service_manager.h | 39 + .../include/appmgr/app_state_callback_host.h | 65 + .../include/appmgr/app_state_callback_proxy.h | 54 + .../include/appmgr/app_task_info.h | 116 + .../include/appmgr/dummy_configuration.h | 71 + .../include/appmgr/iapp_state_callback.h | 55 + .../include/appmgr/priority_object.h | 167 + .../include/appmgr/process_info.h | 83 + .../appexecfwk_core/include/appmgr/profile.h | 71 + .../bundlemgr/bundle_installer_interface.h | 70 + .../bundlemgr/bundle_installer_proxy.h | 68 + .../include/bundlemgr/bundle_mgr_host.h | 301 + .../include/bundlemgr/bundle_mgr_interface.h | 345 + .../include/bundlemgr/bundle_mgr_proxy.h | 329 + .../bundlemgr/bundle_status_callback_host.h | 40 + .../bundle_status_callback_interface.h | 66 + .../bundlemgr/bundle_status_callback_proxy.h | 50 + .../bundlemgr/clean_cache_callback_host.h | 40 + .../clean_cache_callback_interface.h | 42 + .../bundlemgr/clean_cache_callback_proxy.h | 43 + .../include/bundlemgr/status_receiver_host.h | 40 + .../bundlemgr/status_receiver_interface.h | 100 + .../include/bundlemgr/status_receiver_proxy.h | 54 + .../src/appmgr/ams_mgr_proxy.cpp | 246 + .../src/appmgr/ams_mgr_stub.cpp | 152 + .../src/appmgr/app_launch_data.cpp | 94 + .../src/appmgr/app_mgr_client.cpp | 190 + .../src/appmgr/app_mgr_proxy.cpp | 306 + .../src/appmgr/app_mgr_stub.cpp | 163 + .../src/appmgr/app_process_data.cpp | 54 + .../src/appmgr/app_record_id.cpp | 30 + .../src/appmgr/app_scheduler_host.cpp | 169 + .../src/appmgr/app_scheduler_proxy.cpp | 274 + .../src/appmgr/app_service_manager.cpp | 38 + .../src/appmgr/app_state_callback_host.cpp | 94 + .../src/appmgr/app_state_callback_proxy.cpp | 86 + .../src/appmgr/app_task_info.cpp | 87 + .../src/appmgr/dummy_configuration.cpp | 54 + .../src/appmgr/priority_object.cpp | 146 + .../src/appmgr/process_info.cpp | 66 + .../appexecfwk_core/src/appmgr/profile.cpp | 52 + .../src/bundlemgr/bundle_installer_proxy.cpp | 169 + .../src/bundlemgr/bundle_mgr_host.cpp | 762 + .../src/bundlemgr/bundle_mgr_proxy.cpp | 1022 ++ .../bundlemgr/bundle_status_callback_host.cpp | 56 + .../bundle_status_callback_proxy.cpp | 178 + .../bundlemgr/clean_cache_callback_host.cpp | 52 + .../bundlemgr/clean_cache_callback_proxy.cpp | 63 + .../src/bundlemgr/status_receiver_host.cpp | 58 + .../src/bundlemgr/status_receiver_proxy.cpp | 255 + .../innerkits/eventhandler_native/BUILD.gn | 59 + .../native_interface_eventhandler.cpp | 74 + .../native_interface_eventhandler.h | 166 + .../eventhandler_native/libappexecfwk.json | 21 + interfaces/innerkits/libeventhandler/BUILD.gn | 38 + .../libeventhandler/include/dumper.h | 39 + .../libeventhandler/include/event_handler.h | 900 ++ .../include/event_handler_errors.h | 46 + .../libeventhandler/include/event_queue.h | 253 + .../libeventhandler/include/event_runner.h | 165 + .../include/file_descriptor_listener.h | 98 + .../libeventhandler/include/inner_event.h | 506 + .../libeventhandler/include/logger.h | 32 + .../include/native_implement_eventhandler.h | 86 + .../lib_event_handler_headers.gni | 26 + kits/BUILD.gn | 137 + kits/appkit/napi/BUILD.gn | 21 + kits/appkit/napi/appMgr/BUILD.gn | 52 + kits/appkit/napi/appMgr/app_mgr.cpp | 154 + kits/appkit/napi/appMgr/app_mgr.h | 39 + kits/appkit/napi/appMgr/native_module.cpp | 60 + kits/appkit/napi/bundlemgr/BUILD.gn | 52 + kits/appkit/napi/bundlemgr/bundle_mgr.cpp | 1669 +++ kits/appkit/napi/bundlemgr/bundle_mgr.h | 99 + .../napi/bundlemgr/installer_callback.cpp | 41 + .../napi/bundlemgr/installer_callback.h | 40 + kits/appkit/napi/bundlemgr/native_module.cpp | 65 + .../native/app/include/ability_manager.h | 109 + .../native/app/include/ability_record_mgr.h | 100 + .../app/include/ability_start_setting.h | 88 + kits/appkit/native/app/include/app_loader.h | 88 + .../native/app/include/application_context.h | 126 + .../native/app/include/application_env.h | 52 + .../native/app/include/application_env_impl.h | 111 + .../native/app/include/application_impl.h | 148 + kits/appkit/native/app/include/context.h | 485 + .../native/app/include/context_container.h | 372 + kits/appkit/native/app/include/context_deal.h | 507 + .../app/include/dummy_hap_module_info.h | 24 + .../native/app/include/element_callback.h | 48 + kits/appkit/native/app/include/main_thread.h | 441 + .../native/app/include/ohos_application.h | 204 + .../native/app/include/sys_mgr_client.h | 67 + .../appkit/native/app/src/ability_manager.cpp | 127 + .../native/app/src/ability_record_mgr.cpp | 162 + .../native/app/src/ability_start_setting.cpp | 149 + kits/appkit/native/app/src/app_loader.cpp | 61 + .../native/app/src/application_context.cpp | 136 + .../appkit/native/app/src/application_env.cpp | 76 + .../native/app/src/application_env_impl.cpp | 79 + .../native/app/src/application_impl.cpp | 194 + .../native/app/src/context_container.cpp | 716 + kits/appkit/native/app/src/context_deal.cpp | 714 + kits/appkit/native/app/src/main.cpp | 26 + kits/appkit/native/app/src/main_thread.cpp | 1147 ++ .../native/app/src/ohos_application.cpp | 393 + kits/appkit/native/app/src/sys_mgr_client.cpp | 78 + kits/appkit/native/test/BUILD.gn | 208 + .../mock_ability_lifecycle_callbacks.h | 112 + .../test/mock/include/mock_application.h | 87 + .../test/mock/include/mock_element_callback.h | 55 + .../test/unittest/application_impl_test.cpp | 308 + .../native/test/unittest/application_test.cpp | 481 + .../test/unittest/context_container_test.cpp | 578 + .../test/unittest/context_deal_test.cpp | 326 + kits/appkit/test/BUILD.gn | 214 + .../Mock/include/mock_ability_mgr_service.h | 87 + .../test/Mock/include/mock_ability_token.h | 62 + .../test/Mock/include/mock_app_mgr_service.h | 265 + .../test/Mock/include/mock_app_thread.cpp | 28 + .../test/Mock/include/mock_app_thread.h | 38 + .../test/Mock/include/mock_application.cpp | 193 + .../test/Mock/include/mock_application.h | 70 + .../Mock/include/mock_bundle_mgr_service.h | 126 + .../Mock/include/mock_ipc_object_stub.cpp | 490 + .../test/Mock/include/sys_mgr_client_mock.cpp | 54 + ...wk_appkit_native_app_module_test_first.cpp | 536 + ...k_appkit_native_app_module_test_fourth.cpp | 353 + ...k_appkit_native_app_module_test_second.cpp | 282 + ...wk_appkit_native_app_module_test_third.cpp | 122 + libs/libeventhandler/BUILD.gn | 30 + .../lib_event_handler_sources.gni | 27 + libs/libeventhandler/src/epoll_io_waiter.cpp | 259 + libs/libeventhandler/src/epoll_io_waiter.h | 67 + libs/libeventhandler/src/event_handler.cpp | 311 + .../libeventhandler/src/event_handler_utils.h | 72 + libs/libeventhandler/src/event_inner_runner.h | 69 + libs/libeventhandler/src/event_queue.cpp | 551 + libs/libeventhandler/src/event_runner.cpp | 551 + .../src/file_descriptor_listener.cpp | 32 + libs/libeventhandler/src/inner_event.cpp | 249 + libs/libeventhandler/src/io_waiter.h | 89 + .../src/native_implement_eventhandler.cpp | 159 + libs/libeventhandler/src/none_io_waiter.cpp | 90 + libs/libeventhandler/src/none_io_waiter.h | 53 + libs/libeventhandler/src/thread_local_data.h | 93 + libs/libeventhandler/test/BUILD.gn | 77 + .../lib_event_handler_event_queue_test.cpp | 1712 +++ .../lib_event_handler_event_runner_test.cpp | 372 + .../unittest/lib_event_handler_event_test.cpp | 436 + libs/test/BUILD.gn | 20 + .../moduletest/common/event_handler/BUILD.gn | 162 + .../event_handler_fd_listener_module_test.cpp | 378 + .../event_handler_post_task_module_test.cpp | 233 + .../event_handler_press_module_test.cpp | 223 + .../event_handler_send_event_module_test.cpp | 588 + ...nt_handler_send_sync_event_module_test.cpp | 391 + ..._handler_send_timing_event_module_test.cpp | 323 + ...ent_handler_set_get_remove_module_test.cpp | 448 + .../event_handler_test_common.cpp | 43 + .../event_handler/event_handler_test_common.h | 132 + ohos.build | 93 + sa_profile/401.xml | 27 + sa_profile/501.xml | 27 + sa_profile/BUILD.gn | 31 + sa_profile/foundation.rc | 28 + services/BUILD.gn | 19 + services/appmgr/BUILD.gn | 90 + services/appmgr/examples/BUILD.gn | 78 + .../main_client.cpp | 44 + .../examples/app_spawn_client_test/main.cpp | 31 + .../appmgr/include/ability_running_record.h | 162 + services/appmgr/include/ams_mgr_scheduler.h | 136 + services/appmgr/include/app_death_recipient.h | 53 + services/appmgr/include/app_lifecycle_deal.h | 132 + services/appmgr/include/app_mgr_service.h | 220 + .../include/app_mgr_service_event_handler.h | 39 + .../appmgr/include/app_mgr_service_inner.h | 618 + services/appmgr/include/app_process_manager.h | 117 + services/appmgr/include/app_running_manager.h | 129 + services/appmgr/include/app_running_record.h | 394 + services/appmgr/include/app_spawn_client.h | 89 + .../appmgr/include/app_spawn_msg_wrapper.h | 122 + services/appmgr/include/app_spawn_socket.h | 84 + services/appmgr/include/cgroup_manager.h | 79 + services/appmgr/include/lmk_util.h | 48 + services/appmgr/include/lmkd_client.h | 58 + services/appmgr/include/process_optimizer.h | 98 + .../appmgr/include/process_optimizer_uba.h | 170 + services/appmgr/include/record_query_result.h | 41 + .../appmgr/include/remote_client_manager.h | 70 + services/appmgr/include/start_via_asan.h | 38 + .../appmgr/src/ability_running_record.cpp | 106 + services/appmgr/src/ams_mgr_scheduler.cpp | 159 + services/appmgr/src/app_death_recipient.cpp | 61 + services/appmgr/src/app_lifecycle_deal.cpp | 99 + services/appmgr/src/app_mgr_service.cpp | 267 + .../src/app_mgr_service_event_handler.cpp | 40 + services/appmgr/src/app_mgr_service_inner.cpp | 1028 ++ services/appmgr/src/app_process_manager.cpp | 96 + services/appmgr/src/app_running_manager.cpp | 167 + services/appmgr/src/app_running_record.cpp | 415 + services/appmgr/src/app_spawn_client.cpp | 137 + services/appmgr/src/app_spawn_msg_wrapper.cpp | 124 + services/appmgr/src/app_spawn_socket.cpp | 111 + services/appmgr/src/cgroup_manager.cpp | 438 + services/appmgr/src/lmk_util.cpp | 231 + services/appmgr/src/lmkd_client.cpp | 231 + services/appmgr/src/process_optimizer.cpp | 680 + services/appmgr/src/process_optimizer_uba.cpp | 371 + services/appmgr/src/remote_client_manager.cpp | 66 + services/appmgr/src/start_via_asan.cpp | 59 + services/appmgr/test/BUILD.gn | 111 + .../test/mock/include/mock_ability_token.h | 62 + .../mock/include/mock_ams_mgr_scheduler.h | 57 + .../test/mock/include/mock_app_mgr_service.h | 104 + .../mock/include/mock_app_mgr_service_inner.h | 107 + .../test/mock/include/mock_app_scheduler.h | 47 + .../test/mock/include/mock_app_service_mgr.h | 42 + .../test/mock/include/mock_app_spawn_client.h | 35 + .../test/mock/include/mock_app_spawn_socket.h | 62 + .../test/mock/include/mock_application.h | 114 + .../test/mock/include/mock_bundle_manager.h | 306 + .../mock/include/mock_iapp_state_callback.h | 40 + .../appmgr/test/mock/include/sys_mgr_client.h | 67 + .../appmgr/test/mock/include/system_ability.h | 67 + .../test/mock/src/mock_bundle_manager.cpp | 140 + .../test/mock/src/sys_mgr_client_mock.cpp | 47 + .../ams_ability_running_record_test/BUILD.gn | 68 + .../ams_ability_running_record_test.cpp | 529 + .../ams_app_death_recipient_test/BUILD.gn | 77 + .../ams_app_death_recipient_test.cpp | 205 + .../unittest/ams_app_life_cycle_test/BUILD.gn | 75 + .../ams_app_life_cycle_test.cpp | 2023 +++ .../unittest/ams_app_mgr_client_test/BUILD.gn | 63 + .../ams_app_mgr_client_test.cpp | 364 + .../ams_app_running_record_test/BUILD.gn | 66 + .../ams_app_running_record_test.cpp | 1231 ++ .../ams_app_state_callback_test/BUILD.gn | 54 + .../ams_app_state_callback_test.cpp | 117 + .../unittest/ams_app_workflow_test/BUILD.gn | 72 + .../ams_workflow_test.cpp | 877 ++ .../unittest/ams_ipc_interface_test/BUILD.gn | 61 + .../ams_ipc_appmgr_interface_test.cpp | 265 + .../ams_ipc_appscheduler_interface_test.cpp | 287 + .../unittest/ams_mgr_scheduler_test/BUILD.gn | 60 + .../ams_mgr_scheduler_test.cpp | 409 + .../ams_recent_app_list_test/BUILD.gn | 74 + .../ams_recent_app_list_test.cpp | 414 + .../BUILD.gn | 71 + .../ams_service_app_spawn_client_test.cpp | 748 + .../BUILD.gn | 53 + ...ams_service_app_spawn_msg_wrapper_test.cpp | 346 + .../BUILD.gn | 51 + .../ams_service_app_spawn_socket_test.cpp | 369 + .../ams_service_event_drive_test/BUILD.gn | 70 + .../ams_service_event_drive_test.cpp | 961 ++ .../BUILD.gn | 76 + .../ams_service_load_ability_process_test.cpp | 1094 ++ .../ams_service_startup_test/BUILD.gn | 70 + .../ams_service_startup_test.cpp | 170 + .../unittest/ams_start_via_asan_test/BUILD.gn | 36 + .../ams_start_via_asan_test.cpp | 79 + .../BUILD.gn | 76 + .../app_mgr_service_event_handler_test.cpp | 176 + services/appmgr/zidl/IAbilityScheduler.zidl | 21 + services/appmgr/zidl/IAppMgr.zidl | 40 + services/appmgr/zidl/IAppScheduler.zidl | 30 + services/appmgr/zidl/IAppStateCallback.zidl | 19 + services/bundlemgr/BUILD.gn | 213 + services/bundlemgr/appexecfwk_bundlemgr.gni | 49 + .../bundlemgr/include/base_bundle_installer.h | 257 + services/bundlemgr/include/base_extractor.h | 70 + services/bundlemgr/include/bundle_data_mgr.h | 368 + .../bundlemgr/include/bundle_data_storage.h | 72 + .../include/bundle_data_storage_interface.h | 69 + services/bundlemgr/include/bundle_extractor.h | 40 + services/bundlemgr/include/bundle_installer.h | 91 + .../bundlemgr/include/bundle_installer_host.h | 107 + .../include/bundle_installer_manager.h | 104 + .../bundlemgr/include/bundle_mgr_host_impl.h | 280 + .../bundlemgr/include/bundle_mgr_service.h | 90 + .../bundle_mgr_service_event_handler.h | 61 + services/bundlemgr/include/bundle_parser.h | 40 + .../bundlemgr/include/bundle_permission_mgr.h | 161 + services/bundlemgr/include/bundle_profile.h | 38 + services/bundlemgr/include/bundle_scanner.h | 53 + .../bundle_status_callback_death_recipient.h | 34 + services/bundlemgr/include/bundle_util.h | 51 + .../bundlemgr/include/bundle_verify_mgr.h | 31 + services/bundlemgr/include/common_profile.h | 213 + .../bundlemgr/include/inner_bundle_info.h | 825 ++ .../include/installd/installd_host_impl.h | 101 + .../include/installd/installd_operator.h | 123 + .../include/installd/installd_service.h | 72 + services/bundlemgr/include/installd_client.h | 123 + .../include/installd_death_recipient.h | 37 + .../bundlemgr/include/ipc/installd_host.h | 111 + .../include/ipc/installd_interface.h | 117 + .../bundlemgr/include/ipc/installd_proxy.h | 108 + .../bundlemgr/include/system_ability_helper.h | 51 + .../include/system_bundle_installer.h | 43 + services/bundlemgr/include/zip_file.h | 304 + services/bundlemgr/installs.rc | 22 + .../bundlemgr/src/base_bundle_installer.cpp | 690 + services/bundlemgr/src/base_extractor.cpp | 95 + services/bundlemgr/src/bundle_data_mgr.cpp | 1084 ++ .../bundlemgr/src/bundle_data_storage.cpp | 204 + services/bundlemgr/src/bundle_extractor.cpp | 40 + services/bundlemgr/src/bundle_installer.cpp | 80 + .../bundlemgr/src/bundle_installer_host.cpp | 209 + .../src/bundle_installer_manager.cpp | 128 + .../bundlemgr/src/bundle_mgr_host_impl.cpp | 428 + services/bundlemgr/src/bundle_mgr_service.cpp | 176 + .../src/bundle_mgr_service_event_handler.cpp | 94 + services/bundlemgr/src/bundle_parser.cpp | 48 + .../bundlemgr/src/bundle_permission_mgr.cpp | 355 + services/bundlemgr/src/bundle_profile.cpp | 1168 ++ services/bundlemgr/src/bundle_scanner.cpp | 96 + ...bundle_status_callback_death_recipient.cpp | 54 + services/bundlemgr/src/bundle_util.cpp | 80 + services/bundlemgr/src/bundle_verify_mgr.cpp | 36 + services/bundlemgr/src/inner_bundle_info.cpp | 709 + .../src/installd/installd_host_impl.cpp | 233 + .../bundlemgr/src/installd/installd_main.cpp | 42 + .../src/installd/installd_operator.cpp | 240 + .../src/installd/installd_service.cpp | 130 + services/bundlemgr/src/installd_client.cpp | 137 + .../src/installd_death_recipient.cpp | 31 + services/bundlemgr/src/ipc/installd_host.cpp | 210 + services/bundlemgr/src/ipc/installd_proxy.cpp | 246 + .../bundlemgr/src/system_ability_helper.cpp | 58 + .../bundlemgr/src/system_bundle_installer.cpp | 46 + services/bundlemgr/src/zip_file.cpp | 583 + services/bundlemgr/test/BUILD.gn | 52 + .../test/mock/include/json_constants.h | 72 + .../test/mock/include/mock_ability_mgr_host.h | 146 + .../test/mock/include/mock_bundle_status.h | 46 + .../test/mock/include/mock_clean_cache.h | 45 + .../test/mock/include/mock_status_receiver.h | 46 + .../test/mock/src/mock_bundle_status.cpp | 44 + .../test/mock/src/mock_clean_cache.cpp | 39 + .../test/mock/src/mock_status_receiver.cpp | 44 + .../test/mock/src/system_ability_helper.cpp | 67 + .../bms_bundle_data_storage_test/BUILD.gn | 70 + .../bms_bundle_data_storage_test.cpp | 663 + .../bms_bundle_installer_test/BUILD.gn | 79 + .../bms_bundle_installer_test.cpp | 733 + .../bms_bundle_kit_service_test/BUILD.gn | 84 + .../bms_bundle_kit_service_test.cpp | 1894 +++ .../unittest/bms_bundle_parser_test/BUILD.gn | 58 + .../bms_bundle_parser_test.cpp | 913 ++ .../bms_bundle_uninstaller_test/BUILD.gn | 84 + .../bms_bundle_uninstaller_test.cpp | 648 + .../unittest/bms_bundle_updater_test/BUILD.gn | 88 + .../bms_bundle_updater_test.cpp | 532 + .../test/unittest/bms_data_mgr_test/BUILD.gn | 71 + .../bms_data_mgr_test/bms_data_mgr_test.cpp | 1015 ++ .../unittest/bms_install_daemon_test/BUILD.gn | 56 + .../bms_install_daemon_test.cpp | 533 + .../bms_service_bundle_scan_test/BUILD.gn | 73 + .../bms_service_bundle_scan_test.cpp | 269 + .../bms_service_startup_test/BUILD.gn | 74 + .../bms_service_startup_test.cpp | 146 + services/test/BUILD.gn | 39 + .../test/mock/include/mock_ability_mgr_host.h | 144 + .../test/mock/include/mock_status_receiver.h | 46 + .../test/mock/src/mock_status_receiver.cpp | 44 + .../test/mock/src/system_ability_helper.cpp | 64 + services/test/moduletest/common/ams/BUILD.gn | 108 + .../ams/ability_running_record_test/BUILD.gn | 36 + ...ams_ability_running_record_module_test.cpp | 432 + .../common/ams/app_life_cycle_test/BUILD.gn | 37 + .../ams_app_life_cycle_module_test.cpp | 1370 ++ .../common/ams/app_mgr_service_test/BUILD.gn | 36 + .../ams_app_mgr_service_module_test.cpp | 490 + .../common/ams/app_recent_list_test/BUILD.gn | 36 + .../ams_app_recent_list_module_test.cpp | 336 + .../ams/app_running_record_test/BUILD.gn | 37 + .../ams_app_running_record_module_test.cpp | 477 + .../common/ams/app_service_flow_test/BUILD.gn | 35 + .../ams_app_service_flow_module_test.cpp | 711 + .../common/ams/ipc_ams_mgr_test/BUILD.gn | 46 + .../ams_ipc_ams_mgr_module_test.cpp | 427 + .../common/ams/ipc_app_mgr_test/BUILD.gn | 35 + .../ams_ipc_app_mgr_module_test.cpp | 315 + .../ams/ipc_app_scheduler_test/BUILD.gn | 34 + .../ams_ipc_app_scheduler_module_test.cpp | 327 + .../service_app_spawn_client_test/BUILD.gn | 38 + ...s_service_app_spawn_client_module_test.cpp | 703 + .../ams/service_event_drive_test/BUILD.gn | 38 + .../ams_service_event_drive_module_test.cpp | 577 + .../ams/service_start_process_test/BUILD.gn | 35 + .../ams_service_start_process_module_test.cpp | 114 + services/test/moduletest/common/bms/BUILD.gn | 44 + .../common/bms/bundle_installer_test/BUILD.gn | 92 + .../bms_bundle_installer_module_test.cpp | 1274 ++ .../common/bms/bundle_parser_test/BUILD.gn | 52 + .../bms_bundle_parser_module_test.cpp | 127 + .../common/bms/bundle_uninstall_test/BUILD.gn | 87 + .../bms_bundle_uninstaller_module_test.cpp | 369 + .../bms/service_start_process_test/BUILD.gn | 77 + .../bms_service_start_module_test.cpp | 352 + services/test/moduletest/utils/BUILD.gn | 30 + .../moduletest/utils/include/common_tool.h | 40 + .../test/moduletest/utils/src/common_tool.cpp | 183 + .../amsDataSystemTestA.hap | Bin 0 -> 120374 bytes .../amsDataSystemTestB.hap | Bin 0 -> 119282 bytes .../amsDataSystemTestC.hap | Bin 0 -> 117003 bytes .../amsKitSystemTestA.hap | Bin 0 -> 151108 bytes .../amsKitSystemTestB.hap | Bin 0 -> 141275 bytes .../amsKitSystemTestDataA.hap | Bin 0 -> 147780 bytes .../amsKitSystemTestDataB.hap | Bin 0 -> 129125 bytes .../ams/ams_data_ability_bundle/test.txt | 1 + .../amsKitSTAbilityManager.hap | Bin 0 -> 117646 bytes .../amsKitSystemTest.hap | Bin 0 -> 414059 bytes .../amsKitSystemTestPageA.hap | Bin 0 -> 173671 bytes .../amsSystemTestA.hap | Bin 0 -> 105063 bytes .../amsSystemTestB.hap | Bin 0 -> 102465 bytes .../amsSystemTestC.hap | Bin 0 -> 107306 bytes .../amsSystemTestD.hap | Bin 0 -> 105056 bytes .../amsSystemTestE.hap | Bin 0 -> 102440 bytes .../amsSystemTestErrorK.hap | Bin 0 -> 97537 bytes .../amsSystemTestErrorL.hap | Bin 0 -> 97540 bytes .../amsSystemTestF.hap | Bin 0 -> 107292 bytes .../amsSystemTestG.hap | Bin 0 -> 105046 bytes .../amsSystemTestH.hap | Bin 0 -> 102468 bytes .../amsSystemTestI.hap | Bin 0 -> 109460 bytes .../amsSystemTestM.hap | Bin 0 -> 103859 bytes .../amsSystemTestN.hap | Bin 0 -> 112150 bytes .../amsSystemTestO.hap | Bin 0 -> 103147 bytes .../amsSystemTestP.hap | Bin 0 -> 103146 bytes .../amsSystemTestServiceA.hap | Bin 0 -> 108238 bytes .../amsKitSystemTestPageA.hap | Bin 0 -> 173207 bytes .../amsKitSystemTestService.hap | Bin 0 -> 179415 bytes .../amsSystemTestServiceA.hap | Bin 0 -> 108460 bytes .../amsSystemTestServiceB.hap | Bin 0 -> 115231 bytes .../amsSystemTestServiceC.hap | Bin 0 -> 102290 bytes .../amsSystemTestServiceD.hap | Bin 0 -> 108924 bytes .../amsSystemTestServiceE.hap | Bin 0 -> 109304 bytes .../amsSystemTestServiceF.hap | Bin 0 -> 98981 bytes .../amsSystemTestServiceG.hap | Bin 0 -> 109578 bytes .../amsSystemTestServiceH.hap | Bin 0 -> 109571 bytes test/resource/ams/ohos_test.xml | 111 + .../amssystemtestability/abilitySrc/BUILD.gn | 51 + .../abilitySrc/amsDataSystemTestA/BUILD.gn | 70 + .../abilitySrc/amsDataSystemTestA/config.json | 50 + .../include/ams_st_data_ability_data_a.h | 72 + .../include/ams_st_data_ability_page_a.h | 95 + .../src/ams_st_data_ability_data_a.cpp | 240 + .../src/ams_st_data_ability_page_a.cpp | 233 + .../abilitySrc/amsDataSystemTestB/BUILD.gn | 69 + .../abilitySrc/amsDataSystemTestB/config.json | 50 + .../include/ams_st_data_ability_data_b.h | 70 + .../include/ams_st_data_ability_page_b.h | 94 + .../src/ams_st_data_ability_data_b.cpp | 220 + .../src/ams_st_data_ability_page_b.cpp | 222 + .../abilitySrc/amsDataSystemTestC/BUILD.gn | 69 + .../abilitySrc/amsDataSystemTestC/config.json | 51 + .../include/ams_st_data_ability_data_c1.h | 75 + .../include/ams_st_data_ability_data_c2.h | 71 + .../src/ams_st_data_ability_data_c1.cpp | 286 + .../src/ams_st_data_ability_data_c2.cpp | 220 + .../amsKitSTAbilityManager/BUILD.gn | 69 + .../amsKitSTAbilityManager/config.json | 40 + .../include/kit_test_ability_manager_second.h | 145 + .../src/kit_test_ability_manager_second.cpp | 450 + .../abilitySrc/amsKitSystemTest/BUILD.gn | 78 + .../abilitySrc/amsKitSystemTest/config.json | 105 + .../amsKitSystemTest/include/fifth_ability.h | 245 + .../amsKitSystemTest/include/fourth_ability.h | 784 ++ .../include/kit_test_ability_manager.h | 195 + .../amsKitSystemTest/include/main_ability.h | 115 + .../amsKitSystemTest/include/second_ability.h | 1540 ++ .../amsKitSystemTest/include/sixth_ability.h | 260 + .../amsKitSystemTest/include/test_utils.h | 44 + .../amsKitSystemTest/include/third_ability.h | 168 + .../amsKitSystemTest/src/fifth_ability.cpp | 987 ++ .../amsKitSystemTest/src/fourth_ability.cpp | 2379 ++++ .../src/kit_test_ability_manager.cpp | 611 + .../amsKitSystemTest/src/main_ability.cpp | 245 + .../amsKitSystemTest/src/second_ability.cpp | 5268 +++++++ .../amsKitSystemTest/src/sixth_ability.cpp | 780 + .../amsKitSystemTest/src/test_utils.cpp | 130 + .../amsKitSystemTest/src/third_ability.cpp | 503 + .../abilitySrc/amsKitSystemTestA/BUILD.gn | 69 + .../abilitySrc/amsKitSystemTestA/config.json | 51 + .../amsKitSystemTestA/include/main_ability.h | 277 + .../include/second_ability.h | 278 + .../amsKitSystemTestA/include/test_utils.h | 44 + .../amsKitSystemTestA/src/main_ability.cpp | 588 + .../amsKitSystemTestA/src/second_ability.cpp | 409 + .../amsKitSystemTestA/src/test_utils.cpp | 129 + .../abilitySrc/amsKitSystemTestB/BUILD.gn | 68 + .../abilitySrc/amsKitSystemTestB/config.json | 42 + .../amsKitSystemTestB/include/main_ability.h | 275 + .../amsKitSystemTestB/include/test_utils.h | 44 + .../amsKitSystemTestB/src/main_ability.cpp | 475 + .../amsKitSystemTestB/src/test_utils.cpp | 129 + .../abilitySrc/amsKitSystemTestDataA/BUILD.gn | 73 + .../amsKitSystemTestDataA/config.json | 80 + .../include/ams_st_kit_data_ability_data_a1.h | 118 + .../include/ams_st_kit_data_ability_data_a2.h | 114 + .../include/ams_st_kit_data_ability_data_a3.h | 113 + .../include/ams_st_kit_data_ability_page_a.h | 80 + .../ams_st_kit_data_ability_service_a.h | 83 + .../src/ams_st_kit_data_ability_data_a1.cpp | 412 + .../src/ams_st_kit_data_ability_data_a2.cpp | 404 + .../src/ams_st_kit_data_ability_data_a3.cpp | 407 + .../src/ams_st_kit_data_ability_page_a.cpp | 232 + .../src/ams_st_kit_data_ability_service_a.cpp | 250 + .../abilitySrc/amsKitSystemTestDataB/BUILD.gn | 71 + .../amsKitSystemTestDataB/config.json | 61 + .../include/ams_st_kit_data_ability_data_b.h | 113 + .../include/ams_st_kit_data_ability_page_b.h | 78 + .../ams_st_kit_data_ability_service_b.h | 81 + .../src/ams_st_kit_data_ability_data_b.cpp | 391 + .../src/ams_st_kit_data_ability_page_b.cpp | 225 + .../src/ams_st_kit_data_ability_service_b.cpp | 251 + .../abilitySrc/amsKitSystemTestPageA/BUILD.gn | 68 + .../amsKitSystemTestPageA/config.json | 78 + .../include/ability_ability.h | 210 + .../include/ability_context_ability.h | 149 + .../include/ability_life_cycle_ability.h | 209 + .../include/base_ability.h | 89 + .../include/life_cycle_call_backs_ability.h | 95 + .../include/life_cycle_observer_ability.h | 229 + .../include/test_utils.h | 88 + .../src/ability_ability.cpp | 781 + .../src/ability_context_ability.cpp | 363 + .../src/ability_life_cycle_ability.cpp | 715 + .../src/base_ability.cpp | 124 + .../src/life_cycle_call_backs_ability.cpp | 223 + .../src/life_cycle_observer_ability.cpp | 787 ++ .../amsKitSystemTestPageA/src/test_utils.cpp | 48 + .../amsKitSystemTestService/BUILD.gn | 76 + .../amsKitSystemTestService/config.json | 87 + .../include/ability_ability.h | 188 + .../include/ability_connection_ability.h | 154 + .../include/ability_context_ability.h | 149 + .../include/ability_life_cycle_ability.h | 203 + .../include/base_ability.h | 86 + .../include/life_cycle_call_backs_ability.h | 94 + .../include/life_cycle_observer_ability.h | 222 + .../include/test_utils.h | 88 + .../src/ability_ability.cpp | 703 + .../src/ability_connection_ability.cpp | 380 + .../src/ability_context_ability.cpp | 386 + .../src/ability_life_cycle_ability.cpp | 735 + .../src/base_ability.cpp | 110 + .../src/life_cycle_call_backs_ability.cpp | 213 + .../src/life_cycle_observer_ability.cpp | 786 ++ .../src/test_utils.cpp | 48 + .../abilitySrc/amsSystemTestA/BUILD.gn | 66 + .../abilitySrc/amsSystemTestA/config.json | 49 + .../amsSystemTestA/include/amsstabilitya1.h | 46 + .../amsSystemTestA/include/amsstabilitya2.h | 46 + .../amsSystemTestA/src/amsstabilitya1.cpp | 111 + .../amsSystemTestA/src/amsstabilitya2.cpp | 105 + .../abilitySrc/amsSystemTestB/BUILD.gn | 61 + .../abilitySrc/amsSystemTestB/config.json | 40 + .../amsSystemTestB/include/amsstabilityb1.h | 46 + .../amsSystemTestB/src/amsstabilityb1.cpp | 105 + .../abilitySrc/amsSystemTestC/BUILD.gn | 63 + .../abilitySrc/amsSystemTestC/config.json | 58 + .../amsSystemTestC/include/amsstabilityc1.h | 46 + .../amsSystemTestC/include/amsstabilityc2.h | 46 + .../amsSystemTestC/include/amsstabilityc3.h | 46 + .../amsSystemTestC/src/amsstabilityc1.cpp | 111 + .../amsSystemTestC/src/amsstabilityc2.cpp | 111 + .../amsSystemTestC/src/amsstabilityc3.cpp | 111 + .../abilitySrc/amsSystemTestD/BUILD.gn | 62 + .../abilitySrc/amsSystemTestD/config.json | 49 + .../amsSystemTestD/include/amsstabilityd1.h | 46 + .../amsSystemTestD/include/amsstabilityd2.h | 46 + .../amsSystemTestD/src/amsstabilityd1.cpp | 111 + .../amsSystemTestD/src/amsstabilityd2.cpp | 105 + .../abilitySrc/amsSystemTestE/BUILD.gn | 61 + .../abilitySrc/amsSystemTestE/config.json | 40 + .../amsSystemTestE/include/amsstabilitye1.h | 46 + .../amsSystemTestE/src/amsstabilitye1.cpp | 105 + .../abilitySrc/amsSystemTestErrorK/BUILD.gn | 51 + .../amsSystemTestErrorK/config.json | 41 + .../include/amsstabilityerrork1.h | 38 + .../src/amsstabilityerrork1.cpp | 70 + .../abilitySrc/amsSystemTestErrorL/BUILD.gn | 51 + .../amsSystemTestErrorL/config.json | 40 + .../include/amsstabilityerrorl1.h | 38 + .../src/amsstabilityerrorl1.cpp | 66 + .../abilitySrc/amsSystemTestF/BUILD.gn | 63 + .../abilitySrc/amsSystemTestF/config.json | 58 + .../amsSystemTestF/include/amsstabilityf1.h | 46 + .../amsSystemTestF/include/amsstabilityf2.h | 46 + .../amsSystemTestF/include/amsstabilityf3.h | 46 + .../amsSystemTestF/src/amsstabilityf1.cpp | 111 + .../amsSystemTestF/src/amsstabilityf2.cpp | 111 + .../amsSystemTestF/src/amsstabilityf3.cpp | 111 + .../abilitySrc/amsSystemTestG/BUILD.gn | 62 + .../abilitySrc/amsSystemTestG/config.json | 49 + .../amsSystemTestG/include/amsstabilityg1.h | 46 + .../amsSystemTestG/include/amsstabilityg2.h | 46 + .../amsSystemTestG/src/amsstabilityg1.cpp | 111 + .../amsSystemTestG/src/amsstabilityg2.cpp | 105 + .../abilitySrc/amsSystemTestH/BUILD.gn | 61 + .../abilitySrc/amsSystemTestH/config.json | 40 + .../amsSystemTestH/include/amsstabilityh1.h | 46 + .../amsSystemTestH/src/amsstabilityh1.cpp | 105 + .../abilitySrc/amsSystemTestI/BUILD.gn | 64 + .../abilitySrc/amsSystemTestI/config.json | 67 + .../amsSystemTestI/include/amsstabilityi1.h | 46 + .../amsSystemTestI/include/amsstabilityi2.h | 46 + .../amsSystemTestI/include/amsstabilityi3.h | 46 + .../amsSystemTestI/include/amsstabilityi4.h | 46 + .../amsSystemTestI/src/amsstabilityi1.cpp | 111 + .../amsSystemTestI/src/amsstabilityi2.cpp | 111 + .../amsSystemTestI/src/amsstabilityi3.cpp | 111 + .../amsSystemTestI/src/amsstabilityi4.cpp | 111 + .../abilitySrc/amsSystemTestM/BUILD.gn | 61 + .../abilitySrc/amsSystemTestM/config.json | 40 + .../amsSystemTestM/include/amsstabilitym1.h | 51 + .../amsSystemTestM/src/amsstabilitym1.cpp | 154 + .../abilitySrc/amsSystemTestN/BUILD.gn | 64 + .../abilitySrc/amsSystemTestN/config.json | 67 + .../amsSystemTestN/include/amsstabilityn1.h | 51 + .../amsSystemTestN/include/amsstabilityn2.h | 51 + .../amsSystemTestN/include/amsstabilityn3.h | 47 + .../amsSystemTestN/include/amsstabilityn4.h | 47 + .../amsSystemTestN/src/amsstabilityn1.cpp | 154 + .../amsSystemTestN/src/amsstabilityn2.cpp | 154 + .../amsSystemTestN/src/amsstabilityn3.cpp | 128 + .../amsSystemTestN/src/amsstabilityn4.cpp | 133 + .../abilitySrc/amsSystemTestO/BUILD.gn | 61 + .../abilitySrc/amsSystemTestO/config.json | 40 + .../amsSystemTestO/include/amsstabilityo1.h | 48 + .../amsSystemTestO/src/amsstabilityo1.cpp | 134 + .../abilitySrc/amsSystemTestP/BUILD.gn | 61 + .../abilitySrc/amsSystemTestP/config.json | 40 + .../amsSystemTestP/include/amsstabilityp1.h | 48 + .../amsSystemTestP/src/amsstabilityp1.cpp | 134 + .../abilitySrc/amsSystemTestServiceA/BUILD.gn | 58 + .../amsSystemTestServiceA/config.json | 40 + .../include/ams_st_service_ability_a1.h | 127 + .../src/ams_st_service_ability_a1.cpp | 283 + .../abilitySrc/amsSystemTestServiceB/BUILD.gn | 61 + .../amsSystemTestServiceB/config.json | 50 + .../include/ams_st_service_ability_b2.h | 125 + .../include/ams_st_service_ability_b3.h | 126 + .../src/ams_st_service_ability_b2.cpp | 277 + .../src/ams_st_service_ability_b3.cpp | 275 + .../abilitySrc/amsSystemTestServiceC/BUILD.gn | 57 + .../amsSystemTestServiceC/config.json | 41 + .../include/ams_st_service_ability_c4.h | 68 + .../src/ams_st_service_ability_c4.cpp | 180 + .../abilitySrc/amsSystemTestServiceD/BUILD.gn | 59 + .../amsSystemTestServiceD/config.json | 40 + .../include/ams_st_service_ability_d1.h | 120 + .../src/ams_st_service_ability_d1.cpp | 286 + .../abilitySrc/amsSystemTestServiceE/BUILD.gn | 59 + .../amsSystemTestServiceE/config.json | 41 + .../include/ams_st_service_ability_e2.h | 131 + .../src/ams_st_service_ability_e2.cpp | 289 + .../abilitySrc/amsSystemTestServiceF/BUILD.gn | 58 + .../amsSystemTestServiceF/config.json | 42 + .../include/ams_st_service_ability_f3.h | 45 + .../src/ams_st_service_ability_f3.cpp | 116 + .../abilitySrc/amsSystemTestServiceG/BUILD.gn | 59 + .../amsSystemTestServiceG/config.json | 41 + .../include/ams_st_service_ability_g1.h | 131 + .../src/ams_st_service_ability_g1.cpp | 289 + .../abilitySrc/amsSystemTestServiceH/BUILD.gn | 59 + .../amsSystemTestServiceH/config.json | 41 + .../include/ams_st_service_ability_h1.h | 131 + .../src/ams_st_service_ability_h1.cpp | 289 + .../abilitySrc/common/kit_test_common_info.h | 429 + .../abilitySrc/tools/include/event.h | 42 + .../abilitySrc/tools/include/stoperator.h | 61 + .../tools/include/stpageabilityevent.h | 94 + .../abilitySrc/tools/src/event.cpp | 102 + .../abilitySrc/tools/src/stoperator.cpp | 187 + .../tools/src/stpageabilityevent.cpp | 130 + .../bundlemgrservice/bundle_kit/test.hap | Bin 0 -> 93291 bytes .../bundlemgrservice/install_daemon/right.hap | Bin 0 -> 93685 bytes test/resource/bundlemgrservice/ohos_test.xml | 59 + .../parse_bundle/break_zip.hap | Bin 0 -> 5707 bytes .../parse_bundle/empty_config.hap | Bin 0 -> 92883 bytes .../parse_bundle/format_error_profile.hap | Bin 0 -> 93275 bytes .../parse_bundle/format_missing_profile.hap | Bin 0 -> 93538 bytes .../bundlemgrservice/parse_bundle/new.hap | Bin 0 -> 93545 bytes .../parse_bundle/no_profile.hap | Bin 0 -> 92752 bytes .../parse_bundle/nothing_config.hap | Bin 0 -> 5838 bytes .../test_bundle/error_bundle_profile.hap | Bin 0 -> 92874 bytes .../test_bundle/format_error_profile.hap | Bin 0 -> 93678 bytes .../bundlemgrservice/test_bundle/nofile.hap | Bin 0 -> 5707 bytes .../bundlemgrservice/test_bundle/right.hap | Bin 0 -> 93685 bytes .../bundlemgrservice/test_bundle/right1.hap | Bin 0 -> 32810 bytes .../bundlemgrservice/test_bundle/version1.hap | Bin 0 -> 93686 bytes .../bundlemgrservice/test_bundle/version2.hap | Bin 0 -> 93284 bytes .../bundlemgrservice/test_bundle/version3.hap | Bin 0 -> 93285 bytes .../test_bundle/wrong_bundle_name_sign.hap | Bin 0 -> 93685 bytes test/resource/bundlemgrsst/ohos_test.xml | 57 + .../stSystemBundle/bmsSystemBundle1.hap | Bin 0 -> 93241 bytes .../stSystemBundle/bmsSystemBundle2.hap | Bin 0 -> 93243 bytes .../stSystemBundle/bmsSystemBundle3.hap | Bin 0 -> 92757 bytes .../stSystemBundle/bmsSystemBundle4.hap | Bin 0 -> 6216 bytes .../stSystemBundle/bmsSystemBundle5.hap | Bin 0 -> 1312150 bytes .../stThirdBundle/bmsThirdBundle1.hap | Bin 0 -> 99124 bytes .../stThirdBundle/bmsThirdBundle10.hap | Bin 0 -> 93248 bytes .../stThirdBundle/bmsThirdBundle11.hap | Bin 0 -> 92767 bytes .../stThirdBundle/bmsThirdBundle12.rpk | Bin 0 -> 542 bytes .../stThirdBundle/bmsThirdBundle13.hap | Bin 0 -> 1573524 bytes .../stThirdBundle/bmsThirdBundle14.hap | Bin 0 -> 93242 bytes .../stThirdBundle/bmsThirdBundle15.hap | Bin 0 -> 93253 bytes .../stThirdBundle/bmsThirdBundle16.hap | Bin 0 -> 93253 bytes .../stThirdBundle/bmsThirdBundle17.hap | Bin 0 -> 98806 bytes .../stThirdBundle/bmsThirdBundle18.hap | Bin 0 -> 98143 bytes .../stThirdBundle/bmsThirdBundle19.hap | Bin 0 -> 98517 bytes .../stThirdBundle/bmsThirdBundle2.hap | Bin 0 -> 94169 bytes .../stThirdBundle/bmsThirdBundle20.hap | Bin 0 -> 98686 bytes .../stThirdBundle/bmsThirdBundle21.hap | Bin 0 -> 93166 bytes .../stThirdBundle/bmsThirdBundle22.hap | Bin 0 -> 93268 bytes .../stThirdBundle/bmsThirdBundle23.hap | Bin 0 -> 93266 bytes .../stThirdBundle/bmsThirdBundle24.hap | Bin 0 -> 93253 bytes .../stThirdBundle/bmsThirdBundle25.hap | Bin 0 -> 93284 bytes .../stThirdBundle/bmsThirdBundle26.hap | Bin 0 -> 93168 bytes .../stThirdBundle/bmsThirdBundle27.hap | Bin 0 -> 93267 bytes .../stThirdBundle/bmsThirdBundle28.rpk | Bin 0 -> 87428 bytes .../stThirdBundle/bmsThirdBundle3.hap | Bin 0 -> 93183 bytes .../stThirdBundle/bmsThirdBundle30.hap | Bin 0 -> 93256 bytes .../stThirdBundle/bmsThirdBundle31.hap | Bin 0 -> 93257 bytes .../stThirdBundle/bmsThirdBundle32.hap | Bin 0 -> 93258 bytes .../stThirdBundle/bmsThirdBundle33.hap | Bin 0 -> 93256 bytes .../stThirdBundle/bmsThirdBundle34.hap | Bin 0 -> 93258 bytes .../stThirdBundle/bmsThirdBundle35.hap | Bin 0 -> 93257 bytes .../stThirdBundle/bmsThirdBundle36.hap | Bin 0 -> 93247 bytes .../stThirdBundle/bmsThirdBundle37.hap | Bin 0 -> 93272 bytes .../stThirdBundle/bmsThirdBundle38.hap | Bin 0 -> 93239 bytes .../stThirdBundle/bmsThirdBundle39.hap | Bin 0 -> 93255 bytes .../stThirdBundle/bmsThirdBundle4.hap | Bin 0 -> 93256 bytes .../stThirdBundle/bmsThirdBundle40.hap | Bin 0 -> 93254 bytes .../stThirdBundle/bmsThirdBundle41.hap | Bin 0 -> 94208 bytes .../stThirdBundle/bmsThirdBundle5.hap | Bin 0 -> 94171 bytes .../stThirdBundle/bmsThirdBundle6.hap | Bin 0 -> 93175 bytes .../stThirdBundle/bmsThirdBundle7.hap | Bin 0 -> 93318 bytes .../stThirdBundle/bmsThirdBundle8.hap | Bin 0 -> 93359 bytes .../stThirdBundle/bmsThirdBundle9.hap | Bin 0 -> 93252 bytes .../stThirdBundle/bmsThirdBundlee1.hap | Bin 0 -> 93389 bytes .../stThirdBundle/bmsThirdBundles1.hap | Bin 0 -> 93393 bytes .../stThirdBundle/bmsThirdBundles2.hap | Bin 0 -> 93395 bytes .../stThirdBundle/bmsThirdBundlev1.hap | Bin 0 -> 93234 bytes .../stThirdBundle/bmsThirdBundlev2.hap | Bin 0 -> 93235 bytes .../bundlemgrsst/stThirdBundle/e1.hap | Bin 0 -> 94175 bytes .../bundlemgrsst/stThirdBundle/e12.hap | Bin 0 -> 94172 bytes .../bundlemgrsst/stThirdBundle/e14.hap | Bin 0 -> 94173 bytes .../bundlemgrsst/stThirdBundle/e21.hap | Bin 0 -> 94172 bytes .../bundlemgrsst/stThirdBundle/e22.hap | Bin 0 -> 94170 bytes .../bundlemgrsst/stThirdBundle/e23.hap | Bin 0 -> 94175 bytes .../bundlemgrsst/stThirdBundle/e3.hap | Bin 0 -> 94178 bytes .../stVendorBundle/bmsVendorBundle1.hap | Bin 0 -> 93234 bytes .../stVendorBundle/bmsVendorBundle2.hap | Bin 0 -> 93234 bytes .../stVendorBundle/bmsVendorBundle3.hap | Bin 0 -> 93234 bytes .../other_bundle/bmsThirdBundle1.hap | Bin 0 -> 93252 bytes .../other_bundle/bmsThirdBundle10.hap | Bin 0 -> 93250 bytes .../other_bundle/bmsThirdBundle11.hap | Bin 0 -> 92766 bytes .../other_bundle/bmsThirdBundle12.rpk | Bin 0 -> 6197 bytes .../other_bundle/bmsThirdBundle13.hap | Bin 0 -> 93256 bytes .../other_bundle/bmsThirdBundle14.hap | Bin 0 -> 93242 bytes .../other_bundle/bmsThirdBundle15.hap | Bin 0 -> 93254 bytes .../other_bundle/bmsThirdBundle16.hap | Bin 0 -> 93253 bytes .../other_bundle/bmsThirdBundle17.hap | Bin 0 -> 93378 bytes .../other_bundle/bmsThirdBundle18.hap | Bin 0 -> 93176 bytes .../other_bundle/bmsThirdBundle19.hap | Bin 0 -> 93258 bytes .../other_bundle/bmsThirdBundle2.hap | Bin 0 -> 94168 bytes .../other_bundle/bmsThirdBundle20.hap | Bin 0 -> 93257 bytes .../other_bundle/bmsThirdBundle21.hap | Bin 0 -> 93165 bytes .../other_bundle/bmsThirdBundle22.hap | Bin 0 -> 93268 bytes .../other_bundle/bmsThirdBundle23.hap | Bin 0 -> 93266 bytes .../other_bundle/bmsThirdBundle24.hap | Bin 0 -> 93255 bytes .../other_bundle/bmsThirdBundle25.hap | Bin 0 -> 93254 bytes .../other_bundle/bmsThirdBundle26.hap | Bin 0 -> 93252 bytes .../other_bundle/bmsThirdBundle27.hap | Bin 0 -> 93257 bytes .../other_bundle/bmsThirdBundle28.hap | Bin 0 -> 93256 bytes .../other_bundle/bmsThirdBundle3.hap | Bin 0 -> 93184 bytes .../other_bundle/bmsThirdBundle4.hap | Bin 0 -> 93257 bytes .../other_bundle/bmsThirdBundle5.hap | Bin 0 -> 94172 bytes .../other_bundle/bmsThirdBundle6.hap | Bin 0 -> 93177 bytes .../other_bundle/bmsThirdBundle7.hap | Bin 0 -> 93256 bytes .../other_bundle/bmsThirdBundle8.hap | Bin 0 -> 93254 bytes .../other_bundle/bmsThirdBundle9.hap | Bin 0 -> 93254 bytes .../system_bundle/bmsSystemBundle1.hap | Bin 0 -> 93242 bytes .../system_bundle/bmsSystemBundle2.hap | Bin 0 -> 93243 bytes .../system_bundle/bmsSystemBundle3.hap | Bin 0 -> 92758 bytes .../system_bundle/bmsSystemBundle4.hap | Bin 0 -> 6216 bytes .../system_bundle/bmsSystemBundle5.hap | Bin 0 -> 1312150 bytes .../vendor_bundle/bmsVendorBundle1.hap | Bin 0 -> 93234 bytes .../vendor_bundle/bmsVendorBundle2.hap | Bin 0 -> 6197 bytes .../vendor_bundle/bmsVendorBundle3.hap | Bin 0 -> 93235 bytes .../vendor_bundle/bmsVendorBundle4.hap | Bin 0 -> 105062 bytes .../mstbundlemgrservice/ohos_test.xml | 58 + .../tools/bm/pageAbilityBundleForInstall.hap | Bin 0 -> 20629 bytes .../bm/pageAbilityBundleForUninstall.hap | Bin 0 -> 20633 bytes test/resource/tools/ohos_test.xml | 35 + test/systemtest/BUILD.gn | 30 + test/systemtest/common/ams/BUILD.gn | 41 + .../common/ams/ams_aa_command_test/BUILD.gn | 68 + .../ams_aa_command_test.cpp | 227 + .../ams/ams_app_process_manage_test/BUILD.gn | 68 + .../ams_app_process_manage_test.cpp | 1021 ++ .../common/ams/ams_data_ability_test/BUILD.gn | 71 + .../ams_data_ability_test.cpp | 942 ++ .../ams_data_ability_test_def.h | 111 + .../common/ams/ams_kit_test/BUILD.gn | 387 + .../ams/ams_kit_test/acts_ams_kit_a_test.cpp | 2417 ++++ .../ams_kit_test/acts_ams_kit_data_test.cpp | 11746 ++++++++++++++++ .../acts_ams_kit_lifecycle_test.cpp | 7663 ++++++++++ .../acts_ams_kit_processinfo_test.cpp | 2125 +++ .../acts_ams_kit_service_ability_test.cpp | 9987 +++++++++++++ .../ams_kit_test/acts_ams_kit_skills_test.cpp | 6633 +++++++++ .../ams/ams_kit_test/acts_ams_kit_test.cpp | 2112 +++ .../ams_kit_test/acts_ams_kit_want_test.cpp | 8981 ++++++++++++ .../common/ams/ams_page_ability_test/BUILD.gn | 67 + .../ams_page_ability_test.cpp | 3666 +++++ .../ams/ams_service_ability_test/BUILD.gn | 69 + .../ams_service_ability_test.cpp | 2091 +++ .../ams_service_ability_test_def.h | 91 + test/systemtest/common/ams/tool/BUILD.gn | 70 + .../common/ams/tool/include/event.h | 49 + .../ams/tool/include/module_test_dump_util.h | 104 + .../common/ams/tool/include/stoperator.h | 63 + .../tool/include/system_test_ability_util.h | 310 + test/systemtest/common/ams/tool/src/event.cpp | 125 + .../ams/tool/src/module_test_dump_util.cpp | 162 + .../common/ams/tool/src/stoperator.cpp | 124 + .../ams/tool/src/system_test_ability_util.cpp | 382 + test/systemtest/common/bms/BUILD.gn | 78 + .../bms/acts_bms_kit_system_test/BUILD.gn | 55 + .../acts_bms_kit_system_test.cpp | 4319 ++++++ .../bms/bms_install_system_test/BUILD.gn | 57 + .../bms_install_system_test.cpp | 2151 +++ .../bms/bms_search_system_test/BUILD.gn | 52 + .../bms_search_system_test.cpp | 1455 ++ .../bms/bms_uninstall_system_test/BUILD.gn | 51 + .../bms_uninstall_system_test.cpp | 1327 ++ test/systemtest/common/ems/BUILD.gn | 28 + .../ems/ems_dumper_system_test/BUILD.gn | 43 + .../ems_dumper_system_test.cpp | 328 + .../ems_event_handler_system_test/BUILD.gn | 45 + .../ems_event_handler_test.cpp | 2580 ++++ .../ems/ems_event_queue_system_test/BUILD.gn | 43 + .../ems_event_queue_system_test.cpp | 131 + .../ems/ems_event_runner_system_test/BUILD.gn | 43 + .../ems_event_runner_system_test.cpp | 1758 +++ .../ems/ems_inner_event_system_test/BUILD.gn | 43 + .../ems_inner_event_system_test.cpp | 252 + .../ems/ems_logger_system_test/BUILD.gn | 43 + .../ems_logger_system_test.cpp | 184 + tools/BUILD.gn | 16 + tools/bm/BUILD.gn | 80 + tools/bm/include/bundle_command.h | 102 + tools/bm/include/status_receiver_impl.h | 43 + tools/bm/src/bundle_command.cpp | 797 ++ tools/bm/src/main.cpp | 23 + tools/bm/src/status_receiver_impl.cpp | 54 + tools/test/BUILD.gn | 32 + .../test/mock/mock_bundle_installer_host.cpp | 59 + tools/test/mock/mock_bundle_installer_host.h | 48 + tools/test/mock/mock_bundle_mgr_host.cpp | 33 + tools/test/mock/mock_bundle_mgr_host.h | 79 + tools/test/moduletest/bm/BUILD.gn | 157 + .../bm/bundle_command_dump_module_test.cpp | 134 + .../bm/bundle_command_install_module_test.cpp | 137 + .../bundle_command_uninstall_module_test.cpp | 136 + tools/test/systemtest/bm/BUILD.gn | 120 + .../bm/bundle_command_dump_system_test.cpp | 114 + .../bm/bundle_command_install_system_test.cpp | 108 + .../bundle_command_uninstall_system_test.cpp | 124 + tools/test/unittest/bm/BUILD.gn | 210 + .../unittest/bm/bundle_command_dump_test.cpp | 362 + .../bm/bundle_command_install_test.cpp | 393 + .../test/unittest/bm/bundle_command_test.cpp | 193 + .../bm/bundle_command_uninstall_test.cpp | 390 + 943 files changed, 216374 insertions(+), 73 deletions(-) create mode 100644 .gitattributes create mode 100644 BUILD.gn create mode 100644 LICENSE create mode 100644 OAT.xml delete mode 100644 README.en.md delete mode 100644 README.md create mode 100755 README_zh.md create mode 100644 appexecfwk.gni create mode 100644 common/BUILD.gn create mode 100644 common/log/README.md create mode 100644 common/log/include/app_log_wrapper.h create mode 100644 common/log/src/app_log_wrapper.cpp create mode 100644 common/perf/include/perf_profile.h create mode 100755 common/perf/src/perf_profile.cpp create mode 100644 common/test/BUILD.gn create mode 100644 common/test/unittest/common_appexecfwk_log_test/BUILD.gn create mode 100644 common/test/unittest/common_appexecfwk_log_test/appexecfwk_log_test.cpp create mode 100644 common/test/unittest/common_perf_profile_test/BUILD.gn create mode 100644 common/test/unittest/common_perf_profile_test/common_perf_profile_test.cpp create mode 100755 figures/appexecfwk.png create mode 100644 interfaces/innerkits/BUILD.gn create mode 100644 interfaces/innerkits/appexecfwk_base/BUILD.gn create mode 100644 interfaces/innerkits/appexecfwk_base/appexecfwk_base_header.gni create mode 100644 interfaces/innerkits/appexecfwk_base/include/ability_info.h create mode 100644 interfaces/innerkits/appexecfwk_base/include/app_process_info.h create mode 100644 interfaces/innerkits/appexecfwk_base/include/appexecfwk_errors.h create mode 100644 interfaces/innerkits/appexecfwk_base/include/application_info.h create mode 100755 interfaces/innerkits/appexecfwk_base/include/bundle_constants.h create mode 100644 interfaces/innerkits/appexecfwk_base/include/bundle_info.h create mode 100644 interfaces/innerkits/appexecfwk_base/include/element_name.h create mode 100644 interfaces/innerkits/appexecfwk_base/include/hap_module_info.h create mode 100644 interfaces/innerkits/appexecfwk_base/include/install_param.h create mode 100644 interfaces/innerkits/appexecfwk_base/include/json_serializer.h create mode 100644 interfaces/innerkits/appexecfwk_base/include/module_info.h create mode 100644 interfaces/innerkits/appexecfwk_base/include/parcel_macro.h create mode 100644 interfaces/innerkits/appexecfwk_base/include/permission_def.h create mode 100644 interfaces/innerkits/appexecfwk_base/include/running_process_info.h create mode 100644 interfaces/innerkits/appexecfwk_base/src/ability_info.cpp create mode 100644 interfaces/innerkits/appexecfwk_base/src/app_process_info.cpp create mode 100644 interfaces/innerkits/appexecfwk_base/src/application_info.cpp create mode 100644 interfaces/innerkits/appexecfwk_base/src/bundle_info.cpp create mode 100644 interfaces/innerkits/appexecfwk_base/src/element_name.cpp create mode 100644 interfaces/innerkits/appexecfwk_base/src/hap_module_info.cpp create mode 100644 interfaces/innerkits/appexecfwk_base/src/install_param.cpp create mode 100644 interfaces/innerkits/appexecfwk_base/src/module_info.cpp create mode 100644 interfaces/innerkits/appexecfwk_base/src/permission_def.cpp create mode 100644 interfaces/innerkits/appexecfwk_base/src/running_process_info.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/BUILD.gn create mode 100644 interfaces/innerkits/appexecfwk_core/appexecfwk_headers.gni create mode 100644 interfaces/innerkits/appexecfwk_core/include/appmgr/ams_mgr_interface.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/appmgr/ams_mgr_proxy.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/appmgr/ams_mgr_stub.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/appmgr/app_launch_data.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/appmgr/app_mgr_client.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/appmgr/app_mgr_constants.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/appmgr/app_mgr_interface.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/appmgr/app_mgr_proxy.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/appmgr/app_mgr_stub.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/appmgr/app_process_data.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/appmgr/app_record_id.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/appmgr/app_scheduler_host.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/appmgr/app_scheduler_interface.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/appmgr/app_scheduler_proxy.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/appmgr/app_service_manager.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/appmgr/app_state_callback_host.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/appmgr/app_state_callback_proxy.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/appmgr/app_task_info.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/appmgr/dummy_configuration.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/appmgr/iapp_state_callback.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/appmgr/priority_object.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/appmgr/process_info.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/appmgr/profile.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_installer_interface.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_installer_proxy.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_mgr_host.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_mgr_interface.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_mgr_proxy.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_status_callback_host.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_status_callback_interface.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_status_callback_proxy.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/bundlemgr/clean_cache_callback_host.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/bundlemgr/clean_cache_callback_interface.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/bundlemgr/clean_cache_callback_proxy.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/bundlemgr/status_receiver_host.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/bundlemgr/status_receiver_interface.h create mode 100644 interfaces/innerkits/appexecfwk_core/include/bundlemgr/status_receiver_proxy.h create mode 100644 interfaces/innerkits/appexecfwk_core/src/appmgr/ams_mgr_proxy.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/appmgr/ams_mgr_stub.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/appmgr/app_launch_data.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/appmgr/app_mgr_client.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/appmgr/app_mgr_proxy.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/appmgr/app_mgr_stub.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/appmgr/app_process_data.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/appmgr/app_record_id.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/appmgr/app_scheduler_host.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/appmgr/app_scheduler_proxy.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/appmgr/app_service_manager.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/appmgr/app_state_callback_host.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/appmgr/app_state_callback_proxy.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/appmgr/app_task_info.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/appmgr/dummy_configuration.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/appmgr/priority_object.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/appmgr/process_info.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/appmgr/profile.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_installer_proxy.cpp create mode 100755 interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_mgr_host.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_mgr_proxy.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_status_callback_host.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_status_callback_proxy.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/bundlemgr/clean_cache_callback_host.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/bundlemgr/clean_cache_callback_proxy.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/bundlemgr/status_receiver_host.cpp create mode 100644 interfaces/innerkits/appexecfwk_core/src/bundlemgr/status_receiver_proxy.cpp create mode 100644 interfaces/innerkits/eventhandler_native/BUILD.gn create mode 100644 interfaces/innerkits/eventhandler_native/eventhandler/native_interface_eventhandler.cpp create mode 100644 interfaces/innerkits/eventhandler_native/eventhandler/native_interface_eventhandler.h create mode 100644 interfaces/innerkits/eventhandler_native/libappexecfwk.json create mode 100644 interfaces/innerkits/libeventhandler/BUILD.gn create mode 100644 interfaces/innerkits/libeventhandler/include/dumper.h create mode 100644 interfaces/innerkits/libeventhandler/include/event_handler.h create mode 100644 interfaces/innerkits/libeventhandler/include/event_handler_errors.h create mode 100644 interfaces/innerkits/libeventhandler/include/event_queue.h create mode 100644 interfaces/innerkits/libeventhandler/include/event_runner.h create mode 100644 interfaces/innerkits/libeventhandler/include/file_descriptor_listener.h create mode 100644 interfaces/innerkits/libeventhandler/include/inner_event.h create mode 100644 interfaces/innerkits/libeventhandler/include/logger.h create mode 100644 interfaces/innerkits/libeventhandler/include/native_implement_eventhandler.h create mode 100644 interfaces/innerkits/libeventhandler/lib_event_handler_headers.gni create mode 100755 kits/BUILD.gn create mode 100644 kits/appkit/napi/BUILD.gn create mode 100644 kits/appkit/napi/appMgr/BUILD.gn create mode 100755 kits/appkit/napi/appMgr/app_mgr.cpp create mode 100644 kits/appkit/napi/appMgr/app_mgr.h create mode 100644 kits/appkit/napi/appMgr/native_module.cpp create mode 100644 kits/appkit/napi/bundlemgr/BUILD.gn create mode 100644 kits/appkit/napi/bundlemgr/bundle_mgr.cpp create mode 100644 kits/appkit/napi/bundlemgr/bundle_mgr.h create mode 100644 kits/appkit/napi/bundlemgr/installer_callback.cpp create mode 100644 kits/appkit/napi/bundlemgr/installer_callback.h create mode 100644 kits/appkit/napi/bundlemgr/native_module.cpp create mode 100644 kits/appkit/native/app/include/ability_manager.h create mode 100644 kits/appkit/native/app/include/ability_record_mgr.h create mode 100644 kits/appkit/native/app/include/ability_start_setting.h create mode 100644 kits/appkit/native/app/include/app_loader.h create mode 100644 kits/appkit/native/app/include/application_context.h create mode 100644 kits/appkit/native/app/include/application_env.h create mode 100644 kits/appkit/native/app/include/application_env_impl.h create mode 100644 kits/appkit/native/app/include/application_impl.h create mode 100755 kits/appkit/native/app/include/context.h create mode 100755 kits/appkit/native/app/include/context_container.h create mode 100755 kits/appkit/native/app/include/context_deal.h create mode 100644 kits/appkit/native/app/include/dummy_hap_module_info.h create mode 100644 kits/appkit/native/app/include/element_callback.h create mode 100644 kits/appkit/native/app/include/main_thread.h create mode 100644 kits/appkit/native/app/include/ohos_application.h create mode 100644 kits/appkit/native/app/include/sys_mgr_client.h create mode 100644 kits/appkit/native/app/src/ability_manager.cpp create mode 100644 kits/appkit/native/app/src/ability_record_mgr.cpp create mode 100644 kits/appkit/native/app/src/ability_start_setting.cpp create mode 100644 kits/appkit/native/app/src/app_loader.cpp create mode 100644 kits/appkit/native/app/src/application_context.cpp create mode 100644 kits/appkit/native/app/src/application_env.cpp create mode 100644 kits/appkit/native/app/src/application_env_impl.cpp create mode 100644 kits/appkit/native/app/src/application_impl.cpp create mode 100755 kits/appkit/native/app/src/context_container.cpp create mode 100755 kits/appkit/native/app/src/context_deal.cpp create mode 100644 kits/appkit/native/app/src/main.cpp create mode 100644 kits/appkit/native/app/src/main_thread.cpp create mode 100644 kits/appkit/native/app/src/ohos_application.cpp create mode 100644 kits/appkit/native/app/src/sys_mgr_client.cpp create mode 100644 kits/appkit/native/test/BUILD.gn create mode 100644 kits/appkit/native/test/mock/include/mock_ability_lifecycle_callbacks.h create mode 100644 kits/appkit/native/test/mock/include/mock_application.h create mode 100644 kits/appkit/native/test/mock/include/mock_element_callback.h create mode 100644 kits/appkit/native/test/unittest/application_impl_test.cpp create mode 100644 kits/appkit/native/test/unittest/application_test.cpp create mode 100644 kits/appkit/native/test/unittest/context_container_test.cpp create mode 100644 kits/appkit/native/test/unittest/context_deal_test.cpp create mode 100755 kits/appkit/test/BUILD.gn create mode 100644 kits/appkit/test/Mock/include/mock_ability_mgr_service.h create mode 100644 kits/appkit/test/Mock/include/mock_ability_token.h create mode 100755 kits/appkit/test/Mock/include/mock_app_mgr_service.h create mode 100644 kits/appkit/test/Mock/include/mock_app_thread.cpp create mode 100644 kits/appkit/test/Mock/include/mock_app_thread.h create mode 100644 kits/appkit/test/Mock/include/mock_application.cpp create mode 100644 kits/appkit/test/Mock/include/mock_application.h create mode 100755 kits/appkit/test/Mock/include/mock_bundle_mgr_service.h create mode 100644 kits/appkit/test/Mock/include/mock_ipc_object_stub.cpp create mode 100644 kits/appkit/test/Mock/include/sys_mgr_client_mock.cpp create mode 100644 kits/appkit/test/moduletest/appexecfwk_appkit_native_app_module_test_first.cpp create mode 100644 kits/appkit/test/moduletest/appexecfwk_appkit_native_app_module_test_fourth.cpp create mode 100644 kits/appkit/test/moduletest/appexecfwk_appkit_native_app_module_test_second.cpp create mode 100644 kits/appkit/test/moduletest/appexecfwk_appkit_native_app_module_test_third.cpp create mode 100644 libs/libeventhandler/BUILD.gn create mode 100644 libs/libeventhandler/lib_event_handler_sources.gni create mode 100644 libs/libeventhandler/src/epoll_io_waiter.cpp create mode 100644 libs/libeventhandler/src/epoll_io_waiter.h create mode 100644 libs/libeventhandler/src/event_handler.cpp create mode 100644 libs/libeventhandler/src/event_handler_utils.h create mode 100644 libs/libeventhandler/src/event_inner_runner.h create mode 100644 libs/libeventhandler/src/event_queue.cpp create mode 100644 libs/libeventhandler/src/event_runner.cpp create mode 100644 libs/libeventhandler/src/file_descriptor_listener.cpp create mode 100644 libs/libeventhandler/src/inner_event.cpp create mode 100644 libs/libeventhandler/src/io_waiter.h create mode 100644 libs/libeventhandler/src/native_implement_eventhandler.cpp create mode 100644 libs/libeventhandler/src/none_io_waiter.cpp create mode 100644 libs/libeventhandler/src/none_io_waiter.h create mode 100644 libs/libeventhandler/src/thread_local_data.h create mode 100644 libs/libeventhandler/test/BUILD.gn create mode 100644 libs/libeventhandler/test/unittest/lib_event_handler_event_queue_test.cpp create mode 100644 libs/libeventhandler/test/unittest/lib_event_handler_event_runner_test.cpp create mode 100644 libs/libeventhandler/test/unittest/lib_event_handler_event_test.cpp create mode 100644 libs/test/BUILD.gn create mode 100644 libs/test/moduletest/common/event_handler/BUILD.gn create mode 100644 libs/test/moduletest/common/event_handler/event_handler_fd_listener_module_test.cpp create mode 100644 libs/test/moduletest/common/event_handler/event_handler_post_task_module_test.cpp create mode 100644 libs/test/moduletest/common/event_handler/event_handler_press_module_test.cpp create mode 100644 libs/test/moduletest/common/event_handler/event_handler_send_event_module_test.cpp create mode 100644 libs/test/moduletest/common/event_handler/event_handler_send_sync_event_module_test.cpp create mode 100644 libs/test/moduletest/common/event_handler/event_handler_send_timing_event_module_test.cpp create mode 100644 libs/test/moduletest/common/event_handler/event_handler_set_get_remove_module_test.cpp create mode 100644 libs/test/moduletest/common/event_handler/event_handler_test_common.cpp create mode 100644 libs/test/moduletest/common/event_handler/event_handler_test_common.h create mode 100644 ohos.build create mode 100644 sa_profile/401.xml create mode 100644 sa_profile/501.xml create mode 100644 sa_profile/BUILD.gn create mode 100755 sa_profile/foundation.rc create mode 100644 services/BUILD.gn create mode 100644 services/appmgr/BUILD.gn create mode 100644 services/appmgr/examples/BUILD.gn create mode 100644 services/appmgr/examples/app_mgr_service_register_test/main_client.cpp create mode 100644 services/appmgr/examples/app_spawn_client_test/main.cpp create mode 100644 services/appmgr/include/ability_running_record.h create mode 100644 services/appmgr/include/ams_mgr_scheduler.h create mode 100644 services/appmgr/include/app_death_recipient.h create mode 100644 services/appmgr/include/app_lifecycle_deal.h create mode 100644 services/appmgr/include/app_mgr_service.h create mode 100644 services/appmgr/include/app_mgr_service_event_handler.h create mode 100644 services/appmgr/include/app_mgr_service_inner.h create mode 100644 services/appmgr/include/app_process_manager.h create mode 100644 services/appmgr/include/app_running_manager.h create mode 100644 services/appmgr/include/app_running_record.h create mode 100644 services/appmgr/include/app_spawn_client.h create mode 100644 services/appmgr/include/app_spawn_msg_wrapper.h create mode 100644 services/appmgr/include/app_spawn_socket.h create mode 100644 services/appmgr/include/cgroup_manager.h create mode 100644 services/appmgr/include/lmk_util.h create mode 100644 services/appmgr/include/lmkd_client.h create mode 100644 services/appmgr/include/process_optimizer.h create mode 100644 services/appmgr/include/process_optimizer_uba.h create mode 100644 services/appmgr/include/record_query_result.h create mode 100644 services/appmgr/include/remote_client_manager.h create mode 100644 services/appmgr/include/start_via_asan.h create mode 100644 services/appmgr/src/ability_running_record.cpp create mode 100644 services/appmgr/src/ams_mgr_scheduler.cpp create mode 100644 services/appmgr/src/app_death_recipient.cpp create mode 100644 services/appmgr/src/app_lifecycle_deal.cpp create mode 100644 services/appmgr/src/app_mgr_service.cpp create mode 100644 services/appmgr/src/app_mgr_service_event_handler.cpp create mode 100644 services/appmgr/src/app_mgr_service_inner.cpp create mode 100644 services/appmgr/src/app_process_manager.cpp create mode 100644 services/appmgr/src/app_running_manager.cpp create mode 100644 services/appmgr/src/app_running_record.cpp create mode 100644 services/appmgr/src/app_spawn_client.cpp create mode 100644 services/appmgr/src/app_spawn_msg_wrapper.cpp create mode 100644 services/appmgr/src/app_spawn_socket.cpp create mode 100644 services/appmgr/src/cgroup_manager.cpp create mode 100644 services/appmgr/src/lmk_util.cpp create mode 100644 services/appmgr/src/lmkd_client.cpp create mode 100644 services/appmgr/src/process_optimizer.cpp create mode 100644 services/appmgr/src/process_optimizer_uba.cpp create mode 100644 services/appmgr/src/remote_client_manager.cpp create mode 100644 services/appmgr/src/start_via_asan.cpp create mode 100644 services/appmgr/test/BUILD.gn create mode 100644 services/appmgr/test/mock/include/mock_ability_token.h create mode 100644 services/appmgr/test/mock/include/mock_ams_mgr_scheduler.h create mode 100644 services/appmgr/test/mock/include/mock_app_mgr_service.h create mode 100644 services/appmgr/test/mock/include/mock_app_mgr_service_inner.h create mode 100644 services/appmgr/test/mock/include/mock_app_scheduler.h create mode 100644 services/appmgr/test/mock/include/mock_app_service_mgr.h create mode 100644 services/appmgr/test/mock/include/mock_app_spawn_client.h create mode 100644 services/appmgr/test/mock/include/mock_app_spawn_socket.h create mode 100644 services/appmgr/test/mock/include/mock_application.h create mode 100644 services/appmgr/test/mock/include/mock_bundle_manager.h create mode 100644 services/appmgr/test/mock/include/mock_iapp_state_callback.h create mode 100644 services/appmgr/test/mock/include/sys_mgr_client.h create mode 100644 services/appmgr/test/mock/include/system_ability.h create mode 100644 services/appmgr/test/mock/src/mock_bundle_manager.cpp create mode 100644 services/appmgr/test/mock/src/sys_mgr_client_mock.cpp create mode 100644 services/appmgr/test/unittest/ams_ability_running_record_test/BUILD.gn create mode 100644 services/appmgr/test/unittest/ams_ability_running_record_test/ams_ability_running_record_test.cpp create mode 100644 services/appmgr/test/unittest/ams_app_death_recipient_test/BUILD.gn create mode 100644 services/appmgr/test/unittest/ams_app_death_recipient_test/ams_app_death_recipient_test.cpp create mode 100644 services/appmgr/test/unittest/ams_app_life_cycle_test/BUILD.gn create mode 100644 services/appmgr/test/unittest/ams_app_life_cycle_test/ams_app_life_cycle_test.cpp create mode 100644 services/appmgr/test/unittest/ams_app_mgr_client_test/BUILD.gn create mode 100644 services/appmgr/test/unittest/ams_app_mgr_client_test/ams_app_mgr_client_test.cpp create mode 100644 services/appmgr/test/unittest/ams_app_running_record_test/BUILD.gn create mode 100644 services/appmgr/test/unittest/ams_app_running_record_test/ams_app_running_record_test.cpp create mode 100644 services/appmgr/test/unittest/ams_app_state_callback_test/BUILD.gn create mode 100644 services/appmgr/test/unittest/ams_app_state_callback_test/ams_app_state_callback_test.cpp create mode 100644 services/appmgr/test/unittest/ams_app_workflow_test/BUILD.gn create mode 100644 services/appmgr/test/unittest/ams_app_workflow_test/ams_workflow_test.cpp create mode 100644 services/appmgr/test/unittest/ams_ipc_interface_test/BUILD.gn create mode 100644 services/appmgr/test/unittest/ams_ipc_interface_test/ams_ipc_appmgr_interface_test.cpp create mode 100644 services/appmgr/test/unittest/ams_ipc_interface_test/ams_ipc_appscheduler_interface_test.cpp create mode 100644 services/appmgr/test/unittest/ams_mgr_scheduler_test/BUILD.gn create mode 100644 services/appmgr/test/unittest/ams_mgr_scheduler_test/ams_mgr_scheduler_test.cpp create mode 100644 services/appmgr/test/unittest/ams_recent_app_list_test/BUILD.gn create mode 100644 services/appmgr/test/unittest/ams_recent_app_list_test/ams_recent_app_list_test.cpp create mode 100644 services/appmgr/test/unittest/ams_service_app_spawn_client_test/BUILD.gn create mode 100644 services/appmgr/test/unittest/ams_service_app_spawn_client_test/ams_service_app_spawn_client_test.cpp create mode 100644 services/appmgr/test/unittest/ams_service_app_spawn_msg_wrapper_test/BUILD.gn create mode 100644 services/appmgr/test/unittest/ams_service_app_spawn_msg_wrapper_test/ams_service_app_spawn_msg_wrapper_test.cpp create mode 100644 services/appmgr/test/unittest/ams_service_app_spawn_socket_test/BUILD.gn create mode 100644 services/appmgr/test/unittest/ams_service_app_spawn_socket_test/ams_service_app_spawn_socket_test.cpp create mode 100644 services/appmgr/test/unittest/ams_service_event_drive_test/BUILD.gn create mode 100644 services/appmgr/test/unittest/ams_service_event_drive_test/ams_service_event_drive_test.cpp create mode 100644 services/appmgr/test/unittest/ams_service_load_ability_process_test/BUILD.gn create mode 100644 services/appmgr/test/unittest/ams_service_load_ability_process_test/ams_service_load_ability_process_test.cpp create mode 100644 services/appmgr/test/unittest/ams_service_startup_test/BUILD.gn create mode 100644 services/appmgr/test/unittest/ams_service_startup_test/ams_service_startup_test.cpp create mode 100644 services/appmgr/test/unittest/ams_start_via_asan_test/BUILD.gn create mode 100644 services/appmgr/test/unittest/ams_start_via_asan_test/ams_start_via_asan_test.cpp create mode 100644 services/appmgr/test/unittest/app_mgr_service_event_handler_test/BUILD.gn create mode 100644 services/appmgr/test/unittest/app_mgr_service_event_handler_test/app_mgr_service_event_handler_test.cpp create mode 100644 services/appmgr/zidl/IAbilityScheduler.zidl create mode 100644 services/appmgr/zidl/IAppMgr.zidl create mode 100644 services/appmgr/zidl/IAppScheduler.zidl create mode 100644 services/appmgr/zidl/IAppStateCallback.zidl create mode 100644 services/bundlemgr/BUILD.gn create mode 100644 services/bundlemgr/appexecfwk_bundlemgr.gni create mode 100644 services/bundlemgr/include/base_bundle_installer.h create mode 100644 services/bundlemgr/include/base_extractor.h create mode 100755 services/bundlemgr/include/bundle_data_mgr.h create mode 100644 services/bundlemgr/include/bundle_data_storage.h create mode 100644 services/bundlemgr/include/bundle_data_storage_interface.h create mode 100644 services/bundlemgr/include/bundle_extractor.h create mode 100644 services/bundlemgr/include/bundle_installer.h create mode 100644 services/bundlemgr/include/bundle_installer_host.h create mode 100644 services/bundlemgr/include/bundle_installer_manager.h create mode 100644 services/bundlemgr/include/bundle_mgr_host_impl.h create mode 100644 services/bundlemgr/include/bundle_mgr_service.h create mode 100755 services/bundlemgr/include/bundle_mgr_service_event_handler.h create mode 100644 services/bundlemgr/include/bundle_parser.h create mode 100644 services/bundlemgr/include/bundle_permission_mgr.h create mode 100644 services/bundlemgr/include/bundle_profile.h create mode 100644 services/bundlemgr/include/bundle_scanner.h create mode 100644 services/bundlemgr/include/bundle_status_callback_death_recipient.h create mode 100644 services/bundlemgr/include/bundle_util.h create mode 100644 services/bundlemgr/include/bundle_verify_mgr.h create mode 100644 services/bundlemgr/include/common_profile.h create mode 100644 services/bundlemgr/include/inner_bundle_info.h create mode 100644 services/bundlemgr/include/installd/installd_host_impl.h create mode 100644 services/bundlemgr/include/installd/installd_operator.h create mode 100644 services/bundlemgr/include/installd/installd_service.h create mode 100644 services/bundlemgr/include/installd_client.h create mode 100644 services/bundlemgr/include/installd_death_recipient.h create mode 100644 services/bundlemgr/include/ipc/installd_host.h create mode 100644 services/bundlemgr/include/ipc/installd_interface.h create mode 100644 services/bundlemgr/include/ipc/installd_proxy.h create mode 100644 services/bundlemgr/include/system_ability_helper.h create mode 100644 services/bundlemgr/include/system_bundle_installer.h create mode 100644 services/bundlemgr/include/zip_file.h create mode 100755 services/bundlemgr/installs.rc create mode 100755 services/bundlemgr/src/base_bundle_installer.cpp create mode 100644 services/bundlemgr/src/base_extractor.cpp create mode 100755 services/bundlemgr/src/bundle_data_mgr.cpp create mode 100644 services/bundlemgr/src/bundle_data_storage.cpp create mode 100644 services/bundlemgr/src/bundle_extractor.cpp create mode 100755 services/bundlemgr/src/bundle_installer.cpp create mode 100644 services/bundlemgr/src/bundle_installer_host.cpp create mode 100755 services/bundlemgr/src/bundle_installer_manager.cpp create mode 100755 services/bundlemgr/src/bundle_mgr_host_impl.cpp create mode 100644 services/bundlemgr/src/bundle_mgr_service.cpp create mode 100755 services/bundlemgr/src/bundle_mgr_service_event_handler.cpp create mode 100644 services/bundlemgr/src/bundle_parser.cpp create mode 100644 services/bundlemgr/src/bundle_permission_mgr.cpp create mode 100644 services/bundlemgr/src/bundle_profile.cpp create mode 100755 services/bundlemgr/src/bundle_scanner.cpp create mode 100644 services/bundlemgr/src/bundle_status_callback_death_recipient.cpp create mode 100644 services/bundlemgr/src/bundle_util.cpp create mode 100644 services/bundlemgr/src/bundle_verify_mgr.cpp create mode 100644 services/bundlemgr/src/inner_bundle_info.cpp create mode 100644 services/bundlemgr/src/installd/installd_host_impl.cpp create mode 100644 services/bundlemgr/src/installd/installd_main.cpp create mode 100644 services/bundlemgr/src/installd/installd_operator.cpp create mode 100644 services/bundlemgr/src/installd/installd_service.cpp create mode 100644 services/bundlemgr/src/installd_client.cpp create mode 100644 services/bundlemgr/src/installd_death_recipient.cpp create mode 100644 services/bundlemgr/src/ipc/installd_host.cpp create mode 100644 services/bundlemgr/src/ipc/installd_proxy.cpp create mode 100644 services/bundlemgr/src/system_ability_helper.cpp create mode 100644 services/bundlemgr/src/system_bundle_installer.cpp create mode 100755 services/bundlemgr/src/zip_file.cpp create mode 100644 services/bundlemgr/test/BUILD.gn create mode 100644 services/bundlemgr/test/mock/include/json_constants.h create mode 100644 services/bundlemgr/test/mock/include/mock_ability_mgr_host.h create mode 100644 services/bundlemgr/test/mock/include/mock_bundle_status.h create mode 100644 services/bundlemgr/test/mock/include/mock_clean_cache.h create mode 100644 services/bundlemgr/test/mock/include/mock_status_receiver.h create mode 100644 services/bundlemgr/test/mock/src/mock_bundle_status.cpp create mode 100644 services/bundlemgr/test/mock/src/mock_clean_cache.cpp create mode 100644 services/bundlemgr/test/mock/src/mock_status_receiver.cpp create mode 100644 services/bundlemgr/test/mock/src/system_ability_helper.cpp create mode 100644 services/bundlemgr/test/unittest/bms_bundle_data_storage_test/BUILD.gn create mode 100755 services/bundlemgr/test/unittest/bms_bundle_data_storage_test/bms_bundle_data_storage_test.cpp create mode 100644 services/bundlemgr/test/unittest/bms_bundle_installer_test/BUILD.gn create mode 100755 services/bundlemgr/test/unittest/bms_bundle_installer_test/bms_bundle_installer_test.cpp create mode 100644 services/bundlemgr/test/unittest/bms_bundle_kit_service_test/BUILD.gn create mode 100755 services/bundlemgr/test/unittest/bms_bundle_kit_service_test/bms_bundle_kit_service_test.cpp create mode 100644 services/bundlemgr/test/unittest/bms_bundle_parser_test/BUILD.gn create mode 100755 services/bundlemgr/test/unittest/bms_bundle_parser_test/bms_bundle_parser_test.cpp create mode 100644 services/bundlemgr/test/unittest/bms_bundle_uninstaller_test/BUILD.gn create mode 100755 services/bundlemgr/test/unittest/bms_bundle_uninstaller_test/bms_bundle_uninstaller_test.cpp create mode 100644 services/bundlemgr/test/unittest/bms_bundle_updater_test/BUILD.gn create mode 100755 services/bundlemgr/test/unittest/bms_bundle_updater_test/bms_bundle_updater_test.cpp create mode 100644 services/bundlemgr/test/unittest/bms_data_mgr_test/BUILD.gn create mode 100755 services/bundlemgr/test/unittest/bms_data_mgr_test/bms_data_mgr_test.cpp create mode 100644 services/bundlemgr/test/unittest/bms_install_daemon_test/BUILD.gn create mode 100755 services/bundlemgr/test/unittest/bms_install_daemon_test/bms_install_daemon_test.cpp create mode 100644 services/bundlemgr/test/unittest/bms_service_bundle_scan_test/BUILD.gn create mode 100755 services/bundlemgr/test/unittest/bms_service_bundle_scan_test/bms_service_bundle_scan_test.cpp create mode 100644 services/bundlemgr/test/unittest/bms_service_startup_test/BUILD.gn create mode 100755 services/bundlemgr/test/unittest/bms_service_startup_test/bms_service_startup_test.cpp create mode 100644 services/test/BUILD.gn create mode 100644 services/test/mock/include/mock_ability_mgr_host.h create mode 100644 services/test/mock/include/mock_status_receiver.h create mode 100644 services/test/mock/src/mock_status_receiver.cpp create mode 100644 services/test/mock/src/system_ability_helper.cpp create mode 100755 services/test/moduletest/common/ams/BUILD.gn create mode 100755 services/test/moduletest/common/ams/ability_running_record_test/BUILD.gn create mode 100644 services/test/moduletest/common/ams/ability_running_record_test/ams_ability_running_record_module_test.cpp create mode 100755 services/test/moduletest/common/ams/app_life_cycle_test/BUILD.gn create mode 100755 services/test/moduletest/common/ams/app_life_cycle_test/ams_app_life_cycle_module_test.cpp create mode 100755 services/test/moduletest/common/ams/app_mgr_service_test/BUILD.gn create mode 100644 services/test/moduletest/common/ams/app_mgr_service_test/ams_app_mgr_service_module_test.cpp create mode 100755 services/test/moduletest/common/ams/app_recent_list_test/BUILD.gn create mode 100644 services/test/moduletest/common/ams/app_recent_list_test/ams_app_recent_list_module_test.cpp create mode 100755 services/test/moduletest/common/ams/app_running_record_test/BUILD.gn create mode 100644 services/test/moduletest/common/ams/app_running_record_test/ams_app_running_record_module_test.cpp create mode 100755 services/test/moduletest/common/ams/app_service_flow_test/BUILD.gn create mode 100644 services/test/moduletest/common/ams/app_service_flow_test/ams_app_service_flow_module_test.cpp create mode 100755 services/test/moduletest/common/ams/ipc_ams_mgr_test/BUILD.gn create mode 100644 services/test/moduletest/common/ams/ipc_ams_mgr_test/ams_ipc_ams_mgr_module_test.cpp create mode 100755 services/test/moduletest/common/ams/ipc_app_mgr_test/BUILD.gn create mode 100644 services/test/moduletest/common/ams/ipc_app_mgr_test/ams_ipc_app_mgr_module_test.cpp create mode 100755 services/test/moduletest/common/ams/ipc_app_scheduler_test/BUILD.gn create mode 100644 services/test/moduletest/common/ams/ipc_app_scheduler_test/ams_ipc_app_scheduler_module_test.cpp create mode 100755 services/test/moduletest/common/ams/service_app_spawn_client_test/BUILD.gn create mode 100644 services/test/moduletest/common/ams/service_app_spawn_client_test/ams_service_app_spawn_client_module_test.cpp create mode 100755 services/test/moduletest/common/ams/service_event_drive_test/BUILD.gn create mode 100644 services/test/moduletest/common/ams/service_event_drive_test/ams_service_event_drive_module_test.cpp create mode 100755 services/test/moduletest/common/ams/service_start_process_test/BUILD.gn create mode 100644 services/test/moduletest/common/ams/service_start_process_test/ams_service_start_process_module_test.cpp create mode 100755 services/test/moduletest/common/bms/BUILD.gn create mode 100755 services/test/moduletest/common/bms/bundle_installer_test/BUILD.gn create mode 100644 services/test/moduletest/common/bms/bundle_installer_test/bms_bundle_installer_module_test.cpp create mode 100755 services/test/moduletest/common/bms/bundle_parser_test/BUILD.gn create mode 100644 services/test/moduletest/common/bms/bundle_parser_test/bms_bundle_parser_module_test.cpp create mode 100755 services/test/moduletest/common/bms/bundle_uninstall_test/BUILD.gn create mode 100755 services/test/moduletest/common/bms/bundle_uninstall_test/bms_bundle_uninstaller_module_test.cpp create mode 100755 services/test/moduletest/common/bms/service_start_process_test/BUILD.gn create mode 100755 services/test/moduletest/common/bms/service_start_process_test/bms_service_start_module_test.cpp create mode 100644 services/test/moduletest/utils/BUILD.gn create mode 100644 services/test/moduletest/utils/include/common_tool.h create mode 100644 services/test/moduletest/utils/src/common_tool.cpp create mode 100644 test/resource/ams/ams_data_ability_bundle/amsDataSystemTestA.hap create mode 100644 test/resource/ams/ams_data_ability_bundle/amsDataSystemTestB.hap create mode 100644 test/resource/ams/ams_data_ability_bundle/amsDataSystemTestC.hap create mode 100644 test/resource/ams/ams_data_ability_bundle/amsKitSystemTestA.hap create mode 100644 test/resource/ams/ams_data_ability_bundle/amsKitSystemTestB.hap create mode 100644 test/resource/ams/ams_data_ability_bundle/amsKitSystemTestDataA.hap create mode 100644 test/resource/ams/ams_data_ability_bundle/amsKitSystemTestDataB.hap create mode 100644 test/resource/ams/ams_data_ability_bundle/test.txt create mode 100644 test/resource/ams/ams_page_ability_bundle/amsKitSTAbilityManager.hap create mode 100644 test/resource/ams/ams_page_ability_bundle/amsKitSystemTest.hap create mode 100644 test/resource/ams/ams_page_ability_bundle/amsKitSystemTestPageA.hap create mode 100644 test/resource/ams/ams_page_ability_bundle/amsSystemTestA.hap create mode 100644 test/resource/ams/ams_page_ability_bundle/amsSystemTestB.hap create mode 100644 test/resource/ams/ams_page_ability_bundle/amsSystemTestC.hap create mode 100644 test/resource/ams/ams_page_ability_bundle/amsSystemTestD.hap create mode 100644 test/resource/ams/ams_page_ability_bundle/amsSystemTestE.hap create mode 100644 test/resource/ams/ams_page_ability_bundle/amsSystemTestErrorK.hap create mode 100644 test/resource/ams/ams_page_ability_bundle/amsSystemTestErrorL.hap create mode 100644 test/resource/ams/ams_page_ability_bundle/amsSystemTestF.hap create mode 100644 test/resource/ams/ams_page_ability_bundle/amsSystemTestG.hap create mode 100644 test/resource/ams/ams_page_ability_bundle/amsSystemTestH.hap create mode 100644 test/resource/ams/ams_page_ability_bundle/amsSystemTestI.hap create mode 100644 test/resource/ams/ams_page_ability_bundle/amsSystemTestM.hap create mode 100644 test/resource/ams/ams_page_ability_bundle/amsSystemTestN.hap create mode 100644 test/resource/ams/ams_page_ability_bundle/amsSystemTestO.hap create mode 100644 test/resource/ams/ams_page_ability_bundle/amsSystemTestP.hap create mode 100644 test/resource/ams/ams_page_ability_bundle/amsSystemTestServiceA.hap create mode 100644 test/resource/ams/ams_service_ability_bundle/amsKitSystemTestPageA.hap create mode 100644 test/resource/ams/ams_service_ability_bundle/amsKitSystemTestService.hap create mode 100644 test/resource/ams/ams_service_ability_bundle/amsSystemTestServiceA.hap create mode 100644 test/resource/ams/ams_service_ability_bundle/amsSystemTestServiceB.hap create mode 100644 test/resource/ams/ams_service_ability_bundle/amsSystemTestServiceC.hap create mode 100644 test/resource/ams/ams_service_ability_bundle/amsSystemTestServiceD.hap create mode 100644 test/resource/ams/ams_service_ability_bundle/amsSystemTestServiceE.hap create mode 100644 test/resource/ams/ams_service_ability_bundle/amsSystemTestServiceF.hap create mode 100644 test/resource/ams/ams_service_ability_bundle/amsSystemTestServiceG.hap create mode 100644 test/resource/ams/ams_service_ability_bundle/amsSystemTestServiceH.hap create mode 100644 test/resource/ams/ohos_test.xml create mode 100644 test/resource/amssystemtestability/abilitySrc/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsDataSystemTestA/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsDataSystemTestA/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsDataSystemTestA/include/ams_st_data_ability_data_a.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsDataSystemTestA/include/ams_st_data_ability_page_a.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsDataSystemTestA/src/ams_st_data_ability_data_a.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsDataSystemTestA/src/ams_st_data_ability_page_a.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsDataSystemTestB/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsDataSystemTestB/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsDataSystemTestB/include/ams_st_data_ability_data_b.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsDataSystemTestB/include/ams_st_data_ability_page_b.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsDataSystemTestB/src/ams_st_data_ability_data_b.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsDataSystemTestB/src/ams_st_data_ability_page_b.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsDataSystemTestC/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsDataSystemTestC/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsDataSystemTestC/include/ams_st_data_ability_data_c1.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsDataSystemTestC/include/ams_st_data_ability_data_c2.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsDataSystemTestC/src/ams_st_data_ability_data_c1.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsDataSystemTestC/src/ams_st_data_ability_data_c2.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSTAbilityManager/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSTAbilityManager/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSTAbilityManager/include/kit_test_ability_manager_second.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSTAbilityManager/src/kit_test_ability_manager_second.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTest/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTest/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTest/include/fifth_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTest/include/fourth_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTest/include/kit_test_ability_manager.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTest/include/main_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTest/include/second_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTest/include/sixth_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTest/include/test_utils.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTest/include/third_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTest/src/fifth_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTest/src/fourth_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTest/src/kit_test_ability_manager.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTest/src/main_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTest/src/second_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTest/src/sixth_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTest/src/test_utils.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTest/src/third_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestA/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestA/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestA/include/main_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestA/include/second_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestA/include/test_utils.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestA/src/main_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestA/src/second_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestA/src/test_utils.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestB/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestB/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestB/include/main_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestB/include/test_utils.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestB/src/main_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestB/src/test_utils.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestDataA/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestDataA/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestDataA/include/ams_st_kit_data_ability_data_a1.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestDataA/include/ams_st_kit_data_ability_data_a2.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestDataA/include/ams_st_kit_data_ability_data_a3.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestDataA/include/ams_st_kit_data_ability_page_a.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestDataA/include/ams_st_kit_data_ability_service_a.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestDataA/src/ams_st_kit_data_ability_data_a1.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestDataA/src/ams_st_kit_data_ability_data_a2.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestDataA/src/ams_st_kit_data_ability_data_a3.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestDataA/src/ams_st_kit_data_ability_page_a.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestDataA/src/ams_st_kit_data_ability_service_a.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestDataB/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestDataB/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestDataB/include/ams_st_kit_data_ability_data_b.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestDataB/include/ams_st_kit_data_ability_page_b.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestDataB/include/ams_st_kit_data_ability_service_b.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestDataB/src/ams_st_kit_data_ability_data_b.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestDataB/src/ams_st_kit_data_ability_page_b.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestDataB/src/ams_st_kit_data_ability_service_b.cpp create mode 100755 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestPageA/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestPageA/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestPageA/include/ability_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestPageA/include/ability_context_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestPageA/include/ability_life_cycle_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestPageA/include/base_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestPageA/include/life_cycle_call_backs_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestPageA/include/life_cycle_observer_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestPageA/include/test_utils.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestPageA/src/ability_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestPageA/src/ability_context_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestPageA/src/ability_life_cycle_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestPageA/src/base_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestPageA/src/life_cycle_call_backs_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestPageA/src/life_cycle_observer_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestPageA/src/test_utils.cpp create mode 100755 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestService/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestService/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestService/include/ability_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestService/include/ability_connection_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestService/include/ability_context_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestService/include/ability_life_cycle_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestService/include/base_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestService/include/life_cycle_call_backs_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestService/include/life_cycle_observer_ability.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestService/include/test_utils.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestService/src/ability_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestService/src/ability_connection_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestService/src/ability_context_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestService/src/ability_life_cycle_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestService/src/base_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestService/src/life_cycle_call_backs_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestService/src/life_cycle_observer_ability.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsKitSystemTestService/src/test_utils.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestA/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestA/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestA/include/amsstabilitya1.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestA/include/amsstabilitya2.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestA/src/amsstabilitya1.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestA/src/amsstabilitya2.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestB/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestB/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestB/include/amsstabilityb1.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestB/src/amsstabilityb1.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestC/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestC/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestC/include/amsstabilityc1.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestC/include/amsstabilityc2.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestC/include/amsstabilityc3.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestC/src/amsstabilityc1.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestC/src/amsstabilityc2.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestC/src/amsstabilityc3.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestD/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestD/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestD/include/amsstabilityd1.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestD/include/amsstabilityd2.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestD/src/amsstabilityd1.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestD/src/amsstabilityd2.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestE/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestE/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestE/include/amsstabilitye1.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestE/src/amsstabilitye1.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestErrorK/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestErrorK/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestErrorK/include/amsstabilityerrork1.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestErrorK/src/amsstabilityerrork1.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestErrorL/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestErrorL/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestErrorL/include/amsstabilityerrorl1.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestErrorL/src/amsstabilityerrorl1.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestF/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestF/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestF/include/amsstabilityf1.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestF/include/amsstabilityf2.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestF/include/amsstabilityf3.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestF/src/amsstabilityf1.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestF/src/amsstabilityf2.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestF/src/amsstabilityf3.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestG/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestG/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestG/include/amsstabilityg1.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestG/include/amsstabilityg2.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestG/src/amsstabilityg1.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestG/src/amsstabilityg2.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestH/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestH/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestH/include/amsstabilityh1.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestH/src/amsstabilityh1.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestI/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestI/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestI/include/amsstabilityi1.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestI/include/amsstabilityi2.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestI/include/amsstabilityi3.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestI/include/amsstabilityi4.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestI/src/amsstabilityi1.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestI/src/amsstabilityi2.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestI/src/amsstabilityi3.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestI/src/amsstabilityi4.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestM/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestM/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestM/include/amsstabilitym1.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestM/src/amsstabilitym1.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestN/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestN/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestN/include/amsstabilityn1.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestN/include/amsstabilityn2.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestN/include/amsstabilityn3.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestN/include/amsstabilityn4.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestN/src/amsstabilityn1.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestN/src/amsstabilityn2.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestN/src/amsstabilityn3.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestN/src/amsstabilityn4.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestO/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestO/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestO/include/amsstabilityo1.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestO/src/amsstabilityo1.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestP/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestP/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestP/include/amsstabilityp1.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestP/src/amsstabilityp1.cpp create mode 100755 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceA/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceA/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceA/include/ams_st_service_ability_a1.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceA/src/ams_st_service_ability_a1.cpp create mode 100755 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceB/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceB/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceB/include/ams_st_service_ability_b2.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceB/include/ams_st_service_ability_b3.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceB/src/ams_st_service_ability_b2.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceB/src/ams_st_service_ability_b3.cpp create mode 100755 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceC/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceC/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceC/include/ams_st_service_ability_c4.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceC/src/ams_st_service_ability_c4.cpp create mode 100755 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceD/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceD/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceD/include/ams_st_service_ability_d1.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceD/src/ams_st_service_ability_d1.cpp create mode 100755 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceE/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceE/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceE/include/ams_st_service_ability_e2.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceE/src/ams_st_service_ability_e2.cpp create mode 100755 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceF/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceF/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceF/include/ams_st_service_ability_f3.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceF/src/ams_st_service_ability_f3.cpp create mode 100755 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceG/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceG/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceG/include/ams_st_service_ability_g1.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceG/src/ams_st_service_ability_g1.cpp create mode 100755 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceH/BUILD.gn create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceH/config.json create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceH/include/ams_st_service_ability_h1.h create mode 100644 test/resource/amssystemtestability/abilitySrc/amsSystemTestServiceH/src/ams_st_service_ability_h1.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/common/kit_test_common_info.h create mode 100644 test/resource/amssystemtestability/abilitySrc/tools/include/event.h create mode 100644 test/resource/amssystemtestability/abilitySrc/tools/include/stoperator.h create mode 100644 test/resource/amssystemtestability/abilitySrc/tools/include/stpageabilityevent.h create mode 100644 test/resource/amssystemtestability/abilitySrc/tools/src/event.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/tools/src/stoperator.cpp create mode 100644 test/resource/amssystemtestability/abilitySrc/tools/src/stpageabilityevent.cpp create mode 100644 test/resource/bundlemgrservice/bundle_kit/test.hap create mode 100644 test/resource/bundlemgrservice/install_daemon/right.hap create mode 100644 test/resource/bundlemgrservice/ohos_test.xml create mode 100644 test/resource/bundlemgrservice/parse_bundle/break_zip.hap create mode 100644 test/resource/bundlemgrservice/parse_bundle/empty_config.hap create mode 100644 test/resource/bundlemgrservice/parse_bundle/format_error_profile.hap create mode 100644 test/resource/bundlemgrservice/parse_bundle/format_missing_profile.hap create mode 100644 test/resource/bundlemgrservice/parse_bundle/new.hap create mode 100644 test/resource/bundlemgrservice/parse_bundle/no_profile.hap create mode 100644 test/resource/bundlemgrservice/parse_bundle/nothing_config.hap create mode 100644 test/resource/bundlemgrservice/test_bundle/error_bundle_profile.hap create mode 100644 test/resource/bundlemgrservice/test_bundle/format_error_profile.hap create mode 100644 test/resource/bundlemgrservice/test_bundle/nofile.hap create mode 100644 test/resource/bundlemgrservice/test_bundle/right.hap create mode 100644 test/resource/bundlemgrservice/test_bundle/right1.hap create mode 100644 test/resource/bundlemgrservice/test_bundle/version1.hap create mode 100644 test/resource/bundlemgrservice/test_bundle/version2.hap create mode 100644 test/resource/bundlemgrservice/test_bundle/version3.hap create mode 100644 test/resource/bundlemgrservice/test_bundle/wrong_bundle_name_sign.hap create mode 100755 test/resource/bundlemgrsst/ohos_test.xml create mode 100755 test/resource/bundlemgrsst/stSystemBundle/bmsSystemBundle1.hap create mode 100755 test/resource/bundlemgrsst/stSystemBundle/bmsSystemBundle2.hap create mode 100755 test/resource/bundlemgrsst/stSystemBundle/bmsSystemBundle3.hap create mode 100755 test/resource/bundlemgrsst/stSystemBundle/bmsSystemBundle4.hap create mode 100755 test/resource/bundlemgrsst/stSystemBundle/bmsSystemBundle5.hap create mode 100644 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle1.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle10.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle11.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle12.rpk create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle13.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle14.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle15.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle16.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle17.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle18.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle19.hap create mode 100644 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle2.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle20.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle21.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle22.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle23.hap create mode 100644 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle24.hap create mode 100644 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle25.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle26.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle27.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle28.rpk create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle3.hap create mode 100644 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle30.hap create mode 100644 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle31.hap create mode 100644 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle32.hap create mode 100644 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle33.hap create mode 100644 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle34.hap create mode 100644 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle35.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle36.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle37.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle38.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle39.hap create mode 100644 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle4.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle40.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle41.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle5.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle6.hap create mode 100644 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle7.hap create mode 100644 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle8.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundle9.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundlee1.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundles1.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundles2.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundlev1.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/bmsThirdBundlev2.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/e1.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/e12.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/e14.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/e21.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/e22.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/e23.hap create mode 100755 test/resource/bundlemgrsst/stThirdBundle/e3.hap create mode 100644 test/resource/bundlemgrsst/stVendorBundle/bmsVendorBundle1.hap create mode 100644 test/resource/bundlemgrsst/stVendorBundle/bmsVendorBundle2.hap create mode 100644 test/resource/bundlemgrsst/stVendorBundle/bmsVendorBundle3.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/other_bundle/bmsThirdBundle1.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/other_bundle/bmsThirdBundle10.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/other_bundle/bmsThirdBundle11.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/other_bundle/bmsThirdBundle12.rpk create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/other_bundle/bmsThirdBundle13.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/other_bundle/bmsThirdBundle14.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/other_bundle/bmsThirdBundle15.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/other_bundle/bmsThirdBundle16.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/other_bundle/bmsThirdBundle17.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/other_bundle/bmsThirdBundle18.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/other_bundle/bmsThirdBundle19.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/other_bundle/bmsThirdBundle2.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/other_bundle/bmsThirdBundle20.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/other_bundle/bmsThirdBundle21.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/other_bundle/bmsThirdBundle22.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/other_bundle/bmsThirdBundle23.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/other_bundle/bmsThirdBundle24.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/other_bundle/bmsThirdBundle25.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/other_bundle/bmsThirdBundle26.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/other_bundle/bmsThirdBundle27.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/other_bundle/bmsThirdBundle28.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/other_bundle/bmsThirdBundle3.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/other_bundle/bmsThirdBundle4.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/other_bundle/bmsThirdBundle5.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/other_bundle/bmsThirdBundle6.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/other_bundle/bmsThirdBundle7.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/other_bundle/bmsThirdBundle8.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/other_bundle/bmsThirdBundle9.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/system_bundle/bmsSystemBundle1.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/system_bundle/bmsSystemBundle2.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/system_bundle/bmsSystemBundle3.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/system_bundle/bmsSystemBundle4.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/system_bundle/bmsSystemBundle5.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/vendor_bundle/bmsVendorBundle1.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/vendor_bundle/bmsVendorBundle2.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/vendor_bundle/bmsVendorBundle3.hap create mode 100644 test/resource/mstbundlemgrservice/mst_bundle/vendor_bundle/bmsVendorBundle4.hap create mode 100644 test/resource/mstbundlemgrservice/ohos_test.xml create mode 100644 test/resource/tools/bm/pageAbilityBundleForInstall.hap create mode 100644 test/resource/tools/bm/pageAbilityBundleForUninstall.hap create mode 100644 test/resource/tools/ohos_test.xml create mode 100755 test/systemtest/BUILD.gn create mode 100755 test/systemtest/common/ams/BUILD.gn create mode 100644 test/systemtest/common/ams/ams_aa_command_test/BUILD.gn create mode 100755 test/systemtest/common/ams/ams_aa_command_test/ams_aa_command_test.cpp create mode 100644 test/systemtest/common/ams/ams_app_process_manage_test/BUILD.gn create mode 100644 test/systemtest/common/ams/ams_app_process_manage_test/ams_app_process_manage_test.cpp create mode 100644 test/systemtest/common/ams/ams_data_ability_test/BUILD.gn create mode 100644 test/systemtest/common/ams/ams_data_ability_test/ams_data_ability_test.cpp create mode 100644 test/systemtest/common/ams/ams_data_ability_test/ams_data_ability_test_def.h create mode 100644 test/systemtest/common/ams/ams_kit_test/BUILD.gn create mode 100644 test/systemtest/common/ams/ams_kit_test/acts_ams_kit_a_test.cpp create mode 100644 test/systemtest/common/ams/ams_kit_test/acts_ams_kit_data_test.cpp create mode 100644 test/systemtest/common/ams/ams_kit_test/acts_ams_kit_lifecycle_test.cpp create mode 100644 test/systemtest/common/ams/ams_kit_test/acts_ams_kit_processinfo_test.cpp create mode 100644 test/systemtest/common/ams/ams_kit_test/acts_ams_kit_service_ability_test.cpp create mode 100644 test/systemtest/common/ams/ams_kit_test/acts_ams_kit_skills_test.cpp create mode 100644 test/systemtest/common/ams/ams_kit_test/acts_ams_kit_test.cpp create mode 100644 test/systemtest/common/ams/ams_kit_test/acts_ams_kit_want_test.cpp create mode 100644 test/systemtest/common/ams/ams_page_ability_test/BUILD.gn create mode 100644 test/systemtest/common/ams/ams_page_ability_test/ams_page_ability_test.cpp create mode 100755 test/systemtest/common/ams/ams_service_ability_test/BUILD.gn create mode 100755 test/systemtest/common/ams/ams_service_ability_test/ams_service_ability_test.cpp create mode 100644 test/systemtest/common/ams/ams_service_ability_test/ams_service_ability_test_def.h create mode 100644 test/systemtest/common/ams/tool/BUILD.gn create mode 100644 test/systemtest/common/ams/tool/include/event.h create mode 100644 test/systemtest/common/ams/tool/include/module_test_dump_util.h create mode 100644 test/systemtest/common/ams/tool/include/stoperator.h create mode 100644 test/systemtest/common/ams/tool/include/system_test_ability_util.h create mode 100644 test/systemtest/common/ams/tool/src/event.cpp create mode 100644 test/systemtest/common/ams/tool/src/module_test_dump_util.cpp create mode 100644 test/systemtest/common/ams/tool/src/stoperator.cpp create mode 100644 test/systemtest/common/ams/tool/src/system_test_ability_util.cpp create mode 100755 test/systemtest/common/bms/BUILD.gn create mode 100644 test/systemtest/common/bms/acts_bms_kit_system_test/BUILD.gn create mode 100755 test/systemtest/common/bms/acts_bms_kit_system_test/acts_bms_kit_system_test.cpp create mode 100755 test/systemtest/common/bms/bms_install_system_test/BUILD.gn create mode 100755 test/systemtest/common/bms/bms_install_system_test/bms_install_system_test.cpp create mode 100755 test/systemtest/common/bms/bms_search_system_test/BUILD.gn create mode 100644 test/systemtest/common/bms/bms_search_system_test/bms_search_system_test.cpp create mode 100755 test/systemtest/common/bms/bms_uninstall_system_test/BUILD.gn create mode 100755 test/systemtest/common/bms/bms_uninstall_system_test/bms_uninstall_system_test.cpp create mode 100755 test/systemtest/common/ems/BUILD.gn create mode 100755 test/systemtest/common/ems/ems_dumper_system_test/BUILD.gn create mode 100755 test/systemtest/common/ems/ems_dumper_system_test/ems_dumper_system_test.cpp create mode 100755 test/systemtest/common/ems/ems_event_handler_system_test/BUILD.gn create mode 100755 test/systemtest/common/ems/ems_event_handler_system_test/ems_event_handler_test.cpp create mode 100644 test/systemtest/common/ems/ems_event_queue_system_test/BUILD.gn create mode 100644 test/systemtest/common/ems/ems_event_queue_system_test/ems_event_queue_system_test.cpp create mode 100755 test/systemtest/common/ems/ems_event_runner_system_test/BUILD.gn create mode 100755 test/systemtest/common/ems/ems_event_runner_system_test/ems_event_runner_system_test.cpp create mode 100644 test/systemtest/common/ems/ems_inner_event_system_test/BUILD.gn create mode 100644 test/systemtest/common/ems/ems_inner_event_system_test/ems_inner_event_system_test.cpp create mode 100755 test/systemtest/common/ems/ems_logger_system_test/BUILD.gn create mode 100755 test/systemtest/common/ems/ems_logger_system_test/ems_logger_system_test.cpp create mode 100644 tools/BUILD.gn create mode 100644 tools/bm/BUILD.gn create mode 100644 tools/bm/include/bundle_command.h create mode 100644 tools/bm/include/status_receiver_impl.h create mode 100644 tools/bm/src/bundle_command.cpp create mode 100644 tools/bm/src/main.cpp create mode 100644 tools/bm/src/status_receiver_impl.cpp create mode 100644 tools/test/BUILD.gn create mode 100644 tools/test/mock/mock_bundle_installer_host.cpp create mode 100644 tools/test/mock/mock_bundle_installer_host.h create mode 100644 tools/test/mock/mock_bundle_mgr_host.cpp create mode 100644 tools/test/mock/mock_bundle_mgr_host.h create mode 100644 tools/test/moduletest/bm/BUILD.gn create mode 100644 tools/test/moduletest/bm/bundle_command_dump_module_test.cpp create mode 100644 tools/test/moduletest/bm/bundle_command_install_module_test.cpp create mode 100644 tools/test/moduletest/bm/bundle_command_uninstall_module_test.cpp create mode 100644 tools/test/systemtest/bm/BUILD.gn create mode 100644 tools/test/systemtest/bm/bundle_command_dump_system_test.cpp create mode 100644 tools/test/systemtest/bm/bundle_command_install_system_test.cpp create mode 100644 tools/test/systemtest/bm/bundle_command_uninstall_system_test.cpp create mode 100644 tools/test/unittest/bm/BUILD.gn create mode 100644 tools/test/unittest/bm/bundle_command_dump_test.cpp create mode 100644 tools/test/unittest/bm/bundle_command_install_test.cpp create mode 100644 tools/test/unittest/bm/bundle_command_test.cpp create mode 100644 tools/test/unittest/bm/bundle_command_uninstall_test.cpp diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..51c63e295 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,15 @@ +*.tgz filter=lfs diff=lfs merge=lfs -text +*.trp filter=lfs diff=lfs merge=lfs -text +*.apk filter=lfs diff=lfs merge=lfs -text +*.jar filter=lfs diff=lfs merge=lfs -text +*.mp4 filter=lfs diff=lfs merge=lfs -text +*.zip filter=lfs diff=lfs merge=lfs -text +*.asm filter=lfs diff=lfs merge=lfs -text +*.8svn filter=lfs diff=lfs merge=lfs -text +*.9svn filter=lfs diff=lfs merge=lfs -text +*.dylib filter=lfs diff=lfs merge=lfs -text +*.exe filter=lfs diff=lfs merge=lfs -text +*.a filter=lfs diff=lfs merge=lfs -text +*.so filter=lfs diff=lfs merge=lfs -text +*.bin filter=lfs diff=lfs merge=lfs -text +*.dll filter=lfs diff=lfs merge=lfs -text diff --git a/BUILD.gn b/BUILD.gn new file mode 100644 index 000000000..1c9ad50e2 --- /dev/null +++ b/BUILD.gn @@ -0,0 +1,47 @@ +# 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("interfaces/innerkits/appexecfwk_base/appexecfwk_base_header.gni") +import("interfaces/innerkits/appexecfwk_core/appexecfwk_headers.gni") +import("interfaces/innerkits/libeventhandler/lib_event_handler_headers.gni") + +# install to /system/framework +ohos_combine_jars("appexecfwk_install_java") { + deps = [ + "common:appexecfwk_utils_java", + "interfaces/innerkits/abilityshell_java:abilityshell_inner_java", + "interfaces/innerkits/abilityshell_java:abilityshell_java", + "interfaces/innerkits/appexecfwk_base_java:appexecfwk_base_java", + "interfaces/innerkits/appexecfwk_java:appexecfwk_java", + "interfaces/innerkits/appexecfwk_launcher_java:appexecfwk_launcher_java", + "interfaces/innerkits/bundlemgr_adapter_java:bundlemgr_adapter_java", + "interfaces/innerkits/bundlemgr_adapter_java:package_manager_adapter_java", + "interfaces/innerkits/eventhandler_java:eventhandler_java", + "interfaces/innerkits/handler_adapter_java:handler_adapter_java", + "interfaces/innerkits/interwork_java:interwork_java", + "interfaces/innerkits/pluginproxy_adapter_java:pluginproxy_adapter_java", + "kits/appkit:appkit_java", + ] + + if (!is_ivi_product) { + deps += [ "interfaces/innerkits/appexecfwk_plugin:appexecfwk_plugin_java" ] + } + + if (is_double_framework && !mrt) { + subsystem_name = "appexecfwk" + part_name = "appexecfwk_standard" + dex_path = "${target_out_dir}/appexecfwk.z.jar" + } +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..4a459866a --- /dev/null +++ b/LICENSE @@ -0,0 +1,177 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/OAT.xml b/OAT.xml new file mode 100644 index 000000000..aa01ceabe --- /dev/null +++ b/OAT.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + diff --git a/README.en.md b/README.en.md deleted file mode 100644 index 3e1b1167c..000000000 --- a/README.en.md +++ /dev/null @@ -1,36 +0,0 @@ -# appexecfwk_standard - -#### Description -Application execution and management framework | 用户程序运行管理框架 - -#### Software Architecture -Software architecture description - -#### Installation - -1. xxxx -2. xxxx -3. xxxx - -#### Instructions - -1. xxxx -2. xxxx -3. xxxx - -#### Contribution - -1. Fork the repository -2. Create Feat_xxx branch -3. Commit your code -4. Create Pull Request - - -#### Gitee Feature - -1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md -2. Gitee blog [blog.gitee.com](https://blog.gitee.com) -3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) -4. The most valuable open source project [GVP](https://gitee.com/gvp) -5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) -6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/README.md b/README.md deleted file mode 100644 index 77c4188eb..000000000 --- a/README.md +++ /dev/null @@ -1,37 +0,0 @@ -# appexecfwk_standard - -#### 介绍 -Application execution and management framework | 用户程序运行管理框架 - -#### 软件架构 -软件架构说明 - - -#### 安装教程 - -1. xxxx -2. xxxx -3. xxxx - -#### 使用说明 - -1. xxxx -2. xxxx -3. xxxx - -#### 参与贡献 - -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request - - -#### 特技 - -1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md -2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) -3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 -5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/README_zh.md b/README_zh.md new file mode 100755 index 000000000..614c89fa0 --- /dev/null +++ b/README_zh.md @@ -0,0 +1,96 @@ +# **用户程序框架子系统** + +## 简介 + +用户程序框架子系统是OpenHarmony为开发者提供的一套开发OpenHarmony应用程序的框架。 + +**包含以下模块:** + +- **AppKit:**是用户程序框架提供给开发者的开发包,开发者基于该开发包可以开发出基于Ability组件的应用。 + +- **AppManagerService:**应用管理服务,用于管理应用运行关系、调度应用进程生命周期及状态的系统服务。 + +- **BundleManagerService:**是负责管理安装包的系统服务,常见的比如包安装、更新,卸载和包信息查询等,运行在Foundation进程。 + +应用程序框架子系统架构如下图所示: + +![](figures/appexecfwk.png) + + + +## 目录 + +``` +foundation/appexecfwk/standard +├── kits +│   └── appkit # Appkit实现的核心代码 +├── common +│   └── log # 日志组件目录 +├── interfaces +│   └── innerkits # 内部接口存放目录 +├── services +│   ├── appmgr # 用户程序管理服务框架代码 +│   └── bundlemgr # 包管理服务框架代码 +├── test # 测试目录 +└── tools # bm命令存放目录 +``` + +### 使用说明 + +当前版本用户程序框架不具备权限管理的能力。 + +以下模块的JS接口为非正式API,仅供Launcher、Settings、SystemUI等系统应用使用,不排除对这些接口进行变更的可能性,后续版本将提供正式API。 + +- @ohos.bundle_mgr.d.ts +- bundleinfo.d.ts +- common.d.ts +- installresult.d.ts +- moduleinfo.d.ts + + +### bm命令如下 + +**bm命令帮助** + +| 命令 | 描述 | +| ------- | ---------- | +| bm help | bm帮助命令 | + +**安装应用** + +| 命令 | 描述 | +| ----------------------------------- | -------------------------- | +| bm install -p | 通过指定路径安装一个应用包 | +| bm install -r -p | 覆盖安装一个应用包 | + +``` +示例如下: +bm install -p /data/app/ohosapp.hap +``` + +**卸载应用** + +| 命令 | 描述 | +| ----------------------------- | ------------------------ | +| bm uninstall -n | 通过指定包名卸载一个应用 | + +``` +示例如下: +bm uninstall -n com.ohos.app +``` + +**查看应用安装信息** + +| 命令 | 描述 | +| ---------- | -------------------------- | +| bm dump -a | 列出系统已经安装的所有应用 | + +## 相关仓 + +用户程序框架子系统 + +**appexecfwk_standard** + +aafwk_standard + +startup_appspawn diff --git a/appexecfwk.gni b/appexecfwk.gni new file mode 100644 index 000000000..e55f644e9 --- /dev/null +++ b/appexecfwk.gni @@ -0,0 +1,27 @@ +# 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. + +aafwk_path = "//foundation/aafwk/standard" +appexecfwk_path = "//foundation/appexecfwk/standard" +appspawn_path = "//base/startup/appspawn_standard" +even_path = "//base/notification/ces_standard" + +libs_path = "${appexecfwk_path}/libs" +common_path = "${appexecfwk_path}/common" +services_path = "${appexecfwk_path}/services" +kits_path = "${appexecfwk_path}/kits" +innerkits_path = "${appexecfwk_path}/interfaces/innerkits" +tools_path = "${appexecfwk_path}/tools" +test_hap_common_path = "${appexecfwk_path}/test/common" +system_test_app_path = + "${appexecfwk_path}/test/resource/amssystemtestability/abilitySrc" diff --git a/common/BUILD.gn b/common/BUILD.gn new file mode 100644 index 000000000..be0c55d13 --- /dev/null +++ b/common/BUILD.gn @@ -0,0 +1,50 @@ +# 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") + +group("common_target") { + deps = [ ":libappexecfwk_common" ] +} + +config("appexecfwk_common_config") { + include_dirs = [ + "log/include", + "perf/include", + ] +} + +ohos_shared_library("libappexecfwk_common") { + sources = [ + "log/src/app_log_wrapper.cpp", + "perf/src/perf_profile.cpp", + ] + + defines = [ + "APP_LOG_TAG = \"AppExecFwk\"", + "LOG_DOMAIN = 0xD001140", + ] + + public_configs = [ + ":appexecfwk_common_config", + "//utils/native/base:utils_config", + ] + + deps = [ "//utils/native/base:utils" ] + + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + + subsystem_name = "appexecfwk" + part_name = "appexecfwk_standard" +} diff --git a/common/log/README.md b/common/log/README.md new file mode 100644 index 000000000..bd26267e5 --- /dev/null +++ b/common/log/README.md @@ -0,0 +1,54 @@ +## How To Use Log + +# C++ +1. Add a statement to your gn file + +``` + deps = [ + "${common_path}/log:appexecfwk_log_source_set", + ] + + defines = [ + "APP_LOG_TAG = \"Appexecfwk_Core\"", + "LOG_DOMAIN = 0xD001110", + ] +``` +2. Include header file `#include "app_log_wrapper.h"` +3. Control log print level `AppLogWrapper::SetLogLevel(AppLogLevel::DEBUG);` default is DEBUG +4. Example output format `[fileName(functionName)] string` +``` + // dynamic control log level + AppLogWrapper::SetLogLevel(AppLogLevel::FATAL); + + // The following log statement will not print + APP_LOGD("one %{public}d", 1234); + APP_LOGI("two %{public}s", "1234"); + APP_LOGW("three %{private}s", "1234"); + APP_LOGE("four %{private}s", "1234"); + + // The following log statement will print + AppLogWrapper::SetLogLevel(AppLogLevel::DEBUG); + APP_LOGD("five %{public}d", 1234); + APP_LOGI("six %{public}s", "1234"); + APP_LOGW("seven %{private}s", "1234"); + APP_LOGE("eight %{private}s", "1234"); +``` + +# Java + +1. import dependent in your class +``` +import ohosos.appexecfwk.utils.AppLog; +import ohosos.hiviewdfx.HiLogLabel; +``` + +2. custom HiLogLabel (if you don't custom label, the default will be used) +``` +private static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_CORE, 0xD001110, "AppKit"); +``` + +3. use AppLog interface +``` +App_Log.d(LABEL, "log %{public}s", "123"); +App_Log.i("log %{public}d", 123); +``` \ No newline at end of file diff --git a/common/log/include/app_log_wrapper.h b/common/log/include/app_log_wrapper.h new file mode 100644 index 000000000..5d7d4aaf9 --- /dev/null +++ b/common/log/include/app_log_wrapper.h @@ -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. + */ + +#ifndef FOUNDATION_APPEXECFWK_LIBS_LOG_INCLUDE_APP_LOG_WRAPPER_H +#define FOUNDATION_APPEXECFWK_LIBS_LOG_INCLUDE_APP_LOG_WRAPPER_H + +#include "hilog/log.h" +#include + +namespace OHOS { +namespace AppExecFwk { + +#ifndef LOG_DOMAIN +#define LOG_DOMAIN 0xD001100 +#endif + +#ifndef APP_LOG_TAG +#define APP_LOG_TAG NULL +#endif + +enum class AppLogLevel { DEBUG = 0, INFO, WARN, ERROR, FATAL }; + +static constexpr OHOS::HiviewDFX::HiLogLabel APP_LABEL = {LOG_CORE, LOG_DOMAIN, APP_LOG_TAG}; + +class AppLogWrapper { +public: + static bool JudgeLevel(const AppLogLevel &level); + + static void SetLogLevel(const AppLogLevel &level) + { + level_ = level; + } + + static const AppLogLevel &GetLogLevel() + { + return level_; + } + + static std::string GetBriefFileName(const char *str); + +private: + static AppLogLevel level_; +}; + +#define PRINT_LOG(LEVEL, Level, fmt, ...) \ + if (AppLogWrapper::JudgeLevel(AppLogLevel::LEVEL)) \ + OHOS::HiviewDFX::HiLog::Level(APP_LABEL, \ + "[%{public}s(%{public}s):%{public}d] " fmt, \ + AppLogWrapper::GetBriefFileName(__FILE__).c_str(), \ + __FUNCTION__, \ + __LINE__, \ + ##__VA_ARGS__) + +#define APP_LOGD(fmt, ...) PRINT_LOG(DEBUG, Debug, fmt, ##__VA_ARGS__) +#define APP_LOGI(fmt, ...) PRINT_LOG(INFO, Info, fmt, ##__VA_ARGS__) +#define APP_LOGW(fmt, ...) PRINT_LOG(WARN, Warn, fmt, ##__VA_ARGS__) +#define APP_LOGE(fmt, ...) PRINT_LOG(ERROR, Error, fmt, ##__VA_ARGS__) +#define APP_LOGF(fmt, ...) PRINT_LOG(FATAL, Fatal, fmt, ##__VA_ARGS__) + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_LIBS_LOG_INCLUDE_APP_LOG_WRAPPER_H diff --git a/common/log/src/app_log_wrapper.cpp b/common/log/src/app_log_wrapper.cpp new file mode 100644 index 000000000..17f6b31a3 --- /dev/null +++ b/common/log/src/app_log_wrapper.cpp @@ -0,0 +1,44 @@ +/* + * 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 + +namespace OHOS { +namespace AppExecFwk { + +// initial static member object +AppLogLevel AppLogWrapper::level_ = AppLogLevel::DEBUG; + +bool AppLogWrapper::JudgeLevel(const AppLogLevel &level) +{ + return (AppLogWrapper::GetLogLevel() <= level); +} + +std::string AppLogWrapper::GetBriefFileName(const char *str) +{ + if (!str) { + return std::string(); + } + std::string fullPath(str); + size_t pos = fullPath.find_last_of("/"); + if (pos == std::string::npos) { + return std::string(); + } + return fullPath.substr(pos + 1); +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/common/perf/include/perf_profile.h b/common/perf/include/perf_profile.h new file mode 100644 index 000000000..101f362ff --- /dev/null +++ b/common/perf/include/perf_profile.h @@ -0,0 +1,125 @@ +/* + * 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_COMMON_INCLUDE_PERF_PROFILE_H +#define FOUNDATION_APPEXECFWK_SERVICES_COMMON_INCLUDE_PERF_PROFILE_H + +#include + +#include "singleton.h" + +namespace OHOS { +namespace AppExecFwk { + +class PerfProfile : public Singleton { + DECLARE_SINGLETON(PerfProfile); + +public: + int64_t GetBmsLoadStartTime() const; + void SetBmsLoadStartTime(int64_t time); + + int64_t GetBmsLoadEndTime() const; + void SetBmsLoadEndTime(int64_t time); + + int64_t GetBundleScanStartTime() const; + void SetBundleScanStartTime(int64_t time); + + int64_t GetBundleScanEndTime() const; + void SetBundleScanEndTime(int64_t time); + + int64_t GetBundleDownloadStartTime() const; + void SetBundleDownloadStartTime(int64_t time); + + int64_t GetBundleDownloadEndTime() const; + void SetBundleDownloadEndTime(int64_t time); + + int64_t GetBundleInstallStartTime() const; + void SetBundleInstallStartTime(int64_t time); + int64_t GetBundleTotalInstallTime() const; + + int64_t GetBundleInstallEndTime() const; + void SetBundleInstallEndTime(int64_t time); + + int64_t GetBundleUninstallStartTime() const; + void SetBundleUninstallStartTime(int64_t time); + + int64_t GetBundleUninstallEndTime() const; + void SetBundleUninstallEndTime(int64_t time); + + int64_t GetBundleParseStartTime() const; + void SetBundleParseStartTime(int64_t time); + + int64_t GetBundleParseEndTime() const; + void SetBundleParseEndTime(int64_t time); + + int64_t GetAmsLoadStartTime() const; + void SetAmsLoadStartTime(int64_t time); + + int64_t GetAmsLoadEndTime() const; + void SetAmsLoadEndTime(int64_t time); + + int64_t GetAbilityLoadStartTime() const; + void SetAbilityLoadStartTime(int64_t time); + + int64_t GetAbilityLoadEndTime() const; + void SetAbilityLoadEndTime(int64_t time); + + int64_t GetAppForkStartTime() const; + void SetAppForkStartTime(int64_t time); + + int64_t GetAppForkEndTime() const; + void SetAppForkEndTime(int64_t time); + + bool GetPerfProfileEnabled() const; + void SetPerfProfileEnabled(bool enable); + + void Reset(); + + void Dump() const; + +private: + int64_t bmsLoadStart_ = 0; + int64_t bmsLoadEnd_ = 0; + + int64_t bundleScanStart_ = 0; + int64_t bundleScanEnd_ = 0; + + int64_t bundleDownloadStart_ = 0; + int64_t bundleDownloadEnd_ = 0; + + int64_t bundleInstallStart_ = 0; + int64_t bundleInstallEnd_ = 0; + int64_t bundleInstallTime_ = 0; + + int64_t bundleUninstallStart_ = 0; + int64_t bundleUninstallEnd_ = 0; + + int64_t bundleParseStart_ = 0; + int64_t bundleParseEnd_ = 0; + + int64_t amsLoadStart_ = 0; + int64_t amsLoadEnd_ = 0; + + int64_t abilityLoadStart_ = 0; + int64_t abilityLoadEnd_ = 0; + int64_t appForkStart_ = 0; + int64_t appForkEnd_ = 0; + + bool enableProfile_ = true; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_COMMON_INCLUDE_PERF_PROFILE_H diff --git a/common/perf/src/perf_profile.cpp b/common/perf/src/perf_profile.cpp new file mode 100755 index 000000000..8ee14ea9a --- /dev/null +++ b/common/perf/src/perf_profile.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 "perf_profile.h" +#include + +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { + +PerfProfile::PerfProfile() +{ + APP_LOGD("create"); +} + +PerfProfile::~PerfProfile() +{ + APP_LOGD("destroy"); +} + +int64_t PerfProfile::GetBmsLoadStartTime() const +{ + return bmsLoadStart_; +} + +void PerfProfile::SetBmsLoadStartTime(int64_t time) +{ + bmsLoadStart_ = (time > 0) ? time : 0; +} + +int64_t PerfProfile::GetBmsLoadEndTime() const +{ + return bmsLoadEnd_; +} + +void PerfProfile::SetBmsLoadEndTime(int64_t time) +{ + bmsLoadEnd_ = (time > 0 && time > bmsLoadStart_) ? time : bmsLoadStart_; +} + +int64_t PerfProfile::GetBundleScanStartTime() const +{ + return bundleScanStart_; +} + +void PerfProfile::SetBundleScanStartTime(int64_t time) +{ + bundleScanStart_ = (time > 0) ? time : 0; +} + +int64_t PerfProfile::GetBundleScanEndTime() const +{ + return bundleScanEnd_; +} + +void PerfProfile::SetBundleScanEndTime(int64_t time) +{ + bundleScanEnd_ = (time > 0 && time > bundleScanStart_) ? time : bundleScanStart_; +} + +int64_t PerfProfile::GetBundleDownloadStartTime() const +{ + return bundleDownloadStart_; +} + +void PerfProfile::SetBundleDownloadStartTime(int64_t time) +{ + bundleDownloadStart_ = (time > 0) ? time : 0; +} + +int64_t PerfProfile::GetBundleDownloadEndTime() const +{ + return bundleDownloadEnd_; +} + +void PerfProfile::SetBundleDownloadEndTime(int64_t time) +{ + bundleDownloadEnd_ = (time > 0 && time > bundleDownloadStart_) ? time : bundleDownloadStart_; +} + +int64_t PerfProfile::GetBundleInstallStartTime() const +{ + return bundleInstallStart_; +} + +void PerfProfile::SetBundleInstallStartTime(int64_t time) +{ + bundleInstallStart_ = (time > 0) ? time : 0; +} + +int64_t PerfProfile::GetBundleInstallEndTime() const +{ + return bundleInstallEnd_; +} + +void PerfProfile::SetBundleInstallEndTime(int64_t time) +{ + if (time >= 0 && time > bundleInstallStart_) { + bundleInstallEnd_ = time; + bundleInstallTime_ += (bundleInstallEnd_ - bundleInstallStart_); + } else { + bundleInstallEnd_ = bundleInstallStart_; + } +} + +int64_t PerfProfile::GetBundleTotalInstallTime() const +{ + return bundleInstallTime_; +} + +int64_t PerfProfile::GetBundleUninstallStartTime() const +{ + return bundleUninstallStart_; +} + +void PerfProfile::SetBundleUninstallStartTime(int64_t time) +{ + bundleUninstallStart_ = (time > 0) ? time : 0; +} + +int64_t PerfProfile::GetBundleUninstallEndTime() const +{ + return bundleUninstallEnd_; +} + +void PerfProfile::SetBundleUninstallEndTime(int64_t time) +{ + bundleUninstallEnd_ = (time > 0 && time > bundleUninstallStart_) ? time : bundleUninstallStart_; +} + +int64_t PerfProfile::GetBundleParseStartTime() const +{ + return bundleParseStart_; +} + +void PerfProfile::SetBundleParseStartTime(int64_t time) +{ + bundleParseStart_ = (time > 0) ? time : 0; +} + +int64_t PerfProfile::GetBundleParseEndTime() const +{ + return bundleParseEnd_; +} + +void PerfProfile::SetBundleParseEndTime(int64_t time) +{ + bundleParseEnd_ = (time > 0 && time > bundleParseStart_) ? time : bundleParseStart_; +} + +int64_t PerfProfile::GetAmsLoadStartTime() const +{ + return amsLoadStart_; +} + +void PerfProfile::SetAmsLoadStartTime(int64_t time) +{ + amsLoadStart_ = (time > 0) ? time : 0; +} + +int64_t PerfProfile::GetAmsLoadEndTime() const +{ + return amsLoadEnd_; +} + +void PerfProfile::SetAmsLoadEndTime(int64_t time) +{ + amsLoadEnd_ = (time > 0 && time > amsLoadStart_) ? time : amsLoadStart_; +} + +int64_t PerfProfile::GetAbilityLoadStartTime() const +{ + return abilityLoadStart_; +} + +void PerfProfile::SetAbilityLoadStartTime(int64_t time) +{ + abilityLoadStart_ = (time > 0) ? time : 0; +} + +int64_t PerfProfile::GetAbilityLoadEndTime() const +{ + return abilityLoadEnd_; +} + +void PerfProfile::SetAbilityLoadEndTime(int64_t time) +{ + abilityLoadEnd_ = (time > 0 && time > abilityLoadStart_) ? time : abilityLoadStart_; +} + +int64_t PerfProfile::GetAppForkStartTime() const +{ + return appForkStart_; +} + +void PerfProfile::SetAppForkStartTime(int64_t time) +{ + appForkStart_ = (time > 0) ? time : 0; +} + +int64_t PerfProfile::GetAppForkEndTime() const +{ + return appForkEnd_; +} + +void PerfProfile::SetAppForkEndTime(int64_t time) +{ + appForkEnd_ = (time > 0 && time > appForkStart_) ? time : appForkStart_; +} + +bool PerfProfile::GetPerfProfileEnabled() const +{ + return enableProfile_; +} + +void PerfProfile::SetPerfProfileEnabled(bool enable) +{ + enableProfile_ = enable; +} + +void PerfProfile::Reset() +{ + bmsLoadStart_ = 0; + bmsLoadEnd_ = 0; + + bundleScanStart_ = 0; + bundleScanEnd_ = 0; + + bundleDownloadStart_ = 0; + bundleDownloadEnd_ = 0; + + bundleInstallStart_ = 0; + bundleInstallEnd_ = 0; + bundleInstallTime_ = 0; + + bundleUninstallStart_ = 0; + bundleUninstallEnd_ = 0; + + bundleParseStart_ = 0; + bundleParseEnd_ = 0; + + amsLoadStart_ = 0; + amsLoadEnd_ = 0; + + abilityLoadStart_ = 0; + abilityLoadEnd_ = 0; + appForkStart_ = 0; + appForkEnd_ = 0; + + enableProfile_ = true; +} + +void PerfProfile::Dump() const +{ + if (!enableProfile_) { + APP_LOGI("profile disabled!\n"); + return; + } + + // only dump the valid perf time + if ((bundleScanEnd_ > bundleScanStart_) || (bundleInstallTime_ > 0) || + (bundleUninstallEnd_ > bundleUninstallStart_) || (bundleParseEnd_ > bundleParseStart_) || + (abilityLoadEnd_ > abilityLoadStart_) || (bmsLoadEnd_ > bmsLoadStart_) || (amsLoadEnd_ > amsLoadStart_)) { + APP_LOGI("start\n"); + + APP_LOGI("*************************\n"); + + if (bmsLoadEnd_ > bmsLoadStart_) { + APP_LOGI("BmsLoadTime: %{public}" PRId64 "(ms) \n", (bmsLoadEnd_ - bmsLoadStart_)); + } + if (bundleScanEnd_ > bundleScanStart_) { + APP_LOGI("BundleScanTime: %{public}" PRId64 "(ms) \n", (bundleScanEnd_ - bundleScanStart_)); + } + if (bundleInstallTime_ > 0) { + APP_LOGI("BundleInstallTime: %{public}" PRId64 "(ms) \n", bundleInstallTime_); + } + if (bundleUninstallEnd_ > bundleUninstallStart_) { + APP_LOGI("BundleUninstallTime: %{public}" PRId64 "(ms) \n", (bundleUninstallEnd_ - bundleUninstallStart_)); + } + if (bundleParseEnd_ > bundleParseStart_) { + APP_LOGI("BundleParseTime: %{public}" PRId64 "(ms) \n", (bundleParseEnd_ - bundleParseStart_)); + } + if (amsLoadEnd_ > amsLoadStart_) { + APP_LOGI("AmsLoadTime: %{public}" PRId64 "(ms) \n", (amsLoadEnd_ - amsLoadStart_)); + } + if (abilityLoadEnd_ > abilityLoadStart_) { + APP_LOGI("AbilityLoadTime: %{public}" PRId64 "(ms) \n", (abilityLoadEnd_ - abilityLoadStart_)); + APP_LOGI(" AppForkTime: %{public}" PRId64 "(ms) \n", (appForkEnd_ - appForkStart_)); + } + + APP_LOGI("*************************\n"); + + APP_LOGI("end\n"); + } +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/common/test/BUILD.gn b/common/test/BUILD.gn new file mode 100644 index 000000000..03265c294 --- /dev/null +++ b/common/test/BUILD.gn @@ -0,0 +1,30 @@ +# 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("common_test_config") { + defines = [ + "APP_LOG_TAG = \"AppExecFwk\"", + "LOG_DOMAIN = 0xD00114E", + ] +} + +group("unittest") { + testonly = true + + deps = [ + "unittest/common_appexecfwk_log_test:unittest", + "unittest/common_perf_profile_test:unittest", + ] +} diff --git a/common/test/unittest/common_appexecfwk_log_test/BUILD.gn b/common/test/unittest/common_appexecfwk_log_test/BUILD.gn new file mode 100644 index 000000000..d826a9944 --- /dev/null +++ b/common/test/unittest/common_appexecfwk_log_test/BUILD.gn @@ -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. + +import("//build/test.gni") +import("//foundation/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk/common" + +ohos_unittest("AppExecFwkLogTest") { + module_out_path = module_output_path + + sources = [ "${common_path}/log/src/app_log_wrapper.cpp" ] + + sources += [ "appexecfwk_log_test.cpp" ] + + configs = [ + "${common_path}:appexecfwk_common_config", + "${common_path}/test:common_test_config", + ] + + deps = [ "//third_party/googletest:gtest_main" ] + + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] +} + +group("unittest") { + testonly = true + + deps = [ ":AppExecFwkLogTest" ] +} diff --git a/common/test/unittest/common_appexecfwk_log_test/appexecfwk_log_test.cpp b/common/test/unittest/common_appexecfwk_log_test/appexecfwk_log_test.cpp new file mode 100644 index 000000000..00c43bf9a --- /dev/null +++ b/common/test/unittest/common_appexecfwk_log_test/appexecfwk_log_test.cpp @@ -0,0 +1,97 @@ +/* + * 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" + +using namespace testing::ext; +using namespace OHOS::AppExecFwk; + +class AppExecFwkLogTest : public testing::Test { +public: + static void SetUpTestCase() const; + static void TearDownTestCase() const; + void SetUp() const; + void TearDown() const; +}; + +void AppExecFwkLogTest::SetUpTestCase() const +{} + +void AppExecFwkLogTest::TearDownTestCase() const +{} + +void AppExecFwkLogTest::SetUp() const +{} + +void AppExecFwkLogTest::TearDown() const +{} + +/* + * Feature: AppLogWrapper + * Function: AppLogWrapper + * SubFunction: NA + * FunctionPoints: Dynamically control the log print level + * EnvConditions: NA + * CaseDescription: set log print level + */ +HWTEST_F(AppExecFwkLogTest, AppLogWrapper_001, TestSize.Level0) +{ + EXPECT_EQ(AppLogLevel::DEBUG, AppLogWrapper::GetLogLevel()); + AppLogWrapper::SetLogLevel(AppLogLevel::INFO); + EXPECT_EQ(AppLogLevel::INFO, AppLogWrapper::GetLogLevel()); +} + +/* + * Feature: AppLogWrapper + * Function: AppLogWrapper + * SubFunction: NA + * FunctionPoints: splice filename + * EnvConditions: NA + * CaseDescription: normal valid filename + */ +HWTEST_F(AppExecFwkLogTest, AppLogWrapper_002, TestSize.Level0) +{ + std::string fileName = "../foundation/appexecfwk/test.cpp"; + std::string exceptStr = "test.cpp"; + + std::string result = AppLogWrapper::GetBriefFileName(fileName.c_str()); + EXPECT_EQ(exceptStr, result); +} + +/* + * Feature: AppLogWrapper + * Function: AppLogWrapper + * SubFunction: NA + * FunctionPoints: splice filename + * EnvConditions: NA + * CaseDescription: invalid filename + */ +HWTEST_F(AppExecFwkLogTest, AppLogWrapper_003, TestSize.Level0) +{ + std::string fileName = "test.cpp"; + std::string exceptStr = ""; + + std::string result = AppLogWrapper::GetBriefFileName(fileName.c_str()); + EXPECT_EQ(exceptStr, result); + + fileName = ""; + result = AppLogWrapper::GetBriefFileName(fileName.c_str()); + EXPECT_EQ(exceptStr, result); + + result = AppLogWrapper::GetBriefFileName(nullptr); + EXPECT_EQ(exceptStr, result); +} \ No newline at end of file diff --git a/common/test/unittest/common_perf_profile_test/BUILD.gn b/common/test/unittest/common_perf_profile_test/BUILD.gn new file mode 100644 index 000000000..44dc60586 --- /dev/null +++ b/common/test/unittest/common_perf_profile_test/BUILD.gn @@ -0,0 +1,47 @@ +# 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/common" + +ohos_unittest("CommonPerfProfileTest") { + module_out_path = module_output_path + + sources = [ + "${common_path}/log/src/app_log_wrapper.cpp", + "${common_path}/perf/src/perf_profile.cpp", + ] + + sources += [ "common_perf_profile_test.cpp" ] + + configs = [ + "${common_path}:appexecfwk_common_config", + "${common_path}/test:common_test_config", + "//utils/native/base:utils_config", + ] + + deps = [ + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + ] + + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] +} + +group("unittest") { + testonly = true + + deps = [ ":CommonPerfProfileTest" ] +} diff --git a/common/test/unittest/common_perf_profile_test/common_perf_profile_test.cpp b/common/test/unittest/common_perf_profile_test/common_perf_profile_test.cpp new file mode 100644 index 000000000..1e34867b6 --- /dev/null +++ b/common/test/unittest/common_perf_profile_test/common_perf_profile_test.cpp @@ -0,0 +1,751 @@ +/* + * 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 "perf_profile.h" + +using namespace testing::ext; +using namespace OHOS::AppExecFwk; + +namespace { + +const int64_t INVALID_TIME = -1; + +const int64_t BMS_LOAD_INIT_START_TIME = 0; +const int64_t BMS_LOAD_SET_START_TIME = 10; +const int64_t BMS_LOAD_INIT_END_TIME = 0; +const int64_t BMS_LOAD_SET_END_TIME = 120; + +const int64_t BUNDLE_SCAN_INIT_START_TIME = 0; +const int64_t BUNDLE_SCAN_SET_START_TIME = 100; +const int64_t BUNDLE_SCAN_INIT_END_TIME = 0; +const int64_t BUNDLE_SCAN_SET_END_TIME = 150; + +const int64_t BUNDLE_DOWNLOAD_INIT_START_TIME = 0; +const int64_t BUNDLE_DOWNLOAD_SET_START_TIME = 50; +const int64_t BUNDLE_DOWNLOAD_INIT_END_TIME = 0; +const int64_t BUNDLE_DOWNLOAD_SET_END_TIME = 500; + +const int64_t BUNDLE_INSTALL_INIT_START_TIME = 0; +const int64_t BUNDLE_INSTALL_SET_START_TIME = 50; +const int64_t BUNDLE_INSTALL_SET_START_TIME_SECOND = 400; +const int64_t BUNDLE_INSTALL_INIT_END_TIME = 0; +const int64_t BUNDLE_INSTALL_SET_END_TIME = 300; +const int64_t BUNDLE_INSTALL_SET_END_TIME_SECOND = 500; +const int64_t BUNDLE_INSTALL_INIT_TOTAL_TIME = 0; + +const int64_t BUNDLE_UNINSTALL_INIT_START_TIME = 0; +const int64_t BUNDLE_UNINSTALL_SET_START_TIME = 30; +const int64_t BUNDLE_UNINSTALL_INIT_END_TIME = 0; +const int64_t BUNDLE_UNINSTALL_SET_END_TIME = 130; + +const int64_t BUNDLE_PARSE_INIT_START_TIME = 0; +const int64_t BUNDLE_PARSE_SET_START_TIME = 50; +const int64_t BUNDLE_PARSE_INIT_END_TIME = 0; +const int64_t BUNDLE_PARSE_SET_END_TIME = 250; + +const int64_t AMS_LOAD_INIT_START_TIME = 0; +const int64_t AMS_LOAD_SET_START_TIME = 10; +const int64_t AMS_LOAD_INIT_END_TIME = 0; +const int64_t AMS_LOAD_SET_END_TIME = 90; + +const int64_t ABILITY_LOAD_INIT_START_TIME = 0; +const int64_t ABILITY_LOAD_SET_START_TIME = 50; +const int64_t ABILITY_LOAD_INIT_END_TIME = 0; +const int64_t ABILITY_LOAD_SET_END_TIME = 1000; + +const int64_t APP_FORK_INIT_START_TIME = 0; +const int64_t APP_FORK_SET_START_TIME = 50; +const int64_t APP_FORK_INIT_END_TIME = 0; +const int64_t APP_FORK_SET_END_TIME = 100; + +} // namespace + +class CommonPerfProfileTest : public testing::Test { +public: + CommonPerfProfileTest(); + ~CommonPerfProfileTest(); + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); +}; + +CommonPerfProfileTest::CommonPerfProfileTest() +{} + +CommonPerfProfileTest::~CommonPerfProfileTest() +{} + +void CommonPerfProfileTest::SetUpTestCase() +{} + +void CommonPerfProfileTest::TearDownTestCase() +{} + +void CommonPerfProfileTest::SetUp() +{ + PerfProfile::GetInstance().Reset(); +} + +void CommonPerfProfileTest::TearDown() +{} + +/* + * Feature: CommonPerfProfileTest + * Function: SetBmsLoadTime + * SubFunction: NA + * FunctionPoints: SetBmsLoadTime + * EnvConditions: NA + * CaseDescription: verify bms load time can set correct when set the valid start and end time + */ +HWTEST_F(CommonPerfProfileTest, SetBmsLoadTime_001, TestSize.Level0) +{ + PerfProfile::GetInstance().SetBmsLoadStartTime(BMS_LOAD_SET_START_TIME); + int64_t bmsLoadStartTime = PerfProfile::GetInstance().GetBmsLoadStartTime(); + EXPECT_EQ(bmsLoadStartTime, BMS_LOAD_SET_START_TIME) << "bms load start time " << bmsLoadStartTime; + + PerfProfile::GetInstance().SetBmsLoadEndTime(BMS_LOAD_SET_END_TIME); + PerfProfile::GetInstance().Dump(); + int64_t bmsLoadEndTime = PerfProfile::GetInstance().GetBmsLoadEndTime(); + EXPECT_EQ(bmsLoadEndTime, BMS_LOAD_SET_END_TIME) << "bms load end time " << bmsLoadEndTime; + + // after reset the perf profile, the bms load start and end time should be zero + PerfProfile::GetInstance().Reset(); + int64_t initBmsLoadStartTime = PerfProfile::GetInstance().GetBmsLoadStartTime(); + int64_t initBmsLoadEndTime = PerfProfile::GetInstance().GetBmsLoadEndTime(); + EXPECT_EQ(initBmsLoadStartTime, BMS_LOAD_INIT_START_TIME) << "bms init load start time " << initBmsLoadStartTime; + EXPECT_EQ(initBmsLoadEndTime, BMS_LOAD_INIT_END_TIME) << "bms init load end time " << initBmsLoadEndTime; +} + +/* + * Feature: CommonPerfProfileTest + * Function: SetBmsLoadTime + * SubFunction: NA + * FunctionPoints: SetBmsLoadTime + * EnvConditions: NA + * CaseDescription: verify bms load time can set correct when set invalid start or end time + */ +HWTEST_F(CommonPerfProfileTest, SetBmsLoadTime_002, TestSize.Level0) +{ + int64_t bmsLoadStartTime = 0; + int64_t bmsLoadEndTime = 0; + + PerfProfile::GetInstance().SetBmsLoadStartTime(INVALID_TIME); + bmsLoadStartTime = PerfProfile::GetInstance().GetBmsLoadStartTime(); + EXPECT_EQ(bmsLoadStartTime, BMS_LOAD_INIT_START_TIME) << "bms load start time " << bmsLoadStartTime; + + PerfProfile::GetInstance().SetBmsLoadStartTime(BMS_LOAD_SET_START_TIME); + + // set the invalid end time less than zero + PerfProfile::GetInstance().SetBmsLoadEndTime(INVALID_TIME); + bmsLoadEndTime = PerfProfile::GetInstance().GetBmsLoadEndTime(); + EXPECT_EQ(bmsLoadEndTime, BMS_LOAD_SET_START_TIME) << "bms load end time " << bmsLoadEndTime; + + // set the invalid end time more than zero and less then start time + PerfProfile::GetInstance().SetBmsLoadEndTime(BMS_LOAD_SET_START_TIME - 1); + bmsLoadEndTime = PerfProfile::GetInstance().GetBmsLoadEndTime(); + EXPECT_EQ(bmsLoadEndTime, BMS_LOAD_SET_START_TIME) << "bms load end time " << bmsLoadEndTime; +} + +/* + * Feature: CommonPerfProfileTest + * Function: SetBundleScanTime + * SubFunction: NA + * FunctionPoints: SetBundleScanTime + * EnvConditions: NA + * CaseDescription: verify bundle scan time can set correct when set the valid start and end time + */ +HWTEST_F(CommonPerfProfileTest, SetBundleScanTime_001, TestSize.Level0) +{ + PerfProfile::GetInstance().SetBundleScanStartTime(BUNDLE_SCAN_SET_START_TIME); + int64_t scanStartTime = PerfProfile::GetInstance().GetBundleScanStartTime(); + EXPECT_EQ(scanStartTime, BUNDLE_SCAN_SET_START_TIME) << "bundle scan start time " << scanStartTime; + + PerfProfile::GetInstance().SetBundleScanEndTime(BUNDLE_SCAN_SET_END_TIME); + PerfProfile::GetInstance().Dump(); + int64_t scanEndTime = PerfProfile::GetInstance().GetBundleScanEndTime(); + EXPECT_EQ(scanEndTime, BUNDLE_SCAN_SET_END_TIME) << "bundle scan end time " << scanEndTime; + + // after reset the perf profile, the scan start and end time should be zero + PerfProfile::GetInstance().Reset(); + int64_t initScanStartTime = PerfProfile::GetInstance().GetBundleScanStartTime(); + int64_t initScanEndTime = PerfProfile::GetInstance().GetBundleScanEndTime(); + EXPECT_EQ(initScanStartTime, BUNDLE_SCAN_INIT_START_TIME) << "bundle init scan start time " << initScanStartTime; + EXPECT_EQ(initScanEndTime, BUNDLE_SCAN_INIT_END_TIME) << "bundle init scan end time " << initScanEndTime; +} + +/* + * Feature: CommonPerfProfileTest + * Function: SetBundleScanTime + * SubFunction: NA + * FunctionPoints: SetBundleScanTime + * EnvConditions: NA + * CaseDescription: verify bundle scan time can set correct when set invalid start or end time + */ +HWTEST_F(CommonPerfProfileTest, SetBundleScanTime_002, TestSize.Level0) +{ + int64_t scanStartTime = 0; + int64_t scanEndTime = 0; + + PerfProfile::GetInstance().SetBundleScanStartTime(INVALID_TIME); + scanStartTime = PerfProfile::GetInstance().GetBundleScanStartTime(); + EXPECT_EQ(scanStartTime, BUNDLE_SCAN_INIT_START_TIME) << "bundle scan start time " << scanStartTime; + + PerfProfile::GetInstance().SetBundleScanStartTime(BUNDLE_SCAN_SET_START_TIME); + + // set the invalid end time less than zero + PerfProfile::GetInstance().SetBundleScanEndTime(INVALID_TIME); + scanEndTime = PerfProfile::GetInstance().GetBundleScanEndTime(); + EXPECT_EQ(scanEndTime, BUNDLE_SCAN_SET_START_TIME) << "bundle scan end time " << scanEndTime; + + // set the invalid end time more than zero and less then start time + PerfProfile::GetInstance().SetBundleScanEndTime(BUNDLE_SCAN_SET_START_TIME - 1); + scanEndTime = PerfProfile::GetInstance().GetBundleScanEndTime(); + EXPECT_EQ(scanEndTime, BUNDLE_SCAN_SET_START_TIME) << "bundle scan end time " << scanEndTime; +} + +/* + * Feature: CommonPerfProfileTest + * Function: SetBundleDownloadTime + * SubFunction: NA + * FunctionPoints: SetBundleDownloadTime + * EnvConditions: NA + * CaseDescription: verify bundle download time can set correct when set the valid start and end time + */ +HWTEST_F(CommonPerfProfileTest, SetBundleDownloadTime_001, TestSize.Level0) +{ + PerfProfile::GetInstance().SetBundleDownloadStartTime(BUNDLE_DOWNLOAD_SET_START_TIME); + int64_t downloadStartTime = PerfProfile::GetInstance().GetBundleDownloadStartTime(); + EXPECT_EQ(downloadStartTime, BUNDLE_DOWNLOAD_SET_START_TIME) << "bundle download start time " << downloadStartTime; + + PerfProfile::GetInstance().SetBundleDownloadEndTime(BUNDLE_DOWNLOAD_SET_END_TIME); + PerfProfile::GetInstance().Dump(); + int64_t downloadEndTime = PerfProfile::GetInstance().GetBundleDownloadEndTime(); + EXPECT_EQ(downloadEndTime, BUNDLE_DOWNLOAD_SET_END_TIME) << "bundle download end time " << downloadEndTime; + + // after reset the perf profile, the download start and end time should be zero + PerfProfile::GetInstance().Reset(); + int64_t initDownloadStartTime = PerfProfile::GetInstance().GetBundleDownloadStartTime(); + int64_t initDownloadEndTime = PerfProfile::GetInstance().GetBundleDownloadEndTime(); + EXPECT_EQ(initDownloadStartTime, BUNDLE_DOWNLOAD_INIT_START_TIME) + << "bundle init download start time " << initDownloadStartTime; + EXPECT_EQ(initDownloadEndTime, BUNDLE_DOWNLOAD_INIT_END_TIME) + << "bundle init download end time " << initDownloadEndTime; +} + +/* + * Feature: CommonPerfProfileTest + * Function: SetBundleDownloadTime + * SubFunction: NA + * FunctionPoints: SetBundleDownloadTime + * EnvConditions: NA + * CaseDescription: verify bundle download time can set correct when set invalid start or end time + */ +HWTEST_F(CommonPerfProfileTest, SetBundleDownloadTime_002, TestSize.Level0) +{ + int64_t downloadStartTime = 0; + int64_t downloadEndTime = 0; + + PerfProfile::GetInstance().SetBundleDownloadStartTime(INVALID_TIME); + downloadStartTime = PerfProfile::GetInstance().GetBundleDownloadStartTime(); + EXPECT_EQ(downloadStartTime, BUNDLE_DOWNLOAD_INIT_START_TIME) << "bundle download start time " << downloadStartTime; + + PerfProfile::GetInstance().SetBundleDownloadStartTime(BUNDLE_DOWNLOAD_SET_START_TIME); + + // set the invalid end time less than zero + PerfProfile::GetInstance().SetBundleDownloadEndTime(INVALID_TIME); + downloadEndTime = PerfProfile::GetInstance().GetBundleDownloadEndTime(); + EXPECT_EQ(downloadEndTime, BUNDLE_DOWNLOAD_SET_START_TIME) << "bundle download end time " << downloadEndTime; + + // set the invalid end time more than zero and less then start time + PerfProfile::GetInstance().SetBundleDownloadEndTime(BUNDLE_DOWNLOAD_SET_START_TIME - 1); + downloadEndTime = PerfProfile::GetInstance().GetBundleDownloadEndTime(); + EXPECT_EQ(downloadEndTime, BUNDLE_DOWNLOAD_SET_START_TIME) << "bundle download end time " << downloadEndTime; +} + +/* + * Feature: CommonPerfProfileTest + * Function: SetBundleInstallTime + * SubFunction: NA + * FunctionPoints: SetBundleInstallTime + * EnvConditions: NA + * CaseDescription: verify bundle install time can set correct when set the valid start and end time + */ +HWTEST_F(CommonPerfProfileTest, SetBundleInstallTime_001, TestSize.Level0) +{ + int64_t expectTotalInstallTime = 0; + int64_t realTotalInstallTime = 0; + + PerfProfile::GetInstance().SetBundleInstallStartTime(BUNDLE_INSTALL_SET_START_TIME); + int64_t installStartTime = PerfProfile::GetInstance().GetBundleInstallStartTime(); + EXPECT_EQ(installStartTime, BUNDLE_INSTALL_SET_START_TIME) << "bundle install start time " << installStartTime; + + PerfProfile::GetInstance().SetBundleInstallEndTime(BUNDLE_INSTALL_SET_END_TIME); + PerfProfile::GetInstance().Dump(); + int64_t installEndTime = PerfProfile::GetInstance().GetBundleInstallEndTime(); + EXPECT_EQ(installEndTime, BUNDLE_INSTALL_SET_END_TIME) << "bundle install end time " << installEndTime; + + expectTotalInstallTime = (BUNDLE_INSTALL_SET_END_TIME - BUNDLE_INSTALL_SET_START_TIME); + realTotalInstallTime = PerfProfile::GetInstance().GetBundleTotalInstallTime(); + EXPECT_EQ(realTotalInstallTime, expectTotalInstallTime) << "bundle total install time " << realTotalInstallTime; + + PerfProfile::GetInstance().SetBundleInstallStartTime(BUNDLE_INSTALL_SET_START_TIME_SECOND); + PerfProfile::GetInstance().SetBundleInstallEndTime(BUNDLE_INSTALL_SET_END_TIME_SECOND); + expectTotalInstallTime = (BUNDLE_INSTALL_SET_END_TIME - BUNDLE_INSTALL_SET_START_TIME) + + (BUNDLE_INSTALL_SET_END_TIME_SECOND - BUNDLE_INSTALL_SET_START_TIME_SECOND); + realTotalInstallTime = PerfProfile::GetInstance().GetBundleTotalInstallTime(); + EXPECT_EQ(realTotalInstallTime, expectTotalInstallTime) << "bundle total install time " << realTotalInstallTime; + + // after reset the perf profile, the install start and end time should be zero + PerfProfile::GetInstance().Reset(); + int64_t initInstallStartTime = PerfProfile::GetInstance().GetBundleInstallStartTime(); + int64_t initInstallEndTime = PerfProfile::GetInstance().GetBundleInstallEndTime(); + int64_t initInstallTotalTime = PerfProfile::GetInstance().GetBundleInstallEndTime(); + EXPECT_EQ(initInstallStartTime, BUNDLE_INSTALL_INIT_START_TIME) + << "bundle init install start time " << initInstallStartTime; + EXPECT_EQ(initInstallEndTime, BUNDLE_INSTALL_INIT_END_TIME) + << "bundle init install end time " << initInstallEndTime; + EXPECT_EQ(initInstallTotalTime, BUNDLE_INSTALL_INIT_TOTAL_TIME) + << "bundle init total time " << initInstallTotalTime; +} + +/* + * Feature: CommonPerfProfileTest + * Function: SetBundleInstallTime + * SubFunction: NA + * FunctionPoints: SetBundleInstallTime + * EnvConditions: NA + * CaseDescription: verify bundle install time can set correct when set first invalid start or end time + */ +HWTEST_F(CommonPerfProfileTest, SetBundleInstallTime_002, TestSize.Level0) +{ + int64_t installStartTime = 0; + int64_t installEndTime = 0; + int64_t realTotalInstallTime = 0; + + PerfProfile::GetInstance().SetBundleInstallStartTime(INVALID_TIME); + installStartTime = PerfProfile::GetInstance().GetBundleInstallStartTime(); + EXPECT_EQ(installStartTime, BUNDLE_INSTALL_INIT_START_TIME) << "bundle install start time " << installStartTime; + + // set first install right start time and wrong end time + PerfProfile::GetInstance().SetBundleInstallStartTime(BUNDLE_INSTALL_SET_START_TIME); + PerfProfile::GetInstance().SetBundleInstallEndTime(INVALID_TIME); + installEndTime = PerfProfile::GetInstance().GetBundleInstallEndTime(); + EXPECT_EQ(installEndTime, BUNDLE_INSTALL_SET_START_TIME) << "bundle install end time " << installEndTime; + EXPECT_EQ(realTotalInstallTime, BUNDLE_INSTALL_INIT_TOTAL_TIME) + << "bundle total install time " << realTotalInstallTime; + + PerfProfile::GetInstance().SetBundleInstallEndTime(BUNDLE_INSTALL_SET_START_TIME - 1); + installEndTime = PerfProfile::GetInstance().GetBundleInstallEndTime(); + realTotalInstallTime = PerfProfile::GetInstance().GetBundleTotalInstallTime(); + EXPECT_EQ(installEndTime, BUNDLE_INSTALL_SET_START_TIME) << "bundle install end time " << installEndTime; + EXPECT_EQ(realTotalInstallTime, BUNDLE_INSTALL_INIT_TOTAL_TIME) + << "bundle total install time " << realTotalInstallTime; +} + +/* + * Feature: CommonPerfProfileTest + * Function: SetBundleInstallTime + * SubFunction: NA + * FunctionPoints: SetBundleInstallTime + * EnvConditions: NA + * CaseDescription: verify bundle install time can set correct when set second invalid end time + */ +HWTEST_F(CommonPerfProfileTest, SetBundleInstallTime_003, TestSize.Level0) +{ + // set first install right start and end time + PerfProfile::GetInstance().SetBundleInstallStartTime(BUNDLE_INSTALL_SET_START_TIME); + PerfProfile::GetInstance().SetBundleInstallEndTime(BUNDLE_INSTALL_SET_END_TIME); + + // set second install right start time and wrong end time + int64_t expectTotalInstallTime = 0; + int64_t realTotalInstallTime = 0; + PerfProfile::GetInstance().SetBundleInstallStartTime(BUNDLE_INSTALL_SET_START_TIME_SECOND); + + PerfProfile::GetInstance().SetBundleInstallEndTime(INVALID_TIME); + expectTotalInstallTime = BUNDLE_INSTALL_SET_END_TIME - BUNDLE_INSTALL_SET_START_TIME; + realTotalInstallTime = PerfProfile::GetInstance().GetBundleTotalInstallTime(); + EXPECT_EQ(realTotalInstallTime, expectTotalInstallTime) << "bundle total install time " << realTotalInstallTime; + + PerfProfile::GetInstance().SetBundleInstallEndTime(BUNDLE_INSTALL_SET_START_TIME_SECOND - 1); + expectTotalInstallTime = BUNDLE_INSTALL_SET_END_TIME - BUNDLE_INSTALL_SET_START_TIME; + realTotalInstallTime = PerfProfile::GetInstance().GetBundleTotalInstallTime(); + EXPECT_EQ(realTotalInstallTime, expectTotalInstallTime) << "bundle total install time " << realTotalInstallTime; +} + +/* + * Feature: CommonPerfProfileTest + * Function: SetBundleInstallTime + * SubFunction: NA + * FunctionPoints: SetBundleInstallTime + * EnvConditions: NA + * CaseDescription: verify bundle install time can set correct when set second invalid start time + */ +HWTEST_F(CommonPerfProfileTest, SetBundleInstallTime_004, TestSize.Level0) +{ + // set first install right start and end time + PerfProfile::GetInstance().SetBundleInstallStartTime(BUNDLE_INSTALL_SET_START_TIME); + PerfProfile::GetInstance().SetBundleInstallEndTime(BUNDLE_INSTALL_SET_END_TIME); + + // set second install wrong start time and right end time + PerfProfile::GetInstance().SetBundleInstallStartTime(INVALID_TIME); + PerfProfile::GetInstance().SetBundleInstallEndTime(BUNDLE_INSTALL_SET_END_TIME_SECOND); + int64_t expectTotalInstallTime = + BUNDLE_INSTALL_SET_END_TIME - BUNDLE_INSTALL_SET_START_TIME + BUNDLE_INSTALL_SET_END_TIME_SECOND; + int64_t realTotalInstallTime = PerfProfile::GetInstance().GetBundleTotalInstallTime(); + EXPECT_EQ(realTotalInstallTime, expectTotalInstallTime) << "bundle total install time " << realTotalInstallTime; +} + +/* + * Feature: CommonPerfProfileTest + * Function: SetBundleInstallTime + * SubFunction: NA + * FunctionPoints: SetBundleInstallTime + * EnvConditions: NA + * CaseDescription: verify bundle install time can set correct when set second invalid start and end time + */ +HWTEST_F(CommonPerfProfileTest, SetBundleInstallTime_005, TestSize.Level0) +{ + // set first install right start and end time + PerfProfile::GetInstance().SetBundleInstallStartTime(BUNDLE_INSTALL_SET_START_TIME); + PerfProfile::GetInstance().SetBundleInstallEndTime(BUNDLE_INSTALL_SET_END_TIME); + + // set second install wrong start time and end time + PerfProfile::GetInstance().SetBundleInstallStartTime(INVALID_TIME); + PerfProfile::GetInstance().SetBundleInstallEndTime(INVALID_TIME); + int64_t expectTotalInstallTime = BUNDLE_INSTALL_SET_END_TIME - BUNDLE_INSTALL_SET_START_TIME; + int64_t realTotalInstallTime = PerfProfile::GetInstance().GetBundleTotalInstallTime(); + EXPECT_EQ(realTotalInstallTime, expectTotalInstallTime) << "bundle total install time " << realTotalInstallTime; +} + +/* + * Feature: CommonPerfProfileTest + * Function: SetBundleUninstallTime + * SubFunction: NA + * FunctionPoints: SetBundleUninstallTime + * EnvConditions: NA + * CaseDescription: verify bundle uninstall time can set correct when set the valid start and end time + */ +HWTEST_F(CommonPerfProfileTest, SetBundleUninstallTime_001, TestSize.Level0) +{ + PerfProfile::GetInstance().SetBundleUninstallStartTime(BUNDLE_UNINSTALL_SET_START_TIME); + int64_t uninstallStartTime = PerfProfile::GetInstance().GetBundleUninstallStartTime(); + EXPECT_EQ(uninstallStartTime, BUNDLE_UNINSTALL_SET_START_TIME) + << "bundle uninstall start time " << uninstallStartTime; + + PerfProfile::GetInstance().SetBundleUninstallEndTime(BUNDLE_UNINSTALL_SET_END_TIME); + PerfProfile::GetInstance().Dump(); + int64_t uninstallEndTime = PerfProfile::GetInstance().GetBundleUninstallEndTime(); + EXPECT_EQ(uninstallEndTime, BUNDLE_UNINSTALL_SET_END_TIME) << "bundle uninstall end time " << uninstallEndTime; + + // after reset the perf profile, the parse start and end time should be zero + PerfProfile::GetInstance().Reset(); + int64_t initUninstallStartTime = PerfProfile::GetInstance().GetBundleUninstallStartTime(); + int64_t initUninstallEndTime = PerfProfile::GetInstance().GetBundleUninstallEndTime(); + EXPECT_EQ(initUninstallStartTime, BUNDLE_UNINSTALL_INIT_START_TIME) + << "bundle init uninstall start time " << initUninstallStartTime; + EXPECT_EQ(initUninstallEndTime, BUNDLE_UNINSTALL_INIT_END_TIME) + << "bundle init uninstall end time " << initUninstallEndTime; +} + +/* + * Feature: CommonPerfProfileTest + * Function: SetBundleUninstallTime + * SubFunction: NA + * FunctionPoints: SetBundleUninstallTime + * EnvConditions: NA + * CaseDescription: verify bundle uninstall time can set correct when set the invalid start and end time + */ +HWTEST_F(CommonPerfProfileTest, SetBundleUninstallTime_002, TestSize.Level0) +{ + int64_t uninstallStartTime = 0; + int64_t uninstallEndTime = 0; + + PerfProfile::GetInstance().SetBundleUninstallStartTime(INVALID_TIME); + uninstallStartTime = PerfProfile::GetInstance().GetBundleParseStartTime(); + EXPECT_EQ(uninstallStartTime, BUNDLE_UNINSTALL_INIT_START_TIME) + << "bundle uninstall start time " << uninstallStartTime; + + PerfProfile::GetInstance().SetBundleUninstallStartTime(BUNDLE_UNINSTALL_SET_START_TIME); + + // set the invalid end time less than zero + PerfProfile::GetInstance().SetBundleUninstallEndTime(INVALID_TIME); + uninstallEndTime = PerfProfile::GetInstance().GetBundleUninstallEndTime(); + EXPECT_EQ(uninstallEndTime, BUNDLE_UNINSTALL_SET_START_TIME) << "bundle uninstall end time " << uninstallEndTime; + + // set the invalid end time more than zero and less then start time + PerfProfile::GetInstance().SetBundleParseEndTime(BUNDLE_UNINSTALL_SET_START_TIME - 1); + uninstallEndTime = PerfProfile::GetInstance().GetBundleUninstallEndTime(); + EXPECT_EQ(uninstallEndTime, BUNDLE_UNINSTALL_SET_START_TIME) << "bundle uninstall end time " << uninstallEndTime; +} + +/* + * Feature: CommonPerfProfileTest + * Function: SetBundleParseTime + * SubFunction: NA + * FunctionPoints: SetBundleParseTime + * EnvConditions: NA + * CaseDescription: verify bundle parse time can set correct when set the valid start and end time + */ +HWTEST_F(CommonPerfProfileTest, SetBundleParseTime_001, TestSize.Level0) +{ + PerfProfile::GetInstance().SetBundleParseStartTime(BUNDLE_PARSE_SET_START_TIME); + int64_t parseStartTime = PerfProfile::GetInstance().GetBundleParseStartTime(); + EXPECT_EQ(parseStartTime, BUNDLE_PARSE_SET_START_TIME) << "bundle parse start time " << parseStartTime; + + PerfProfile::GetInstance().SetBundleParseEndTime(BUNDLE_PARSE_SET_END_TIME); + PerfProfile::GetInstance().Dump(); + int64_t parseEndTime = PerfProfile::GetInstance().GetBundleParseEndTime(); + EXPECT_EQ(parseEndTime, BUNDLE_PARSE_SET_END_TIME) << "bundle parse end time " << parseEndTime; + + // after reset the perf profile, the parse start and end time should be zero + PerfProfile::GetInstance().Reset(); + int64_t initParseStartTime = PerfProfile::GetInstance().GetBundleParseStartTime(); + int64_t initParseEndTime = PerfProfile::GetInstance().GetBundleParseEndTime(); + EXPECT_EQ(initParseStartTime, BUNDLE_PARSE_INIT_START_TIME) + << "bundle init parse start time " << initParseStartTime; + EXPECT_EQ(initParseEndTime, BUNDLE_PARSE_INIT_END_TIME) << "bundle init parse end time " << initParseEndTime; +} + +/* + * Feature: CommonPerfProfileTest + * Function: SetBundleParseTime + * SubFunction: NA + * FunctionPoints: SetBundleParseTime + * EnvConditions: NA + * CaseDescription: verify bundle parse time can set correct when set invalid start or end time + */ +HWTEST_F(CommonPerfProfileTest, SetBundleParseTime_002, TestSize.Level0) +{ + int64_t parseStartTime = 0; + int64_t parseEndTime = 0; + + PerfProfile::GetInstance().SetBundleParseStartTime(INVALID_TIME); + parseStartTime = PerfProfile::GetInstance().GetBundleParseStartTime(); + EXPECT_EQ(parseStartTime, BUNDLE_PARSE_INIT_START_TIME) << "bundle parse start time " << parseStartTime; + + PerfProfile::GetInstance().SetBundleParseStartTime(BUNDLE_PARSE_SET_START_TIME); + + // set the invalid end time less than zero + PerfProfile::GetInstance().SetBundleParseEndTime(INVALID_TIME); + parseEndTime = PerfProfile::GetInstance().GetBundleParseEndTime(); + EXPECT_EQ(parseEndTime, BUNDLE_PARSE_SET_START_TIME) << "bundle parse end time " << parseEndTime; + + // set the invalid end time more than zero and less then start time + PerfProfile::GetInstance().SetBundleParseEndTime(BUNDLE_PARSE_SET_START_TIME - 1); + parseEndTime = PerfProfile::GetInstance().GetBundleParseEndTime(); + EXPECT_EQ(parseEndTime, BUNDLE_PARSE_SET_START_TIME) << "bundle parse end time " << parseEndTime; +} + +/* + * Feature: CommonPerfProfileTest + * Function: SetAmsLoadTime + * SubFunction: NA + * FunctionPoints: SetAmsLoadTime + * EnvConditions: NA + * CaseDescription: verify ams load time can set correct when set the valid start and end time + */ +HWTEST_F(CommonPerfProfileTest, SetAmsLoadTime_001, TestSize.Level0) +{ + PerfProfile::GetInstance().SetAmsLoadStartTime(AMS_LOAD_SET_START_TIME); + int64_t amsLoadStartTime = PerfProfile::GetInstance().GetAmsLoadStartTime(); + EXPECT_EQ(amsLoadStartTime, AMS_LOAD_SET_START_TIME) << "ams load start time " << amsLoadStartTime; + + PerfProfile::GetInstance().SetAmsLoadEndTime(AMS_LOAD_SET_END_TIME); + PerfProfile::GetInstance().Dump(); + int64_t amsLoadEndTime = PerfProfile::GetInstance().GetAmsLoadEndTime(); + EXPECT_EQ(amsLoadEndTime, AMS_LOAD_SET_END_TIME) << "ams load end time " << amsLoadEndTime; + + // after reset the perf profile, the ams load start and end time should be zero + PerfProfile::GetInstance().Reset(); + int64_t initAmsLoadStartTime = PerfProfile::GetInstance().GetAmsLoadStartTime(); + int64_t initAmsLoadEndTime = PerfProfile::GetInstance().GetAmsLoadEndTime(); + EXPECT_EQ(initAmsLoadStartTime, AMS_LOAD_INIT_START_TIME) << "ams init load start time " << initAmsLoadStartTime; + EXPECT_EQ(initAmsLoadEndTime, AMS_LOAD_INIT_END_TIME) << "ams init load end time " << initAmsLoadEndTime; +} + +/* + * Feature: CommonPerfProfileTest + * Function: SetAmsLoadTime + * SubFunction: NA + * FunctionPoints: SetAmsLoadTime + * EnvConditions: NA + * CaseDescription: verify ams load time can set correct when set invalid start or end time + */ +HWTEST_F(CommonPerfProfileTest, SetAmsLoadTime_002, TestSize.Level0) +{ + int64_t amsLoadStartTime = 0; + int64_t amsLoadEndTime = 0; + + PerfProfile::GetInstance().SetAmsLoadStartTime(INVALID_TIME); + amsLoadStartTime = PerfProfile::GetInstance().GetAmsLoadStartTime(); + EXPECT_EQ(amsLoadStartTime, AMS_LOAD_INIT_START_TIME) << "ams load start time " << amsLoadStartTime; + + PerfProfile::GetInstance().SetAmsLoadStartTime(AMS_LOAD_SET_START_TIME); + + // set the invalid end time less than zero + PerfProfile::GetInstance().SetAmsLoadEndTime(INVALID_TIME); + amsLoadEndTime = PerfProfile::GetInstance().GetAmsLoadEndTime(); + EXPECT_EQ(amsLoadEndTime, AMS_LOAD_SET_START_TIME) << "ams load end time " << amsLoadEndTime; + + // set the invalid end time more than zero and less then start time + PerfProfile::GetInstance().SetAmsLoadEndTime(AMS_LOAD_SET_START_TIME - 1); + amsLoadEndTime = PerfProfile::GetInstance().GetAmsLoadEndTime(); + EXPECT_EQ(amsLoadEndTime, AMS_LOAD_SET_START_TIME) << "ams load end time " << amsLoadEndTime; +} + +/* + * Feature: CommonPerfProfileTest + * Function: SetAbilityLoadTime + * SubFunction: NA + * FunctionPoints: SetAbilityLoadTime + * EnvConditions: NA + * CaseDescription: verify ability load time can set correct when set the valid start and end time + */ +HWTEST_F(CommonPerfProfileTest, SetAbilityLoadTime_001, TestSize.Level0) +{ + PerfProfile::GetInstance().SetAbilityLoadStartTime(ABILITY_LOAD_SET_START_TIME); + int64_t loadStartTime = PerfProfile::GetInstance().GetAbilityLoadStartTime(); + EXPECT_EQ(loadStartTime, ABILITY_LOAD_SET_START_TIME) << "ability load start time " << loadStartTime; + + PerfProfile::GetInstance().SetAbilityLoadEndTime(ABILITY_LOAD_SET_END_TIME); + PerfProfile::GetInstance().Dump(); + int64_t loadEndTime = PerfProfile::GetInstance().GetAbilityLoadEndTime(); + EXPECT_EQ(loadEndTime, ABILITY_LOAD_SET_END_TIME) << "ability load end time " << loadEndTime; + + // after reset the perf profile, the ability load start and end time should be zero + PerfProfile::GetInstance().Reset(); + int64_t initLoadStartTime = PerfProfile::GetInstance().GetAbilityLoadStartTime(); + int64_t initLoadEndTime = PerfProfile::GetInstance().GetAbilityLoadEndTime(); + EXPECT_EQ(initLoadStartTime, ABILITY_LOAD_INIT_START_TIME) << "ability init load start time " << initLoadStartTime; + EXPECT_EQ(initLoadEndTime, ABILITY_LOAD_INIT_END_TIME) << "ability init load end time " << initLoadEndTime; +} + +/* + * Feature: CommonPerfProfileTest + * Function: SetAbilityLoadTime + * SubFunction: NA + * FunctionPoints: SetAbilityLoadTime + * EnvConditions: NA + * CaseDescription: verify ability load time can set correct when set invalid start or end time + */ +HWTEST_F(CommonPerfProfileTest, SetAbilityLoadTime_002, TestSize.Level0) +{ + int64_t loadStartTime = 0; + int64_t loadEndTime = 0; + + PerfProfile::GetInstance().SetAbilityLoadStartTime(INVALID_TIME); + loadStartTime = PerfProfile::GetInstance().GetAbilityLoadStartTime(); + EXPECT_EQ(loadStartTime, ABILITY_LOAD_INIT_START_TIME) << "ability load start time " << loadStartTime; + + PerfProfile::GetInstance().SetAbilityLoadStartTime(ABILITY_LOAD_SET_START_TIME); + + // set the invalid end time less than zero + PerfProfile::GetInstance().SetAbilityLoadEndTime(INVALID_TIME); + loadEndTime = PerfProfile::GetInstance().GetAbilityLoadEndTime(); + EXPECT_EQ(loadEndTime, ABILITY_LOAD_SET_START_TIME) << "ability load end time " << loadEndTime; + + // set the invalid end time more than zero and less then start time + PerfProfile::GetInstance().SetAmsLoadEndTime(ABILITY_LOAD_SET_START_TIME - 1); + loadEndTime = PerfProfile::GetInstance().GetAbilityLoadEndTime(); + EXPECT_EQ(loadEndTime, ABILITY_LOAD_SET_START_TIME) << "ability load end time " << loadEndTime; +} + +/* + * Feature: CommonPerfProfileTest + * Function: SetAppForkTime + * SubFunction: NA + * FunctionPoints: SetAppForkTime + * EnvConditions: NA + * CaseDescription: verify app fork time can set correct when set the valid start and end time + */ +HWTEST_F(CommonPerfProfileTest, SetAppForkTime_001, TestSize.Level0) +{ + PerfProfile::GetInstance().SetAppForkStartTime(APP_FORK_SET_START_TIME); + int64_t forkStartTime = PerfProfile::GetInstance().GetAppForkStartTime(); + EXPECT_EQ(forkStartTime, APP_FORK_SET_START_TIME) << "app fork start time " << forkStartTime; + + PerfProfile::GetInstance().SetAppForkEndTime(APP_FORK_SET_END_TIME); + PerfProfile::GetInstance().Dump(); + int64_t forkEndTime = PerfProfile::GetInstance().GetAppForkEndTime(); + EXPECT_EQ(forkEndTime, APP_FORK_SET_END_TIME) << "app fork end time " << forkEndTime; + + // after reset the perf profile, the ability load start and end time should be zero + PerfProfile::GetInstance().Reset(); + int64_t initForkStartTime = PerfProfile::GetInstance().GetAppForkStartTime(); + int64_t initForkEndTime = PerfProfile::GetInstance().GetAppForkEndTime(); + EXPECT_EQ(initForkStartTime, APP_FORK_INIT_START_TIME) << "app init fork start time " << initForkStartTime; + EXPECT_EQ(initForkEndTime, APP_FORK_INIT_END_TIME) << "app init fork end time " << initForkEndTime; +} + +/* + * Feature: CommonPerfProfileTest + * Function: SetAppForkTime + * SubFunction: NA + * FunctionPoints: SetAppForkTime + * EnvConditions: NA + * CaseDescription: verify app fork time can set correct when set invalid start or end time + */ +HWTEST_F(CommonPerfProfileTest, SetAppForkTime_002, TestSize.Level0) +{ + int64_t forkStartTime = 0; + int64_t forkEndTime = 0; + + PerfProfile::GetInstance().SetAppForkStartTime(INVALID_TIME); + forkStartTime = PerfProfile::GetInstance().GetAppForkStartTime(); + EXPECT_EQ(forkStartTime, APP_FORK_INIT_START_TIME) << "app fork start time " << forkStartTime; + + PerfProfile::GetInstance().SetAppForkStartTime(APP_FORK_SET_START_TIME); + + // set the invalid end time less than zero + PerfProfile::GetInstance().SetAppForkEndTime(INVALID_TIME); + forkEndTime = PerfProfile::GetInstance().GetAppForkEndTime(); + EXPECT_EQ(forkEndTime, APP_FORK_SET_START_TIME) << "app fork end time " << forkEndTime; + + // set the invalid end time more than zero and less then start time + PerfProfile::GetInstance().SetAppForkEndTime(APP_FORK_SET_START_TIME - 1); + forkEndTime = PerfProfile::GetInstance().GetAppForkEndTime(); + EXPECT_EQ(forkEndTime, ABILITY_LOAD_SET_START_TIME) << "app fork end time " << forkEndTime; +} + +/* + * Feature: CommonPerfProfileTest + * Function: PerfProfileEnable + * SubFunction: NA + * FunctionPoints: PerfProfileEnable + * EnvConditions: NA + * CaseDescription: verify perf profile dump can set enable or disable + */ +HWTEST_F(CommonPerfProfileTest, PerfProfileEnable_001, TestSize.Level0) +{ + bool profileFlag = false; + PerfProfile::GetInstance().SetPerfProfileEnabled(false); + profileFlag = PerfProfile::GetInstance().GetPerfProfileEnabled(); + PerfProfile::GetInstance().Dump(); + ASSERT_FALSE(profileFlag); + + PerfProfile::GetInstance().SetPerfProfileEnabled(true); + profileFlag = PerfProfile::GetInstance().GetPerfProfileEnabled(); + PerfProfile::GetInstance().Dump(); + ASSERT_TRUE(profileFlag); + + // after reset the perf profile, the perf profile flag should be true + PerfProfile::GetInstance().SetPerfProfileEnabled(false); + PerfProfile::GetInstance().Reset(); + profileFlag = PerfProfile::GetInstance().GetPerfProfileEnabled(); + ASSERT_TRUE(profileFlag); +} diff --git a/figures/appexecfwk.png b/figures/appexecfwk.png new file mode 100755 index 0000000000000000000000000000000000000000..e40a548d48af43430fed8599b30c4efcab60fa1d GIT binary patch literal 31029 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 literal 0 HcmV?d00001 diff --git a/interfaces/innerkits/BUILD.gn b/interfaces/innerkits/BUILD.gn new file mode 100644 index 000000000..2e5939328 --- /dev/null +++ b/interfaces/innerkits/BUILD.gn @@ -0,0 +1,24 @@ +# 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") + +group("innerkits_target") { + deps = [ + "appexecfwk_base:appexecfwk_base", + "appexecfwk_core:appexecfwk_core", + "eventhandler_native:eventhandler_native", + "libeventhandler:libeventhandler", + ] +} diff --git a/interfaces/innerkits/appexecfwk_base/BUILD.gn b/interfaces/innerkits/appexecfwk_base/BUILD.gn new file mode 100644 index 000000000..a87405a62 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/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") +import("//build/test.gni") +import("//foundation/appexecfwk/standard/appexecfwk.gni") + +config("appexecfwk_base_sdk_config") { + include_dirs = [ "include" ] +} + +ohos_shared_library("appexecfwk_base") { + include_dirs = [ "//third_party/json/include" ] + + sources = [ + "src/ability_info.cpp", + "src/app_process_info.cpp", + "src/application_info.cpp", + "src/bundle_info.cpp", + "src/element_name.cpp", + "src/hap_module_info.cpp", + "src/install_param.cpp", + "src/module_info.cpp", + "src/permission_def.cpp", + "src/running_process_info.cpp", + ] + + public_configs = [ + ":appexecfwk_base_sdk_config", + "//utils/native/base:utils_config", + ] + + defines = [ + "APP_LOG_TAG = \"AppExecFwkBase\"", + "LOG_DOMAIN = 0xD001100", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${common_path}:libappexecfwk_common", + "//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/appexecfwk_base/appexecfwk_base_header.gni b/interfaces/innerkits/appexecfwk_base/appexecfwk_base_header.gni new file mode 100644 index 000000000..c5cf12d18 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/appexecfwk_base_header.gni @@ -0,0 +1,30 @@ +# 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. + +appexecfwk_base_headers = { + header_files = [ + "ability_info.h", + "appexecfwk_errors.h", + "application_info.h", + "element_name.h", + "bundle_info.h", + "hap_module_info.h", + "install_param.h", + "module_info.h", + "permission_def.h", + "app_process_info.h", + "running_process_info.h", + ] + + header_base = "interfaces/innerkits/appexecfwk_base/include" +} diff --git a/interfaces/innerkits/appexecfwk_base/include/ability_info.h b/interfaces/innerkits/appexecfwk_base/include/ability_info.h new file mode 100644 index 000000000..cb1c043ea --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/include/ability_info.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_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_ABILITY_INFO_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_ABILITY_INFO_H + +#include + +#include "parcel.h" +#include "application_info.h" + +namespace OHOS { +namespace AppExecFwk { + +enum class AbilityType { + UNKNOWN = 0, + PAGE, + SERVICE, + DATA, +}; + +enum class DisplayOrientation { + UNSPECIFIED = 0, + LANDSCAPE, + PORTRAIT, + FOLLOWRECENT, +}; + +enum class LaunchMode { + SINGLETON = 0, + SINGLETOP, + STANDARD, // support more than one instance +}; + +// configuration information about an ability +struct AbilityInfo : public Parcelable { + std::string name; // ability name, only the main class name + std::string label; + std::string description; + std::string iconPath; + bool visible = false; + std::string kind; // ability category + AbilityType type = AbilityType::UNKNOWN; + DisplayOrientation orientation = DisplayOrientation::UNSPECIFIED; + LaunchMode launchMode = LaunchMode::STANDARD; + std::vector permissions; + + std::string process; + std::vector deviceTypes; + std::vector deviceCapabilities; + std::string uri; + ApplicationInfo applicationInfo; + bool isLauncherAbility = false; + bool isNativeAbility = false; + + // set when install + std::string package; // the "module.package" in config.json + std::string bundleName; + std::string moduleName; // the "module.name" in config.json + std::string applicationName; // the "bundlename" in config.json + std::string deviceId; // should auto-get self device id + std::string codePath; // ability main code path with name + std::string resourcePath; // resource path for resource init + std::string libPath; // ability library path without name, libPath->libDir + + bool ReadFromParcel(Parcel &parcel); + virtual bool Marshalling(Parcel &parcel) const override; + static AbilityInfo *Unmarshalling(Parcel &parcel); + void Dump(std::string prefix, int fd); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_ABILITY_INFO_H diff --git a/interfaces/innerkits/appexecfwk_base/include/app_process_info.h b/interfaces/innerkits/appexecfwk_base/include/app_process_info.h new file mode 100644 index 000000000..0fc667229 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/include/app_process_info.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_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_APP_PROCESS_INFO_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_APP_PROCESS_INFO_H + +#include + +#include "parcel.h" + +namespace OHOS { + +namespace AppExecFwk { + +enum class AppProcessState { + APP_STATE_BEGIN = 0, + APP_STATE_CREATE = APP_STATE_BEGIN, + APP_STATE_READY, + APP_STATE_FOREGROUND, + APP_STATE_BACKGROUND, + APP_STATE_SUSPENDED, + APP_STATE_TERMINATED, + APP_STATE_END, +}; + +enum class WeightReasonCode { + REASON_UNKNOWN = 0, + WEIGHT_FOREGROUND = 100, + WEIGHT_FOREGROUND_SERVICE = 125, + WEIGHT_VISIBLE = 200, + WEIGHT_PERCEPTIBLE = 230, + WEIGHT_SERVICE = 300, + WEIGHT_TOP_SLEEPING = 325, + WEIGHT_CANT_SAVE_STATE = 350, + WEIGHT_CACHED = 400, + WEIGHT_GONE = 1000, +}; + +struct AppProcessInfo : public Parcelable { + std::string processName_; + std::int32_t pid_; + std::int32_t uid_; + AppProcessState state_; + + bool ReadFromParcel(Parcel &parcel); + virtual bool Marshalling(Parcel &parcel) const override; + static AppProcessInfo *Unmarshalling(Parcel &parcel); +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_APP_PROCESS_INFO_H \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_base/include/appexecfwk_errors.h b/interfaces/innerkits/appexecfwk_base/include/appexecfwk_errors.h new file mode 100644 index 000000000..81c5d7ed4 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/include/appexecfwk_errors.h @@ -0,0 +1,106 @@ +/* + * 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_APPEXECFWK_ERRORS_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_APPEXECFWK_ERRORS_H + +#include "errors.h" + +namespace OHOS { + +enum { + APPEXECFWK_MODULE_COMMON = 0x00, + APPEXECFWK_MODULE_APPMGR = 0x01, + APPEXECFWK_MODULE_BUNDLEMGR = 0x02, + // Reserved 0x03 ~ 0x0f for new modules, Event related modules start from 0x10 + APPEXECFWK_MODULE_EVENTMGR = 0x10 +}; + +// Error code for Common +constexpr ErrCode APPEXECFWK_COMMON_ERR_OFFSET = ErrCodeOffset(SUBSYS_APPEXECFWK, APPEXECFWK_MODULE_COMMON); +enum { + ERR_APPEXECFWK_SERVICE_NOT_READY = APPEXECFWK_COMMON_ERR_OFFSET + 1, + ERR_APPEXECFWK_SERVICE_NOT_CONNECTED, + ERR_APPEXECFWK_INVALID_UID, + ERR_APPEXECFWK_INVALID_PID, + ERR_APPEXECFWK_PARCEL_ERROR, +}; + +// Error code for AppMgr +constexpr ErrCode APPEXECFWK_APPMGR_ERR_OFFSET = ErrCodeOffset(SUBSYS_APPEXECFWK, APPEXECFWK_MODULE_APPMGR); +enum { + ERR_APPEXECFWK_ASSEMBLE_START_MSG_FAILED = APPEXECFWK_APPMGR_ERR_OFFSET + 1, + ERR_APPEXECFWK_CONNECT_APPSPAWN_FAILED, + ERR_APPEXECFWK_BAD_APPSPAWN_CLIENT, + ERR_APPEXECFWK_BAD_APPSPAWN_SOCKET, + ERR_APPEXECFWK_SOCKET_READ_FAILED, + ERR_APPEXECFWK_SOCKET_WRITE_FAILED +}; + +// Error code for BundleMgr +constexpr ErrCode APPEXECFWK_BUNDLEMGR_ERR_OFFSET = ErrCodeOffset(SUBSYS_APPEXECFWK, APPEXECFWK_MODULE_BUNDLEMGR); +enum { + // the install error code from 0x0001 ~ 0x0020. + ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR = APPEXECFWK_BUNDLEMGR_ERR_OFFSET + 0x0001, + ERR_APPEXECFWK_INSTALL_HOST_INSTALLER_FAILED, + ERR_APPEXECFWK_INSTALL_PARSE_FAILED, + ERR_APPEXECFWK_INSTALL_VERSION_DOWNGRADE, + ERR_APPEXECFWK_INSTALL_VERIFICATION_FAILED, + ERR_APPEXECFWK_INSTALL_NO_SIGNATURE_INFO, + ERR_APPEXECFWK_INSTALL_UPDATE_INCOMPATIBLE, + ERR_APPEXECFWK_INSTALL_PARAM_ERROR, + ERR_APPEXECFWK_INSTALL_PERMISSION_DENIED, + ERR_APPEXECFWK_INSTALL_ENTRY_ALREADY_EXIST, + ERR_APPEXECFWK_INSTALL_STATE_ERROR, + ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID, + ERR_APPEXECFWK_INSTALL_INVALID_HAP_NAME, + ERR_APPEXECFWK_INSTALL_INVALID_BUNDLE_FILE, + ERR_APPEXECFWK_INSTALL_GENERATE_UID_ERROR, + ERR_APPEXECFWK_INSTALL_INSTALLD_SERVICE_ERROR, + ERR_APPEXECFWK_INSTALL_BUNDLE_MGR_SERVICE_ERROR, + ERR_APPEXECFWK_INSTALL_ALREADY_EXIST, + + ERR_APPEXECFWK_PARSE_UNEXPECTED = APPEXECFWK_BUNDLEMGR_ERR_OFFSET + 0x0021, + ERR_APPEXECFWK_PARSE_MISSING_BUNDLE, + ERR_APPEXECFWK_PARSE_MISSING_ABILITY, + ERR_APPEXECFWK_PARSE_NO_PROFILE, + ERR_APPEXECFWK_PARSE_BAD_PROFILE, + ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR, + ERR_APPEXECFWK_PARSE_PROFILE_MISSING_PROP, + ERR_APPEXECFWK_PARSE_PERMISSION_ERROR, + + ERR_APPEXECFWK_INSTALLD_PARAM_ERROR, + ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR, + ERR_APPEXECFWK_INSTALLD_CREATE_DIR_FAILED, + ERR_APPEXECFWK_INSTALLD_CREATE_DIR_EXIST, + ERR_APPEXECFWK_INSTALLD_CHOWN_FAILED, + ERR_APPEXECFWK_INSTALLD_REMOVE_DIR_FAILED, + ERR_APPEXECFWK_INSTALLD_EXTRACT_FILES_FAILED, + ERR_APPEXECFWK_INSTALLD_RNAME_DIR_FAILED, + ERR_APPEXECFWK_INSTALLD_CLEAN_DIR_FAILED, + + ERR_APPEXECFWK_UNINSTALL_SYSTEM_APP_ERROR, + ERR_APPEXECFWK_UNINSTALL_KILLING_APP_ERROR, + ERR_APPEXECFWK_UNINSTALL_INVALID_NAME, + ERR_APPEXECFWK_UNINSTALL_PARAM_ERROR, + ERR_APPEXECFWK_UNINSTALL_PERMISSION_DENIED, + ERR_APPEXECFWK_UNINSTALL_BUNDLE_MGR_SERVICE_ERROR, + ERR_APPEXECFWK_UNINSTALL_MISSING_INSTALLED_BUNDLE, + ERR_APPEXECFWK_UNINSTALL_MISSING_INSTALLED_MODULE +}; + +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_APPEXECFWK_ERRORS_H \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_base/include/application_info.h b/interfaces/innerkits/appexecfwk_base/include/application_info.h new file mode 100644 index 000000000..cd4b39b24 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/include/application_info.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_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_APPLICATION_INFO_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_APPLICATION_INFO_H + +#include +#include + +#include "parcel.h" + +#include "module_info.h" + +namespace OHOS { +namespace AppExecFwk { + +enum class ApplicationFlag { + // get the basic ApplicationInfo + GET_BASIC_APPLICATION_INFO = 0x00000000, + // get the ApplicationInfo with permission specified + GET_APPLICATION_INFO_WITH_PERMS = 0x00000008, +}; + +// configuration information about an application +struct ApplicationInfo : public Parcelable { + std::string name; // application name is same to bundleName + std::string bundleName; + std::string description; + std::string iconPath; + std::string label; // entity.system.home ability label + int32_t labelId = 0; + int32_t iconId = 0; + int32_t descriptionId = 0; + std::string deviceId; // should auto-get self device id. + std::string signatureKey; // the public key info of this application. + bool isSystemApp = false; + bool isLauncherApp = false; + int supportedModes = 0; // returns 0 if the application does not support the driving mode + std::string process; + std::vector permissions; + std::vector moduleSourceDirs; + std::vector moduleInfos; + std::string entryDir; + std::string codePath; + std::string dataDir; + std::string dataBaseDir; + std::string cacheDir; + + bool ReadFromParcel(Parcel &parcel); + virtual bool Marshalling(Parcel &parcel) const override; + static ApplicationInfo *Unmarshalling(Parcel &parcel); + void Dump(std::string prefix, int fd); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_APPLICATION_INFO_H \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_base/include/bundle_constants.h b/interfaces/innerkits/appexecfwk_base/include/bundle_constants.h new file mode 100755 index 000000000..47293472f --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/include/bundle_constants.h @@ -0,0 +1,116 @@ +/* + * 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_BUNDLE_CONSTANTS_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_BUNDLE_CONSTANTS_H + +#include + +namespace OHOS { +namespace AppExecFwk { +namespace Constants { + +const std::string EMPTY_STRING = ""; +const std::string BUNDLE_PROFILE_NAME = "config.json"; +const std::string INSTALL_FILE_SUFFIX = ".hap"; +const std::string PATH_SEPARATOR = "/"; +const std::string FILE_UNDERLINE = "_"; +const std::string ILLEGAL_PATH_FIELD = "../"; +const char DOT_SUFFIX = '.'; +const std::string CURRENT_DEVICE_ID = "PHONE-001"; +const std::string BUNDLE_DATA_BASE_DIR = "/data/bundlemgr"; +const std::string BUNDLE_DATA_BASE_FILE = BUNDLE_DATA_BASE_DIR + "/bmsdb.json"; +const std::string SYSTEM_APP_SCAN_PATH = "/system/app"; +const std::string SYSTEM_APP_INSTALL_PATH = "/data/accounts"; +const std::string THIRD_SYSTEM_APP_SCAN_PATH = "/system/vendor"; +const std::string THIRD_SYSTEM_APP_INSTALL_PATH = "/data/accounts"; +const std::string THIRD_PARTY_APP_INSTALL_PATH = "/data/accounts"; +const std::string EXTRACT_TMP_PATH = "/data/sadata/install_tmp/bundle_haps"; +const std::string HAP_COPY_PATH = "/data/sadata/install_tmp/Tmp_"; +const std::string USER_ACCOUNT_DIR = "account"; +const std::string APP_CODE_DIR = "applications"; +const std::string APP_DATA_DIR = "appdata"; +const std::string DATA_BASE_DIR = "database"; +const std::string DATA_DIR = "files"; +const std::string CACHE_DIR = "cache"; +const std::string SHARED_DIR = "shared"; +const std::string SHARED_PREFERENCE_DIR = "sharedPreference"; +const std::string TMP_SUFFIX = "_tmp"; +const std::string ASSETS_DIR = "assets"; +const std::string RESOURCES_INDEX = "resources.index"; + +const std::string BMS_SERVICE_NAME = "BundleMgrService"; +const std::string INSTALLD_SERVICE_NAME = "installd"; +const std::string SYSTEM_APP = "system"; +const std::string THIRD_PARTY_APP = "third-party"; +constexpr int DEFAULT_USERID = 0; +constexpr int INVALID_USERID = -1; +constexpr int PATH_MAX_SIZE = 256; +constexpr int SIGNATURE_MATCHED = 0; +constexpr int SIGNATURE_NOT_MATCHED = 1; +constexpr int SIGNATURE_UNKNOWN_BUNDLE = 2; +constexpr int PERMISSION_GRANTED = 0; +constexpr int PERMISSION_NOT_GRANTED = -1; +constexpr int DUMP_INDENT = 4; +constexpr unsigned int INSTALLD_UMASK = 0000; + +// uid and gid +constexpr int32_t INVALID_UID = -1; +constexpr int32_t INVALID_GID = -1; +constexpr int32_t ROOT_UID = 0; +constexpr int32_t BMS_UID = 1000; +constexpr int32_t BMS_GID = 1000; +constexpr int32_t BASE_SYS_UID = 2100; +constexpr int32_t MAX_SYS_UID = 2899; +constexpr int32_t BASE_SYS_VEN_UID = 5000; +constexpr int32_t MAX_SYS_VEN_UID = 5999; +constexpr int32_t BASE_APP_UID = 10000; +constexpr int32_t MAX_APP_UID = 65535; +const std::string PROFILE_KEY_UID_SIZE = "size"; +const std::string PROFILE_KEY_UID_AND_GID = "uid_and_gid"; + +// permissions +const std::string PERMISSION_INSTALL_BUNDLE = "ohos.permission.INSTALL_BUNDLE"; + +enum class AppType { + SYSTEM_APP = 0, + THIRD_SYSTEM_APP, + THIRD_PARTY_APP, +}; + +const std::string INTENT_ACTION_HOME = "action.system.home"; +const std::string INTENT_ENTITY_HOME = "entity.system.home"; +const std::string FLAG_HW_HOME_INTENT_FROM_SYSTEM = "flag.home.intent.from.system"; + +// the ability file folder name. +const std::string LIB_FOLDER_NAME = "libs"; +const std::string RES_FOLDER_NAME = "resources"; + +constexpr uint8_t MAX_LABLE_LEN = 30; +constexpr uint8_t MAX_BUNDLE_NAME = 255; +constexpr uint8_t MIN_BUNDLE_NAME = 7; +constexpr uint8_t MAX_VENDOR = 255; +constexpr uint8_t EQUAL_ZERO = 0; +constexpr uint8_t MAX_MODULE_PACKAGE = 127; +constexpr uint8_t MAX_MODULE_NAME = 255; +constexpr uint8_t MAX_MODULE_ABILITIES_READPERMISSION = 255; +constexpr uint8_t MAX_MODULE_ABILITIES_WRITEPERMISSION = 255; +constexpr uint8_t MAX_MODULE_SHORTCUTID = 63; +constexpr uint8_t MAX_MODULE_LABEL = 63; + +} // namespace Constants +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_BUNDLE_CONSTANTS_H \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_base/include/bundle_info.h b/interfaces/innerkits/appexecfwk_base/include/bundle_info.h new file mode 100644 index 000000000..0c2970f1c --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/include/bundle_info.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_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_BUNDLE_INFO_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_BUNDLE_INFO_H + +#include +#include + +#include "parcel.h" + +#include "ability_info.h" +#include "application_info.h" + +namespace OHOS { +namespace AppExecFwk { + +enum class BundleFlag { + // get bundle info except abilityInfos + GET_BUNDLE_DEFAULT = 0x00000000, + // get bundle info include abilityInfos + GET_BUNDLE_WITH_ABILITIES = 0x00000001, +}; + +// configuration information about a bundle +struct BundleInfo : public Parcelable { + std::string name; // bundle name + std::string label; // name display on screen + std::string description; // detail description. When ResourceKit ready replace with descriptionId + std::string vendor; + uint32_t versionCode = 0; + std::string versionName; + std::string jointUserId; + int32_t minSdkVersion = -1; // The min SDK version this app can run on + int32_t maxSdkVersion = -1; // The max SDK version this app can run on + std::string mainEntry; // entry is path of ability main executable file + std::string cpuAbi; + std::string appId; + int compatibleVersion = 0; + int targetVersion = 0; + std::string releaseType; + int uid = -1; + int gid = -1; + std::string seInfo; + std::string entryModuleName; + bool isKeepAlive = false; + bool isNativeApp = false; + int64_t installTime = 0; // the installation time is the number of seconds elapsed since January 1, + // 1970 00:00:00 UTC. The time will be recalculated if the application is reinstalled + // after being uninstalled. + int64_t updateTime = 0; // the update time is the number of seconds elapsed since January 1, + // 1970 00:00:00 UTC. If the application is installed for the first time, the application + // update time is the same as the installation time. + ApplicationInfo applicationInfo; + std::vector abilityInfos; + std::vector reqPermissions; + std::vector defPermissions; // the permissions required for accessing the application. + std::vector hapModuleNames; // the "module.package" in each config.json + std::vector moduleNames; // the "module.name" in each config.json + std::vector modulePublicDirs; // the public paths of all modules of the application. + std::vector moduleDirs; // the paths of all modules of the application. + std::vector moduleResPaths; // the paths of all resources paths. + + bool ReadFromParcel(Parcel &parcel); + virtual bool Marshalling(Parcel &parcel) const override; + static BundleInfo *Unmarshalling(Parcel &parcel); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_BUNDLE_INFO_H diff --git a/interfaces/innerkits/appexecfwk_base/include/element_name.h b/interfaces/innerkits/appexecfwk_base/include/element_name.h new file mode 100644 index 000000000..690e9101d --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/include/element_name.h @@ -0,0 +1,85 @@ +/* + * 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_ELEMENT_NAME_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_ELEMENT_NAME_H + +#include + +#include "parcel.h" + +namespace OHOS { +namespace AppExecFwk { + +class ElementName : public Parcelable { + /* + * How to locate unique Ability: deviceId/bundleName/abilityName + */ +public: + ElementName(const std::string &deviceId, const std::string &bundleName, const std::string &abilityName); + ElementName(); + ~ElementName(); + + std::string GetURI() const; + bool operator==(const ElementName &element) const; + + inline void SetDeviceID(const std::string &id) + { + deviceId_ = id; + } + + inline std::string GetDeviceID() const + { + return deviceId_; + } + + inline void SetBundleName(const std::string &name) + { + bundleName_ = name; + } + + inline std::string GetBundleName() const + { + return bundleName_; + } + + inline void SetAbilityName(const std::string &name) + { + abilityName_ = name; + } + + inline std::string GetAbilityName() const + { + return abilityName_; + } + + bool ReadFromParcel(Parcel &parcel); + virtual bool Marshalling(Parcel &parcel) const override; + static ElementName *Unmarshalling(Parcel &parcel); + + void SetElementDeviceID(ElementName *element, const char *deviceId); + void SetElementBundleName(ElementName *element, const char *bundleName); + void SetElementAbilityName(ElementName *element, const char *abilityName); + void ClearElement(ElementName *element); + +private: + std::string deviceId_; + std::string bundleName_; + std::string abilityName_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_ELEMENT_NAME_H diff --git a/interfaces/innerkits/appexecfwk_base/include/hap_module_info.h b/interfaces/innerkits/appexecfwk_base/include/hap_module_info.h new file mode 100644 index 000000000..a8460ca25 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/include/hap_module_info.h @@ -0,0 +1,48 @@ +/* + * 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_HAP_MODULE_INFO_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_HAP_MODULE_INFO_H + +#include + +#include "parcel.h" +#include "ability_info.h" + +namespace OHOS { +namespace AppExecFwk { + +// configuration information about an module +struct HapModuleInfo : public Parcelable { + std::string name; // module.package in config.json + std::string moduleName; // module.name in config.json + std::string description; + std::string iconPath; + std::string label; + std::string backgroundImg; + int supportedModes = 0; + + std::vector reqCapabilities; + std::vector deviceTypes; + std::vector abilityInfos; + + bool ReadFromParcel(Parcel &parcel); + virtual bool Marshalling(Parcel &parcel) const override; + static HapModuleInfo *Unmarshalling(Parcel &parcel); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_HAP_MODULE_INFO_H diff --git a/interfaces/innerkits/appexecfwk_base/include/install_param.h b/interfaces/innerkits/appexecfwk_base/include/install_param.h new file mode 100644 index 000000000..fdec9375b --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/include/install_param.h @@ -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. + */ + +#ifndef FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_INSTALL_PARAM_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_INSTALL_PARAM_H + +#include + +#include "parcel.h" + +namespace OHOS { +namespace AppExecFwk { + +enum class InstallFlag { + NORMAL = 0, + // 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, +}; + +enum class InstallLocation { + INTERNAL_ONLY = 1, + PREFER_EXTERNAL = 2, +}; + +// provides parameters required for installing or uninstalling an application +struct InstallParam : public Parcelable { + InstallFlag installFlag = InstallFlag::NORMAL; + InstallLocation installLocation = InstallLocation::INTERNAL_ONLY; + int userId = 0; + // is keep user data while uninstall. + bool isKeepData = false; + + // the parcel object function is not const. + bool ReadFromParcel(Parcel &parcel); + virtual bool Marshalling(Parcel &parcel) const override; + static InstallParam *Unmarshalling(Parcel &parcel); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_INSTALL_PARAM_H diff --git a/interfaces/innerkits/appexecfwk_base/include/json_serializer.h b/interfaces/innerkits/appexecfwk_base/include/json_serializer.h new file mode 100644 index 000000000..e1210b3aa --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/include/json_serializer.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_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_JSON_SERIALIZER_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_JSON_SERIALIZER_H + +#include "nlohmann/json.hpp" +#include "bundle_info.h" + +namespace OHOS { +namespace AppExecFwk { + +/* + * form_json and to_json is global static overload method, which need callback by json library, + * and can not rename this function, so don't named according UpperCamelCase style + */ +void to_json(nlohmann::json &jsonObject, const AbilityInfo &abilityInfo); +void from_json(const nlohmann::json &jsonObject, AbilityInfo &abilityInfo); +void to_json(nlohmann::json &jsonObject, const ApplicationInfo &applicationInfo); +void from_json(const nlohmann::json &jsonObject, ApplicationInfo &applicationInfo); +void to_json(nlohmann::json &jsonObject, const BundleInfo &bundleInfo); +void from_json(const nlohmann::json &jsonObject, BundleInfo &bundleInfo); +void to_json(nlohmann::json &jsonObject, const ModuleInfo &moduleInfo); +void from_json(const nlohmann::json &jsonObject, ModuleInfo &moduleInfo); + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_JSON_SERIALIZER_H diff --git a/interfaces/innerkits/appexecfwk_base/include/module_info.h b/interfaces/innerkits/appexecfwk_base/include/module_info.h new file mode 100644 index 000000000..6eb2fc3ba --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/include/module_info.h @@ -0,0 +1,38 @@ +/* + * 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_INFO_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_MODULE_INFO_H + +#include + +#include "parcel.h" + +namespace OHOS { +namespace AppExecFwk { + +// stores module information about an application +struct ModuleInfo : public Parcelable { + std::string moduleName; // the "name" in module part in config.json + std::string moduleSourceDir; + + bool ReadFromParcel(Parcel &parcel); + virtual bool Marshalling(Parcel &parcel) const override; + static ModuleInfo *Unmarshalling(Parcel &parcel); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_MODULE_INFO_H diff --git a/interfaces/innerkits/appexecfwk_base/include/parcel_macro.h b/interfaces/innerkits/appexecfwk_base/include/parcel_macro.h new file mode 100644 index 000000000..31be4b571 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/include/parcel_macro.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 FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_PARCEL_MACRO_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_PARCEL_MACRO_H + +#include "parcel.h" + +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { + +#define READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(type, parcel, data) \ + do { \ + if (!(parcel).Read##type(data)) { \ + APP_LOGE("fail to read %{public}s type from parcel", #type); \ + return false; \ + } \ + } while (0) + +#define WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(type, parcel, data) \ + do { \ + if (!(parcel).Write##type(data)) { \ + APP_LOGE("fail to write %{public}s type into parcel", #type); \ + return false; \ + } \ + } while (0) + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_PARCEL_MACRO_H \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_base/include/permission_def.h b/interfaces/innerkits/appexecfwk_base/include/permission_def.h new file mode 100644 index 000000000..48c8e45a9 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/include/permission_def.h @@ -0,0 +1,43 @@ +/* + * 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_PERMISSION_DEF_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_PERMISSION_DEF_H + +#include + +#include "parcel.h" + +namespace OHOS { +namespace AppExecFwk { +// provides known system security permissions. +struct PermissionDef : public Parcelable { + std::string permissionName; + std::string bundleName; + int grantMode = 0; + int availableScope = 0; + std::string label; + int labelId = 0; + std::string description; + int descriptionId = 0; + + bool ReadFromParcel(Parcel &parcel); + virtual bool Marshalling(Parcel &parcel) const override; + static PermissionDef *Unmarshalling(Parcel &parcel); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_PERMISSION_DEF_H diff --git a/interfaces/innerkits/appexecfwk_base/include/running_process_info.h b/interfaces/innerkits/appexecfwk_base/include/running_process_info.h new file mode 100644 index 000000000..a7d9f92e0 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/include/running_process_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_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_RUNNING_PROCESS_INFO_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_RUNNING_PROCESS_INFO_H + +#include +#include + +#include "parcel.h" +#include "app_process_info.h" + +namespace OHOS { + +namespace AppExecFwk { + +struct RunningProcessInfo : public Parcelable { + std::vector appProcessInfos; + + bool ReadFromParcel(Parcel &parcel); + virtual bool Marshalling(Parcel &parcel) const override; + static RunningProcessInfo *Unmarshalling(Parcel &parcel); +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_RUNNING_PROCESS_INFO_H \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_base/src/ability_info.cpp b/interfaces/innerkits/appexecfwk_base/src/ability_info.cpp new file mode 100644 index 000000000..4b1649737 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/src/ability_info.cpp @@ -0,0 +1,261 @@ +/* + * 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_info.h" + +#include +#include +#include +#include + +#include "nlohmann/json.hpp" +#include "string_ex.h" +#include "app_log_wrapper.h" +#include "parcel_macro.h" +#include "json_serializer.h" +#include "bundle_constants.h" + +namespace OHOS { +namespace AppExecFwk { + +namespace { + +const std::string JSON_KEY_PACKAGE = "package"; +const std::string JSON_KEY_NAME = "name"; +const std::string JSON_KEY_BUNDLE_NAME = "bundleName"; +const std::string JSON_KEY_APPLICATION_NAME = "applicationName"; +const std::string JSON_KEY_LABEL = "label"; +const std::string JSON_KEY_DESCRIPTION = "description"; +const std::string JSON_KEY_ICON_PATH = "iconPath"; +const std::string JSON_KEY_VISIBLE = "visible"; +const std::string JSON_KEY_KIND = "kind"; +const std::string JSON_KEY_TYPE = "type"; +const std::string JSON_KEY_ORIENTATION = "orientation"; +const std::string JSON_KEY_LAUNCH_MODE = "launchMode"; +const std::string JSON_KEY_CODE_PATH = "codePath"; +const std::string JSON_KEY_RESOURCE_PATH = "resourcePath"; +const std::string JSON_KEY_LIB_PATH = "libPath"; +const std::string JSON_KEY_PERMISSIONS = "permissions"; +const std::string JSON_KEY_PROCESS = "process"; +const std::string JSON_KEY_DEVICE_TYPES = "deviceTypes"; +const std::string JSON_KEY_DEVICE_CAPABILITIES = "deviceCapabilities"; +const std::string JSON_KEY_URI = "uri"; +const std::string JSON_KEY_MODULE_NAME = "moduleName"; +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"; + +} // namespace + +bool AbilityInfo::ReadFromParcel(Parcel &parcel) +{ + name = Str16ToStr8(parcel.ReadString16()); + label = Str16ToStr8(parcel.ReadString16()); + description = Str16ToStr8(parcel.ReadString16()); + iconPath = Str16ToStr8(parcel.ReadString16()); + kind = Str16ToStr8(parcel.ReadString16()); + uri = Str16ToStr8(parcel.ReadString16()); + package = Str16ToStr8(parcel.ReadString16()); + bundleName = Str16ToStr8(parcel.ReadString16()); + moduleName = Str16ToStr8(parcel.ReadString16()); + applicationName = Str16ToStr8(parcel.ReadString16()); + process = Str16ToStr8(parcel.ReadString16()); + deviceId = Str16ToStr8(parcel.ReadString16()); + codePath = Str16ToStr8(parcel.ReadString16()); + resourcePath = Str16ToStr8(parcel.ReadString16()); + libPath = Str16ToStr8(parcel.ReadString16()); + visible = parcel.ReadBool(); + isLauncherAbility = parcel.ReadBool(); + isNativeAbility = parcel.ReadBool(); + + int32_t typeData; + READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, typeData); + type = static_cast(typeData); + + int32_t orientationData; + READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, orientationData); + orientation = static_cast(orientationData); + + int32_t launchModeData; + 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); + for (int32_t i = 0; i < permissionsSize; i++) { + permissions.emplace_back(Str16ToStr8(parcel.ReadString16())); + } + + int32_t deviceTypesSize; + READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, deviceTypesSize); + for (int32_t i = 0; i < deviceTypesSize; i++) { + deviceTypes.emplace_back(Str16ToStr8(parcel.ReadString16())); + } + + int32_t deviceCapabilitiesSize; + READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, deviceCapabilitiesSize); + for (int32_t i = 0; i < deviceCapabilitiesSize; i++) { + deviceCapabilities.emplace_back(Str16ToStr8(parcel.ReadString16())); + } + + std::unique_ptr appInfo(parcel.ReadParcelable()); + if (!appInfo) { + APP_LOGE("ReadParcelable failed"); + return false; + } + applicationInfo = *appInfo; + return true; +} + +AbilityInfo *AbilityInfo::Unmarshalling(Parcel &parcel) +{ + AbilityInfo *info = new (std::nothrow) AbilityInfo(); + if (info && !info->ReadFromParcel(parcel)) { + APP_LOGW("read from parcel failed"); + delete info; + info = nullptr; + } + return info; +} + +bool AbilityInfo::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(label)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(description)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(iconPath)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(kind)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(uri)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(package)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(bundleName)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(moduleName)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(applicationName)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(process)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(deviceId)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(codePath)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(resourcePath)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(libPath)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Bool, parcel, visible); + 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(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)); + + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, permissions.size()); + for (auto &permission : permissions) { + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(permission)); + } + + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, deviceTypes.size()); + for (auto &deviceType : deviceTypes) { + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(deviceType)); + } + + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, deviceCapabilities.size()); + for (auto &deviceCapability : deviceCapabilities) { + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(deviceCapability)); + } + + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Parcelable, parcel, &applicationInfo); + return true; +} + +void AbilityInfo::Dump(std::string prefix, int fd) +{ + APP_LOGI("called dump Abilityinfo"); + if (fd < 0) { + APP_LOGE("dump Abilityinfo fd error"); + return; + } + int flags = fcntl(fd, F_GETFL); + if (flags < 0) { + APP_LOGE("dump Abilityinfo fcntl error %{public}s", strerror(errno)); + return; + } + flags &= O_ACCMODE; + if ((flags == O_WRONLY) || (flags == O_RDWR)) { + nlohmann::json jsonObject = *this; + std::string result; + result.append(prefix); + result.append(jsonObject.dump(Constants::DUMP_INDENT)); + int ret = TEMP_FAILURE_RETRY(write(fd, result.c_str(), result.size())); + if (ret < 0) { + APP_LOGE("dump Abilityinfo write error %{public}s", strerror(errno)); + } + } + return; +} + +void to_json(nlohmann::json &jsonObject, const AbilityInfo &abilityInfo) +{ + jsonObject = nlohmann::json{ + {"name", abilityInfo.name}, + {"label", abilityInfo.label}, + {"description", abilityInfo.description}, + {"iconPath", abilityInfo.iconPath}, + {"visible", abilityInfo.visible}, + {"isLauncherAbility", abilityInfo.isLauncherAbility}, + {"isNativeAbility", abilityInfo.isNativeAbility}, + {"kind", abilityInfo.kind}, + {"type", abilityInfo.type}, + {"orientation", abilityInfo.orientation}, + {"launchMode", abilityInfo.launchMode}, + {"permissions", abilityInfo.permissions}, + {"process", abilityInfo.process}, + {"deviceTypes", abilityInfo.deviceTypes}, + {"deviceCapabilities", abilityInfo.deviceCapabilities}, + {"uri", abilityInfo.uri}, + {"package", abilityInfo.package}, + {"bundleName", abilityInfo.bundleName}, + {"moduleName", abilityInfo.moduleName}, + {"applicationName", abilityInfo.applicationName}, + {"deviceId", abilityInfo.deviceId}, + {"codePath", abilityInfo.codePath}, + {"resourcePath", abilityInfo.resourcePath}, + {"libPath", abilityInfo.libPath} + }; +} + +void from_json(const nlohmann::json &jsonObject, AbilityInfo &abilityInfo) +{ + abilityInfo.name = jsonObject.at(JSON_KEY_NAME).get(); + abilityInfo.label = jsonObject.at(JSON_KEY_LABEL).get(); + abilityInfo.description = jsonObject.at(JSON_KEY_DESCRIPTION).get(); + abilityInfo.iconPath = jsonObject.at(JSON_KEY_ICON_PATH).get(); + abilityInfo.visible = jsonObject.at(JSON_KEY_VISIBLE).get(); + abilityInfo.isLauncherAbility = jsonObject.at(JSON_KEY_IS_LAUNCHER_ABILITY).get(); + abilityInfo.isNativeAbility = jsonObject.at(JSON_KEY_IS_NATIVE_ABILITY).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(); + abilityInfo.launchMode = jsonObject.at(JSON_KEY_LAUNCH_MODE).get(); + abilityInfo.permissions = jsonObject.at(JSON_KEY_PERMISSIONS).get>(); + abilityInfo.process = jsonObject.at(JSON_KEY_PROCESS).get(); + abilityInfo.deviceTypes = jsonObject.at(JSON_KEY_DEVICE_TYPES).get>(); + abilityInfo.deviceCapabilities = jsonObject.at(JSON_KEY_DEVICE_CAPABILITIES).get>(); + abilityInfo.uri = jsonObject.at(JSON_KEY_URI).get(); + abilityInfo.package = jsonObject.at(JSON_KEY_PACKAGE).get(); + abilityInfo.bundleName = jsonObject.at(JSON_KEY_BUNDLE_NAME).get(); + abilityInfo.moduleName = jsonObject.at(JSON_KEY_MODULE_NAME).get(); + abilityInfo.applicationName = jsonObject.at(JSON_KEY_APPLICATION_NAME).get(); + abilityInfo.deviceId = jsonObject.at(JSON_KEY_DEVICE_ID).get(); + abilityInfo.codePath = jsonObject.at(JSON_KEY_CODE_PATH).get(); + abilityInfo.resourcePath = jsonObject.at(JSON_KEY_RESOURCE_PATH).get(); + abilityInfo.libPath = jsonObject.at(JSON_KEY_LIB_PATH).get(); +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_base/src/app_process_info.cpp b/interfaces/innerkits/appexecfwk_base/src/app_process_info.cpp new file mode 100644 index 000000000..2d5779840 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/src/app_process_info.cpp @@ -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. + */ + +#include "app_process_info.h" + +#include "nlohmann/json.hpp" +#include "string_ex.h" + +#include "app_log_wrapper.h" +#include "parcel_macro.h" + +namespace OHOS { + +namespace AppExecFwk { + +namespace { + +const std::string JSON_KEY_PROCESSNAME = "processName"; +const std::string JSON_KEY_PID = "pid"; +const std::string JSON_KEY_STATE = "state"; +} // namespace + +bool AppProcessInfo::ReadFromParcel(Parcel &parcel) +{ + processName_ = Str16ToStr8(parcel.ReadString16()); + int32_t typeData; + READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, typeData); + pid_ = static_cast(typeData); + int32_t uidData; + READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, uidData); + uid_ = static_cast(uidData); + int32_t stateData; + READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, stateData); + state_ = static_cast(stateData); + return true; +} + +AppProcessInfo *AppProcessInfo::Unmarshalling(Parcel &parcel) +{ + AppProcessInfo *info = new (std::nothrow) AppProcessInfo(); + if (info && !info->ReadFromParcel(parcel)) { + APP_LOGW("read from parcel failed"); + delete info; + info = nullptr; + } + return info; +} + +bool AppProcessInfo::Marshalling(Parcel &parcel) const +{ + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(processName_)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, static_cast(pid_)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, static_cast(uid_)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, static_cast(state_)); + return true; +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_base/src/application_info.cpp b/interfaces/innerkits/appexecfwk_base/src/application_info.cpp new file mode 100644 index 000000000..238c935f8 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/src/application_info.cpp @@ -0,0 +1,210 @@ +/* + * 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 "application_info.h" + +#include +#include +#include +#include + +#include "nlohmann/json.hpp" +#include "string_ex.h" +#include "app_log_wrapper.h" +#include "bundle_constants.h" +#include "parcel_macro.h" +#include "json_serializer.h" + +namespace OHOS { +namespace AppExecFwk { + +bool ApplicationInfo::ReadFromParcel(Parcel &parcel) +{ + name = Str16ToStr8(parcel.ReadString16()); + bundleName = Str16ToStr8(parcel.ReadString16()); + description = Str16ToStr8(parcel.ReadString16()); + iconPath = Str16ToStr8(parcel.ReadString16()); + label = Str16ToStr8(parcel.ReadString16()); + deviceId = Str16ToStr8(parcel.ReadString16()); + signatureKey = Str16ToStr8(parcel.ReadString16()); + process = Str16ToStr8(parcel.ReadString16()); + entryDir = Str16ToStr8(parcel.ReadString16()); + codePath = Str16ToStr8(parcel.ReadString16()); + dataDir = Str16ToStr8(parcel.ReadString16()); + dataBaseDir = Str16ToStr8(parcel.ReadString16()); + cacheDir = Str16ToStr8(parcel.ReadString16()); + isSystemApp = parcel.ReadBool(); + isLauncherApp = parcel.ReadBool(); + supportedModes = parcel.ReadInt32(); + labelId = parcel.ReadInt32(); + iconId = parcel.ReadInt32(); + descriptionId = parcel.ReadInt32(); + + int32_t permissionsSize; + READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, permissionsSize); + for (int32_t i = 0; i < permissionsSize; i++) { + permissions.emplace_back(Str16ToStr8(parcel.ReadString16())); + } + + int32_t moduleSourceDirsSize; + READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, moduleSourceDirsSize); + for (int32_t i = 0; i < moduleSourceDirsSize; i++) { + moduleSourceDirs.emplace_back(Str16ToStr8(parcel.ReadString16())); + } + + int32_t moduleInfosSize = parcel.ReadInt32(); + for (int32_t i = 0; i < moduleInfosSize; i++) { + std::unique_ptr moduleInfo(parcel.ReadParcelable()); + if (!moduleInfo) { + APP_LOGE("ReadParcelable failed"); + return false; + } + moduleInfos.emplace_back(*moduleInfo); + } + return true; +} + +ApplicationInfo *ApplicationInfo::Unmarshalling(Parcel &parcel) +{ + ApplicationInfo *info = new (std::nothrow) ApplicationInfo(); + if (info && !info->ReadFromParcel(parcel)) { + APP_LOGW("read from parcel failed"); + delete info; + info = nullptr; + } + return info; +} + +bool ApplicationInfo::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(description)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(iconPath)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(label)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(deviceId)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(signatureKey)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(process)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(entryDir)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(codePath)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(dataDir)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(dataBaseDir)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(cacheDir)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Bool, parcel, isSystemApp); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Bool, parcel, isLauncherApp); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, supportedModes); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, labelId); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, iconId); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, descriptionId); + + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, permissions.size()); + for (auto &permission : permissions) { + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(permission)); + } + + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, moduleSourceDirs.size()); + for (auto &moduleSourceDir : moduleSourceDirs) { + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(moduleSourceDir)); + } + + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, moduleInfos.size()); + for (auto &moduleInfo : moduleInfos) { + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Parcelable, parcel, &moduleInfo); + } + return true; +} + +void ApplicationInfo::Dump(std::string prefix, int fd) +{ + APP_LOGI("called dump ApplicationInfo"); + if (fd < 0) { + APP_LOGE("dump ApplicationInfo fd error"); + return; + } + int flags = fcntl(fd, F_GETFL); + if (flags < 0) { + APP_LOGE("dump ApplicationInfo fcntl error %{public}s", strerror(errno)); + return; + } + flags &= O_ACCMODE; + if ((flags == O_WRONLY) || (flags == O_RDWR)) { + nlohmann::json jsonObject = *this; + std::string result; + result.append(prefix); + result.append(jsonObject.dump(Constants::DUMP_INDENT)); + int ret = TEMP_FAILURE_RETRY(write(fd, result.c_str(), result.size())); + if (ret < 0) { + APP_LOGE("dump ApplicationInfo write error %{public}s", strerror(errno)); + } + } + return; +} + +void to_json(nlohmann::json &jsonObject, const ApplicationInfo &applicationInfo) +{ + jsonObject = nlohmann::json{ + {"name", applicationInfo.name}, + {"bundleName", applicationInfo.bundleName}, + {"description", applicationInfo.description}, + {"iconPath", applicationInfo.iconPath}, + {"label", applicationInfo.label}, + {"labelId", applicationInfo.labelId}, + {"descriptionId", applicationInfo.descriptionId}, + {"iconId", applicationInfo.iconId}, + {"deviceId", applicationInfo.deviceId}, + {"signatureKey", applicationInfo.signatureKey}, + {"isSystemApp", applicationInfo.isSystemApp}, + {"isLauncherApp", applicationInfo.isLauncherApp}, + {"supportedModes", applicationInfo.supportedModes}, + {"process", applicationInfo.process}, + {"permissions", applicationInfo.permissions}, + {"moduleSourceDirs", applicationInfo.moduleSourceDirs}, + {"moduleInfos", applicationInfo.moduleInfos}, + {"entryDir", applicationInfo.entryDir}, + {"codePath", applicationInfo.codePath}, + {"dataDir", applicationInfo.dataDir}, + {"dataBaseDir", applicationInfo.dataBaseDir}, + {"cacheDir", applicationInfo.cacheDir} + }; +} + +void from_json(const nlohmann::json &jsonObject, ApplicationInfo &applicationInfo) +{ + applicationInfo.name = jsonObject.at("name").get(); + applicationInfo.bundleName = jsonObject.at("bundleName").get(); + applicationInfo.description = jsonObject.at("description").get(); + applicationInfo.iconPath = jsonObject.at("iconPath").get(); + applicationInfo.label = jsonObject.at("label").get(); + applicationInfo.labelId = jsonObject.at("labelId").get(); + applicationInfo.descriptionId = jsonObject.at("descriptionId").get(); + applicationInfo.iconId = jsonObject.at("iconId").get(); + applicationInfo.deviceId = jsonObject.at("deviceId").get(); + applicationInfo.signatureKey = jsonObject.at("signatureKey").get(); + applicationInfo.isSystemApp = jsonObject.at("isSystemApp").get(); + applicationInfo.isLauncherApp = jsonObject.at("isLauncherApp").get(); + applicationInfo.supportedModes = jsonObject.at("supportedModes").get(); + applicationInfo.process = jsonObject.at("process").get(); + applicationInfo.permissions = jsonObject.at("permissions").get>(); + applicationInfo.moduleSourceDirs = jsonObject.at("moduleSourceDirs").get>(); + applicationInfo.moduleInfos = jsonObject.at("moduleInfos").get>(); + applicationInfo.entryDir = jsonObject.at("entryDir").get(); + applicationInfo.codePath = jsonObject.at("codePath").get(); + applicationInfo.dataDir = jsonObject.at("dataDir").get(); + applicationInfo.dataBaseDir = jsonObject.at("dataBaseDir").get(); + applicationInfo.cacheDir = jsonObject.at("cacheDir").get(); +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_base/src/bundle_info.cpp b/interfaces/innerkits/appexecfwk_base/src/bundle_info.cpp new file mode 100644 index 000000000..b072b75f4 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/src/bundle_info.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 "bundle_info.h" + +#include "string_ex.h" + +#include "app_log_wrapper.h" +#include "json_serializer.h" +#include "parcel_macro.h" + +namespace OHOS { +namespace AppExecFwk { + +bool BundleInfo::ReadFromParcel(Parcel &parcel) +{ + name = Str16ToStr8(parcel.ReadString16()); + label = Str16ToStr8(parcel.ReadString16()); + description = Str16ToStr8(parcel.ReadString16()); + vendor = Str16ToStr8(parcel.ReadString16()); + versionName = Str16ToStr8(parcel.ReadString16()); + mainEntry = Str16ToStr8(parcel.ReadString16()); + cpuAbi = Str16ToStr8(parcel.ReadString16()); + appId = Str16ToStr8(parcel.ReadString16()); + entryModuleName = Str16ToStr8(parcel.ReadString16()); + releaseType = Str16ToStr8(parcel.ReadString16()); + jointUserId = Str16ToStr8(parcel.ReadString16()); + seInfo = Str16ToStr8(parcel.ReadString16()); + versionCode = parcel.ReadUint32(); + minSdkVersion = parcel.ReadInt32(); + maxSdkVersion = parcel.ReadInt32(); + compatibleVersion = parcel.ReadInt32(); + targetVersion = parcel.ReadInt32(); + uid = parcel.ReadInt32(); + gid = parcel.ReadInt32(); + isKeepAlive = parcel.ReadBool(); + isNativeApp = parcel.ReadBool(); + installTime = parcel.ReadInt64(); + updateTime = parcel.ReadInt64(); + + int32_t reqPermissionsSize; + READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, reqPermissionsSize); + for (int32_t i = 0; i < reqPermissionsSize; i++) { + reqPermissions.emplace_back(Str16ToStr8(parcel.ReadString16())); + } + + int32_t defPermissionsSize; + READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, defPermissionsSize); + for (int32_t i = 0; i < defPermissionsSize; i++) { + defPermissions.emplace_back(Str16ToStr8(parcel.ReadString16())); + } + + int32_t hapModuleNamesSize; + READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, hapModuleNamesSize); + for (int32_t i = 0; i < hapModuleNamesSize; i++) { + hapModuleNames.emplace_back(Str16ToStr8(parcel.ReadString16())); + } + + int32_t moduleNamesSize; + READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, moduleNamesSize); + for (int32_t i = 0; i < moduleNamesSize; i++) { + moduleNames.emplace_back(Str16ToStr8(parcel.ReadString16())); + } + + int32_t modulePublicDirsSize; + READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, modulePublicDirsSize); + for (int32_t i = 0; i < modulePublicDirsSize; i++) { + modulePublicDirs.emplace_back(Str16ToStr8(parcel.ReadString16())); + } + + int32_t moduleDirsSize; + READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, moduleDirsSize); + for (int32_t i = 0; i < moduleDirsSize; i++) { + moduleDirs.emplace_back(Str16ToStr8(parcel.ReadString16())); + } + + int32_t moduleResPathsSize; + READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, moduleResPathsSize); + for (int32_t i = 0; i < moduleResPathsSize; i++) { + moduleResPaths.emplace_back(Str16ToStr8(parcel.ReadString16())); + } + + std::unique_ptr appInfo(parcel.ReadParcelable()); + if (!appInfo) { + APP_LOGE("ReadParcelable failed"); + return false; + } + applicationInfo = *appInfo; + + int32_t abilityInfosSize = parcel.ReadInt32(); + for (int32_t i = 0; i < abilityInfosSize; i++) { + std::unique_ptr abilityInfo(parcel.ReadParcelable()); + if (!abilityInfo) { + APP_LOGE("ReadParcelable failed"); + return false; + } + abilityInfos.emplace_back(*abilityInfo); + } + return true; +} + +bool BundleInfo::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(label)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(description)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(vendor)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(versionName)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(mainEntry)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(cpuAbi)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(appId)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(entryModuleName)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(releaseType)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(jointUserId)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(seInfo)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Uint32, parcel, versionCode); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, minSdkVersion); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, maxSdkVersion); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, compatibleVersion); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, targetVersion); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, uid); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, gid); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Bool, parcel, isKeepAlive); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Bool, parcel, isNativeApp); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int64, parcel, installTime); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int64, parcel, updateTime); + + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, reqPermissions.size()); + for (auto &reqPermission : reqPermissions) { + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(reqPermission)); + } + + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, defPermissions.size()); + for (auto &defPermission : defPermissions) { + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(defPermission)); + } + + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, hapModuleNames.size()); + for (auto &hapModuleName : hapModuleNames) { + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(hapModuleName)); + } + + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, moduleNames.size()); + for (auto &moduleName : moduleNames) { + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(moduleName)); + } + + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, modulePublicDirs.size()); + for (auto &modulePublicDir : modulePublicDirs) { + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(modulePublicDir)); + } + + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, moduleDirs.size()); + for (auto &moduleDir : moduleDirs) { + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(moduleDir)); + } + + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, moduleResPaths.size()); + for (auto &moduleResPath : moduleResPaths) { + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(moduleResPath)); + } + + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Parcelable, parcel, &applicationInfo); + + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, abilityInfos.size()); + for (auto &abilityInfo : abilityInfos) { + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Parcelable, parcel, &abilityInfo); + } + return true; +} + +BundleInfo *BundleInfo::Unmarshalling(Parcel &parcel) +{ + BundleInfo *info = new (std::nothrow) BundleInfo(); + if (info && !info->ReadFromParcel(parcel)) { + APP_LOGW("read from parcel failed"); + delete info; + info = nullptr; + } + return info; +} + +void to_json(nlohmann::json &jsonObject, const BundleInfo &bundleInfo) +{ + jsonObject = nlohmann::json{ + {"name", bundleInfo.name}, + {"label", bundleInfo.label}, + {"description", bundleInfo.description}, + {"vendor", bundleInfo.vendor}, + {"isKeepAlive", bundleInfo.isKeepAlive}, + {"isNativeApp", bundleInfo.isNativeApp}, + {"applicationInfo", bundleInfo.applicationInfo}, + {"abilityInfos", bundleInfo.abilityInfos}, + {"jointUserId", bundleInfo.jointUserId}, + {"versionCode", bundleInfo.versionCode}, + {"versionName", bundleInfo.versionName}, + {"minSdkVersion", bundleInfo.minSdkVersion}, + {"maxSdkVersion", bundleInfo.maxSdkVersion}, + {"mainEntry", bundleInfo.mainEntry}, + {"cpuAbi", bundleInfo.cpuAbi}, + {"appId", bundleInfo.appId}, + {"compatibleVersion", bundleInfo.compatibleVersion}, + {"targetVersion", bundleInfo.targetVersion}, + {"releaseType", bundleInfo.releaseType}, + {"uid", bundleInfo.uid}, + {"gid", bundleInfo.gid}, + {"seInfo", bundleInfo.seInfo}, + {"installTime", bundleInfo.installTime}, + {"updateTime", bundleInfo.updateTime}, + {"entryModuleName", bundleInfo.entryModuleName}, + {"reqPermissions", bundleInfo.reqPermissions}, + {"defPermissions", bundleInfo.defPermissions}, + {"hapModuleNames", bundleInfo.hapModuleNames}, + {"moduleNames", bundleInfo.moduleNames}, + {"modulePublicDirs", bundleInfo.modulePublicDirs}, + {"moduleDirs", bundleInfo.moduleDirs}, + {"moduleResPaths", bundleInfo.moduleResPaths} + }; +} + +void from_json(const nlohmann::json &jsonObject, BundleInfo &bundleInfo) +{ + bundleInfo.name = jsonObject.at("name").get(); + bundleInfo.label = jsonObject.at("label").get(); + bundleInfo.description = jsonObject.at("description").get(); + bundleInfo.vendor = jsonObject.at("vendor").get(); + bundleInfo.isKeepAlive = jsonObject.at("isKeepAlive").get(); + bundleInfo.isNativeApp = jsonObject.at("isNativeApp").get(); + bundleInfo.applicationInfo = jsonObject.at("applicationInfo").get(); + bundleInfo.abilityInfos = jsonObject.at("abilityInfos").get>(); + bundleInfo.versionCode = jsonObject.at("versionCode").get(); + bundleInfo.versionName = jsonObject.at("versionName").get(); + bundleInfo.jointUserId = jsonObject.at("jointUserId").get(); + bundleInfo.minSdkVersion = jsonObject.at("minSdkVersion").get(); + bundleInfo.maxSdkVersion = jsonObject.at("maxSdkVersion").get(); + bundleInfo.mainEntry = jsonObject.at("mainEntry").get(); + bundleInfo.cpuAbi = jsonObject.at("cpuAbi").get(); + bundleInfo.appId = jsonObject.at("appId").get(); + bundleInfo.compatibleVersion = jsonObject.at("compatibleVersion").get(); + bundleInfo.targetVersion = jsonObject.at("targetVersion").get(); + bundleInfo.releaseType = jsonObject.at("releaseType").get(); + bundleInfo.uid = jsonObject.at("uid").get(); + bundleInfo.gid = jsonObject.at("gid").get(); + bundleInfo.seInfo = jsonObject.at("seInfo").get(); + bundleInfo.installTime = jsonObject.at("installTime").get(); + bundleInfo.updateTime = jsonObject.at("updateTime").get(); + bundleInfo.entryModuleName = jsonObject.at("entryModuleName").get(); + bundleInfo.reqPermissions = jsonObject.at("reqPermissions").get>(); + bundleInfo.defPermissions = jsonObject.at("defPermissions").get>(); + bundleInfo.hapModuleNames = jsonObject.at("hapModuleNames").get>(); + bundleInfo.moduleNames = jsonObject.at("moduleNames").get>(); + bundleInfo.modulePublicDirs = jsonObject.at("modulePublicDirs").get>(); + bundleInfo.moduleDirs = jsonObject.at("moduleDirs").get>(); + bundleInfo.moduleResPaths = jsonObject.at("moduleResPaths").get>(); +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_base/src/element_name.cpp b/interfaces/innerkits/appexecfwk_base/src/element_name.cpp new file mode 100644 index 000000000..09f6f7fc2 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/src/element_name.cpp @@ -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. + */ + +#include "element_name.h" + +#include "string_ex.h" + +#include "app_log_wrapper.h" +#include "parcel_macro.h" + +namespace OHOS { +namespace AppExecFwk { + +void ElementName::SetElementDeviceID(ElementName *element, const char *deviceId) +{ + if (element == nullptr) { + return; + } + element->SetDeviceID(deviceId); +} + +void ElementName::SetElementBundleName(ElementName *element, const char *bundleName) +{ + if (element == nullptr) { + return; + } + element->SetBundleName(bundleName); +} + +void ElementName::SetElementAbilityName(ElementName *element, const char *abilityName) +{ + if (element == nullptr) { + return; + } + element->SetAbilityName(abilityName); +} + +void ElementName::ClearElement(ElementName *element) +{ + if (element == nullptr) { + return; + } + element->SetDeviceID(""); + element->SetBundleName(""); + element->SetAbilityName(""); +} + +ElementName::ElementName(const std::string &deviceId, const std::string &bundleName, const std::string &abilityName) + : deviceId_(deviceId), bundleName_(bundleName), abilityName_(abilityName) +{ + APP_LOGD("instance is created with parameters"); +} + +ElementName::ElementName() +{ + APP_LOGD("instance is created without parameter"); +} + +ElementName::~ElementName() +{ + APP_LOGD("instance is destroyed"); +} + +std::string ElementName::GetURI() const +{ + return deviceId_ + "/" + bundleName_ + "/" + abilityName_; +} + +bool ElementName::operator==(const ElementName &element) const +{ + return (deviceId_ == element.GetDeviceID() && bundleName_ == element.GetBundleName() && + abilityName_ == element.GetAbilityName()); +} + +bool ElementName::ReadFromParcel(Parcel &parcel) +{ + bundleName_ = Str16ToStr8(parcel.ReadString16()); + abilityName_ = Str16ToStr8(parcel.ReadString16()); + deviceId_ = Str16ToStr8(parcel.ReadString16()); + return true; +} + +ElementName *ElementName::Unmarshalling(Parcel &parcel) +{ + ElementName *elementName = new (std::nothrow) ElementName(); + if (elementName && !elementName->ReadFromParcel(parcel)) { + APP_LOGW("read from parcel failed"); + delete elementName; + elementName = nullptr; + } + return elementName; +} + +bool ElementName::Marshalling(Parcel &parcel) const +{ + 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(String16, parcel, Str8ToStr16(deviceId_)); + return true; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_base/src/hap_module_info.cpp b/interfaces/innerkits/appexecfwk_base/src/hap_module_info.cpp new file mode 100644 index 000000000..b7fdea8c9 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/src/hap_module_info.cpp @@ -0,0 +1,97 @@ +/* + * 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 "hap_module_info.h" + +#include "nlohmann/json.hpp" +#include "string_ex.h" + +#include "app_log_wrapper.h" +#include "parcel_macro.h" + +namespace OHOS { +namespace AppExecFwk { + +bool HapModuleInfo::ReadFromParcel(Parcel &parcel) +{ + name = Str16ToStr8(parcel.ReadString16()); + moduleName = Str16ToStr8(parcel.ReadString16()); + description = Str16ToStr8(parcel.ReadString16()); + iconPath = Str16ToStr8(parcel.ReadString16()); + label = Str16ToStr8(parcel.ReadString16()); + backgroundImg = Str16ToStr8(parcel.ReadString16()); + supportedModes = parcel.ReadInt32(); + + int32_t reqCapabilitiesSize; + READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, reqCapabilitiesSize); + for (int32_t i = 0; i < reqCapabilitiesSize; i++) { + reqCapabilities.emplace_back(Str16ToStr8(parcel.ReadString16())); + } + + int32_t deviceTypesSize; + READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, deviceTypesSize); + for (int32_t i = 0; i < deviceTypesSize; i++) { + deviceTypes.emplace_back(Str16ToStr8(parcel.ReadString16())); + } + + int32_t abilityInfosSize = parcel.ReadInt32(); + for (int32_t i = 0; i < abilityInfosSize; i++) { + std::unique_ptr abilityInfo(parcel.ReadParcelable()); + if (!abilityInfo) { + APP_LOGE("ReadParcelable failed"); + return false; + } + abilityInfos.emplace_back(*abilityInfo); + } + return true; +} + +HapModuleInfo *HapModuleInfo::Unmarshalling(Parcel &parcel) +{ + HapModuleInfo *info = new (std::nothrow) HapModuleInfo(); + if (info && !info->ReadFromParcel(parcel)) { + APP_LOGW("read from parcel failed"); + delete info; + info = nullptr; + } + return info; +} + +bool HapModuleInfo::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(moduleName)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(description)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(iconPath)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(label)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(backgroundImg)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, supportedModes); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, reqCapabilities.size()); + for (auto &reqCapability : reqCapabilities) { + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(reqCapability)); + } + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, deviceTypes.size()); + for (auto &deviceType : deviceTypes) { + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(deviceType)); + } + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, abilityInfos.size()); + for (auto &abilityInfo : abilityInfos) { + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Parcelable, parcel, &abilityInfo); + } + return true; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_base/src/install_param.cpp b/interfaces/innerkits/appexecfwk_base/src/install_param.cpp new file mode 100644 index 000000000..378233ae3 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/src/install_param.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 "install_param.h" + +#include "nlohmann/json.hpp" +#include "string_ex.h" + +#include "app_log_wrapper.h" +#include "parcel_macro.h" + +namespace OHOS { +namespace AppExecFwk { + +bool InstallParam::ReadFromParcel(Parcel &parcel) +{ + int32_t flagData; + READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, flagData); + installFlag = static_cast(flagData); + + int32_t locationData; + READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, locationData); + installLocation = static_cast(locationData); + + userId = parcel.ReadInt32(); + isKeepData = parcel.ReadBool(); + return true; +} + +InstallParam *InstallParam::Unmarshalling(Parcel &parcel) +{ + InstallParam *info = new (std::nothrow) InstallParam(); + if (info && !info->ReadFromParcel(parcel)) { + APP_LOGW("read from parcel failed"); + delete info; + info = nullptr; + } + return info; +} + +bool InstallParam::Marshalling(Parcel &parcel) const +{ + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, static_cast(installFlag)); + 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); + return true; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_base/src/module_info.cpp b/interfaces/innerkits/appexecfwk_base/src/module_info.cpp new file mode 100644 index 000000000..9c7e51b03 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/src/module_info.cpp @@ -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. + */ + +#include "module_info.h" + +#include "nlohmann/json.hpp" +#include "string_ex.h" + +#include "app_log_wrapper.h" +#include "parcel_macro.h" + +namespace OHOS { +namespace AppExecFwk { + +bool ModuleInfo::ReadFromParcel(Parcel &parcel) +{ + moduleName = Str16ToStr8(parcel.ReadString16()); + moduleSourceDir = Str16ToStr8(parcel.ReadString16()); + return true; +} + +ModuleInfo *ModuleInfo::Unmarshalling(Parcel &parcel) +{ + ModuleInfo *info = new (std::nothrow) ModuleInfo(); + if (info && !info->ReadFromParcel(parcel)) { + APP_LOGW("read from parcel failed"); + delete info; + info = nullptr; + } + return info; +} + +bool ModuleInfo::Marshalling(Parcel &parcel) const +{ + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(moduleName)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(moduleSourceDir)); + return true; +} + +void to_json(nlohmann::json &jsonObject, const ModuleInfo &moduleInfo) +{ + jsonObject = nlohmann::json{ + {"moduleName", moduleInfo.moduleName}, + {"moduleSourceDir", moduleInfo.moduleSourceDir} + }; +} + +void from_json(const nlohmann::json &jsonObject, ModuleInfo &moduleInfo) +{ + moduleInfo.moduleName = jsonObject.at("moduleName").get(); + moduleInfo.moduleSourceDir = jsonObject.at("moduleSourceDir").get(); +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_base/src/permission_def.cpp b/interfaces/innerkits/appexecfwk_base/src/permission_def.cpp new file mode 100644 index 000000000..28baa352b --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/src/permission_def.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 "permission_def.h" + +#include "nlohmann/json.hpp" +#include "string_ex.h" + +#include "app_log_wrapper.h" +#include "parcel_macro.h" + +namespace OHOS { +namespace AppExecFwk { + +bool PermissionDef::ReadFromParcel(Parcel &parcel) +{ + permissionName = Str16ToStr8(parcel.ReadString16()); + bundleName = Str16ToStr8(parcel.ReadString16()); + label = Str16ToStr8(parcel.ReadString16()); + description = Str16ToStr8(parcel.ReadString16()); + READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, availableScope); + READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, grantMode); + READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, labelId); + READ_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, descriptionId); + return true; +} + +PermissionDef *PermissionDef::Unmarshalling(Parcel &parcel) +{ + PermissionDef *info = new (std::nothrow) PermissionDef(); + if (info && !info->ReadFromParcel(parcel)) { + APP_LOGW("read from parcel failed"); + delete info; + info = nullptr; + } + return info; +} + +bool PermissionDef::Marshalling(Parcel &parcel) const +{ + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(permissionName)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(bundleName)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(label)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(String16, parcel, Str8ToStr16(description)); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, availableScope); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, grantMode); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, labelId); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, parcel, descriptionId); + return true; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_base/src/running_process_info.cpp b/interfaces/innerkits/appexecfwk_base/src/running_process_info.cpp new file mode 100644 index 000000000..8fdf2269a --- /dev/null +++ b/interfaces/innerkits/appexecfwk_base/src/running_process_info.cpp @@ -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. + */ + +#include "running_process_info.h" + +#include "nlohmann/json.hpp" +#include "string_ex.h" + +#include "app_log_wrapper.h" +#include "parcel_macro.h" + +namespace OHOS { +namespace AppExecFwk { + +bool RunningProcessInfo::ReadFromParcel(Parcel &parcel) +{ + int32_t processInfoSize = parcel.ReadInt32(); + for (int32_t i = 0; i < processInfoSize; i++) { + std::unique_ptr appProcessInfo(parcel.ReadParcelable()); + if (!appProcessInfo) { + APP_LOGE("ReadParcelable failed"); + return false; + } + appProcessInfos.emplace_back(*appProcessInfo); + } + return true; +} + +bool RunningProcessInfo::Marshalling(Parcel &parcel) const +{ + size_t appProcessInfoSize = appProcessInfos.size(); + if (!parcel.WriteInt32(appProcessInfoSize)) { + return false; + } + for (size_t i = 0; i < appProcessInfoSize; i++) { + if (!parcel.WriteParcelable(&appProcessInfos[i])) { + return false; + } + } + return true; +} + +RunningProcessInfo *RunningProcessInfo::Unmarshalling(Parcel &parcel) +{ + RunningProcessInfo *info = new (std::nothrow) RunningProcessInfo(); + if (info && !info->ReadFromParcel(parcel)) { + APP_LOGW("read from parcel failed"); + delete info; + info = nullptr; + } + return info; +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_core/BUILD.gn b/interfaces/innerkits/appexecfwk_core/BUILD.gn new file mode 100644 index 000000000..e74d6278e --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/BUILD.gn @@ -0,0 +1,100 @@ +# 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("appmgr_sdk_config") { + include_dirs = [ + "include/appmgr", + "//foundation/aafwk/standard/frameworks/kits/ability/native/include", + ] +} + +config("bundlemgr_sdk_config") { + include_dirs = [ "include/bundlemgr" ] +} + +config("appexecfwk_core_config") { + include_dirs = [ "include" ] +} + +ohos_shared_library("appexecfwk_core") { + include_dirs = [ + "//third_party/json/include", + "${services_path}/appmgr/include", + "${services_path}/bundlemgr/include", + "//utils/system/safwk/native/include", + ] + + sources = [ + "src/appmgr/ams_mgr_proxy.cpp", + "src/appmgr/ams_mgr_stub.cpp", + "src/appmgr/app_launch_data.cpp", + "src/appmgr/app_mgr_client.cpp", + "src/appmgr/app_mgr_proxy.cpp", + "src/appmgr/app_mgr_stub.cpp", + "src/appmgr/app_process_data.cpp", + "src/appmgr/app_record_id.cpp", + "src/appmgr/app_scheduler_host.cpp", + "src/appmgr/app_scheduler_proxy.cpp", + "src/appmgr/app_service_manager.cpp", + "src/appmgr/app_state_callback_host.cpp", + "src/appmgr/app_state_callback_proxy.cpp", + "src/appmgr/app_task_info.cpp", + "src/appmgr/dummy_configuration.cpp", + "src/appmgr/priority_object.cpp", + "src/appmgr/process_info.cpp", + "src/appmgr/profile.cpp", + "src/bundlemgr/bundle_installer_proxy.cpp", + "src/bundlemgr/bundle_mgr_host.cpp", + "src/bundlemgr/bundle_mgr_proxy.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/status_receiver_host.cpp", + "src/bundlemgr/status_receiver_proxy.cpp", + ] + + public_configs = [ + ":appexecfwk_core_config", + ":appmgr_sdk_config", + ":bundlemgr_sdk_config", + ] + + defines = [ + "APP_LOG_TAG = \"AppexecfwkCore\"", + "LOG_DOMAIN = 0xD001100", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${common_path}:libappexecfwk_common", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "//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/appexecfwk_core/appexecfwk_headers.gni b/interfaces/innerkits/appexecfwk_core/appexecfwk_headers.gni new file mode 100644 index 000000000..e8a5c3446 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/appexecfwk_headers.gni @@ -0,0 +1,29 @@ +# 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. + +appexecfwk_headers = { + 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", + ] + + header_base = "interfaces/innerkits/appexecfwk_core/include" +} diff --git a/interfaces/innerkits/appexecfwk_core/include/appmgr/ams_mgr_interface.h b/interfaces/innerkits/appexecfwk_core/include/appmgr/ams_mgr_interface.h new file mode 100644 index 000000000..2fb384723 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/appmgr/ams_mgr_interface.h @@ -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. + */ + +#ifndef FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_AMS_MGR_INTERFACE_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_AMS_MGR_INTERFACE_H + +#include "iremote_broker.h" +#include "iremote_object.h" + +#include "ability_info.h" +#include "application_info.h" +#include "app_record_id.h" +#include "iapp_state_callback.h" + +namespace OHOS { +namespace AppExecFwk { + +class IAmsMgr : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.appexecfwk.IAmsMgr"); + + /** + * LoadAbility, call LoadAbility() through proxy project, load the ability that needed to be started. + * + * @param token, the unique identification to start the ability. + * @param preToken, the unique identification to call the ability. + * @param abilityInfo, the ability information. + * @param appInfo, the app information. + * @return + */ + virtual void LoadAbility(const sptr &token, const sptr &preToken, + const std::shared_ptr &abilityInfo, const std::shared_ptr &appInfo) = 0; + + /** + * TerminateAbility, call TerminateAbility() through the proxy object, terminate the token ability. + * + * @param token, token, he unique identification to terminate the ability. + * @return + */ + virtual void TerminateAbility(const sptr &token) = 0; + + /** + * UpdateAbilityState, call UpdateAbilityState() through the proxy object, update the ability status. + * + * @param token, the unique identification to update the ability. + * @param state, ability status that needs to be updated. + * @return + */ + virtual void UpdateAbilityState(const sptr &token, const AbilityState state) = 0; + + /** + * RegisterAppStateCallback, call RegisterAppStateCallback() through the proxy object, register the callback. + * + * @param callback, Ams register the callback. + * @return + */ + virtual void RegisterAppStateCallback(const sptr &callback) = 0; + + /** + * Reset,call Reset() through the proxy object, reset DFX of AppMgr. + * + * @return + */ + virtual void Reset() = 0; + + /** + * AbilityBehaviorAnalysis,call AbilityBehaviorAnalysis() through the proxy object, + * ability behavior analysis assistant process optimization. + * + * @param token, the unique identification to start the ability. + * @param preToken, the unique identification to call the ability. + * @param visibility, the visibility information about windows info. + * @param perceptibility, the Perceptibility information about windows info. + * @param connectionState, the service ability connection state. + * @return + */ + virtual void AbilityBehaviorAnalysis(const sptr &token, const sptr &preToken, + const int32_t visibility, const int32_t perceptibility, const int32_t connectionState) = 0; + + /** + * KillProcessByAbilityToken, call KillProcessByAbilityToken() through proxy object, + * kill the process by ability token. + * + * @param token, the unique identification to the ability. + * @return + */ + virtual void KillProcessByAbilityToken(const sptr &token) = 0; + + /** + * KillApplication, call KillApplication() through proxy object, kill the application. + * + * @param bundleName, bundle name in Application record. + * @return ERR_OK, return back success, others fail. + */ + virtual int KillApplication(const std::string &bundleName) = 0; + + enum class Message { + AMS_LOAD_ABILITY = 0, + AMS_TERMINATE_ABILITY, + AMS_UPDATE_ABILITY_STATE, + AMS_REGISTER_APP_STATE_CALLBACK, + AMS_RESET, + AMS_ABILITY_BEHAVIOR_ANALYSIS, + AMS_KILL_PEOCESS_BY_ABILITY_TOKEN, + AMS_KILL_APPLICATION, + }; +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_AMS_MGR_INTERFACE_H diff --git a/interfaces/innerkits/appexecfwk_core/include/appmgr/ams_mgr_proxy.h b/interfaces/innerkits/appexecfwk_core/include/appmgr/ams_mgr_proxy.h new file mode 100644 index 000000000..3a9f4f12d --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/appmgr/ams_mgr_proxy.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_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_AMS_MGR_CLIENT_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_AMS_MGR_CLIENT_H + +#include "iremote_proxy.h" + +#include "ams_mgr_interface.h" + +namespace OHOS { +namespace AppExecFwk { + +class AmsMgrProxy : public IRemoteProxy { +public: + explicit AmsMgrProxy(const sptr &impl); + virtual ~AmsMgrProxy() = default; + + /** + * LoadAbility, call LoadAbility() through proxy project, load the ability that needed to be started. + * + * @param token, the unique identification to start the ability. + * @param preToken, the unique identification to call the ability. + * @param abilityInfo, the ability information. + * @param appInfo, the app information. + * @return + */ + virtual void LoadAbility(const sptr &token, const sptr &preToken, + const std::shared_ptr &abilityInfo, const std::shared_ptr &appInfo) override; + + /** + * TerminateAbility, call TerminateAbility() through the proxy object, terminate the token ability. + * + * @param token, token, he unique identification to terminate the ability. + * @return + */ + virtual void TerminateAbility(const sptr &token) override; + + /** + * UpdateAbilityState, call UpdateAbilityState() through the proxy object, update the ability status. + * + * @param token, the unique identification to update the ability. + * @param state, ability status that needs to be updated. + * @return + */ + virtual void UpdateAbilityState(const sptr &token, const AbilityState state) override; + + /** + * RegisterAppStateCallback, call RegisterAppStateCallback() through the proxy object, register the callback. + * + * @param callback, Ams register the callback. + * @return + */ + virtual void RegisterAppStateCallback(const sptr &callback) override; + + /** + * Reset,call Reset() through the proxy object, reset DFX of AppMgr. + * + * @return + */ + virtual void Reset() override; + + /** + * AbilityBehaviorAnalysis,call AbilityBehaviorAnalysis() through the proxy object, + * ability behavior analysis assistant process optimization. + * + * @param token, the unique identification to start the ability. + * @param preToken, the unique identification to call the ability. + * @param visibility, the visibility information about windows info. + * @param perceptibility, the Perceptibility information about windows info. + * @param connectionState, the service ability connection state. + * @return + */ + virtual void AbilityBehaviorAnalysis(const sptr &token, const sptr &preToken, + const int32_t visibility, const int32_t perceptibility, const int32_t connectionState) override; + + /** + * KillProcessByAbilityToken, call KillProcessByAbilityToken() through proxy object, + * kill the process by ability token. + * + * @param token, the unique identification to the ability. + * @return + */ + virtual void KillProcessByAbilityToken(const sptr &token) override; + + /** + * KillApplication, call KillApplication() through proxy object, kill the application. + * + * @param bundleName, bundle name in Application record. + * @return ERR_OK, return back success, others fail. + */ + virtual int32_t KillApplication(const std::string &bundleName) override; + +private: + bool WriteInterfaceToken(MessageParcel &data); + +private: + static inline BrokerDelegator delegator_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_AMS_MGR_CLIENT_H diff --git a/interfaces/innerkits/appexecfwk_core/include/appmgr/ams_mgr_stub.h b/interfaces/innerkits/appexecfwk_core/include/appmgr/ams_mgr_stub.h new file mode 100644 index 000000000..d9e63564b --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/appmgr/ams_mgr_stub.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_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_AMS_MGR_STUB_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_AMS_MGR_STUB_H + +#include + +#include "iremote_stub.h" +#include "nocopyable.h" +#include "string_ex.h" +#include "ams_mgr_interface.h" + +namespace OHOS { +namespace AppExecFwk { + +class AmsMgrStub : public IRemoteStub { +public: + AmsMgrStub(); + virtual ~AmsMgrStub(); + + virtual int OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + +private: + int32_t HandleLoadAbility(MessageParcel &data, MessageParcel &reply); + int32_t HandleTerminateAbility(MessageParcel &data, MessageParcel &reply); + int32_t HandleUpdateAbilityState(MessageParcel &data, MessageParcel &reply); + int32_t HandleRegisterAppStateCallback(MessageParcel &data, MessageParcel &reply); + int32_t HandleReset(MessageParcel &data, MessageParcel &reply); + int32_t HandleAbilityBehaviorAnalysis(MessageParcel &data, MessageParcel &reply); + int32_t HandleKillProcessByAbilityToken(MessageParcel &data, MessageParcel &reply); + int32_t HandleKillApplication(MessageParcel &data, MessageParcel &reply); + + using AmsMgrFunc = int32_t (AmsMgrStub::*)(MessageParcel &data, MessageParcel &reply); + std::map memberFuncMap_; + + DISALLOW_COPY_AND_MOVE(AmsMgrStub); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_AMS_MGR_STUB_H diff --git a/interfaces/innerkits/appexecfwk_core/include/appmgr/app_launch_data.h b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_launch_data.h new file mode 100644 index 000000000..b65b80abd --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_launch_data.h @@ -0,0 +1,149 @@ +/* + * 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_APPMGR_INCLUDE_APP_LAUNCH_DATA_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_APPMGR_INCLUDE_APP_LAUNCH_DATA_H + +#include + +#include "parcel.h" + +#include "application_info.h" +#include "process_info.h" +#include "profile.h" + +namespace OHOS { +namespace AppExecFwk { + +class AppLaunchData : public Parcelable { +public: + /** + * @brief setting information for the application. + * + * @param ApplicationInfo&, the current application info. + */ + void SetApplicationInfo(const ApplicationInfo &); + + /** + * @brief Setting information for the profile. + * + * @param Profile&, the current profile. + */ + void SetProfile(const Profile &); + + /** + * @brief Setting information for the process. + * + * @param Profile&, the current process info. + */ + void SetProcessInfo(const ProcessInfo &); + + /** + * @brief Setting id for app record. + * + * @param int32_t, the current app record id. + */ + void SetRecordId(const int32_t); + + /** + * @brief Setting id for User. + * + * @param int32_t, the current app User. + */ + void SetUId(const int32_t); + + /** + * @brief Obtains the info of the application. + * + * @return Returns the current application info. + */ + inline const ApplicationInfo &GetApplicationInfo() const + { + return applicationInfo_; + } + + /** + * @brief Obtains the profile. + * + * @return Returns the current profile. + */ + inline const Profile &GetProfile() const + { + return profile_; + } + + /** + * @brief Obtains the info of the process. + * + * @return Returns the current process info. + */ + inline const ProcessInfo &GetProcessInfo() const + { + return processInfo_; + } + + /** + * @brief Obtains the id of the app record. + * + * @return Returns the current appRecord id. + */ + inline int32_t GetRecordId() const + { + return recordId_; + } + + /** + * @brief Obtains the id of the User. + * + * @return Returns the current User id. + */ + inline int32_t GetUId() const + { + return uId_; + } + + /** + * @brief read this Sequenceable object from a Parcel. + * + * @param inParcel Indicates the Parcel object into which the Sequenceable object has been marshaled. + * @return Returns true if read successed; returns false otherwise. + */ + bool ReadFromParcel(Parcel &parcel); + + /** + * @brief Marshals this Sequenceable object into a Parcel. + * + * @param outParcel Indicates the Parcel object to which the Sequenceable object will be marshaled. + */ + virtual bool Marshalling(Parcel &parcel) const override; + + /** + * @brief Unmarshals this Sequenceable object from a Parcel. + * + * @param inParcel Indicates the Parcel object into which the Sequenceable object has been marshaled. + */ + static AppLaunchData *Unmarshalling(Parcel &parcel); + +private: + ApplicationInfo applicationInfo_; + Profile profile_; + ProcessInfo processInfo_; + int32_t recordId_ = 0; + int32_t uId_ = 0; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_APPMGR_INCLUDE_APP_LAUNCH_DATA_H diff --git a/interfaces/innerkits/appexecfwk_core/include/appmgr/app_mgr_client.h b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_mgr_client.h new file mode 100644 index 000000000..44e21c6b6 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_mgr_client.h @@ -0,0 +1,148 @@ +/* + * 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_APP_MGR_CLIENT_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APP_MGR_CLIENT_H + +#include "iremote_object.h" +#include "refbase.h" + +#include "ability_info.h" +#include "application_info.h" +#include "app_mgr_constants.h" +#include "iapp_state_callback.h" +#include "running_process_info.h" + +namespace OHOS { +namespace AppExecFwk { + +class AppServiceManager; + +class AppMgrClient { +public: + AppMgrClient(); + virtual ~AppMgrClient(); + + /** + * Load ability. + * + * @param token, Ability identify. + * @param abilityInfo, Ability information. + * @param appInfo, Application information. + * @return Returns RESULT_OK on success, others on failure. + */ + virtual AppMgrResultCode LoadAbility(const sptr &token, const sptr &preToken, + const AbilityInfo &abilityInfo, const ApplicationInfo &appInfo); + + /** + * Terminate ability. + * + * @param token Ability identify. + * + * @return Returns RESULT_OK on success, others on failure. + */ + virtual AppMgrResultCode TerminateAbility(const sptr &token); + + /** + * Update ability state. + * + * @param token Ability identify. + * @param state Ability running state. + * @return Returns RESULT_OK on success, others on failure. + */ + virtual AppMgrResultCode UpdateAbilityState(const sptr &token, const AbilityState state); + + /** + * Register Application state callback. + * + * @param callback IAppStateCallback + * @return Returns RESULT_OK on success, others on failure. + */ + virtual AppMgrResultCode RegisterAppStateCallback(const sptr &callback); + + /** + * Connect service. + * + * @return Returns RESULT_OK on success, others on failure. + */ + virtual AppMgrResultCode ConnectAppMgrService(); + + /** + * Ability manager resst. + * + * @return Returns RESULT_OK on success, others on failure. + */ + virtual AppMgrResultCode Reset(); + + /** + * AbilityBehaviorAnalysis, ability behavior analysis assistant process optimization. + * + * @param token, the unique identification to start the ability. + * @param preToken, the unique identification to call the ability. + * @param visibility, the visibility information about windows info. + * @param perceptibility, the Perceptibility information about windows info. + * @param connectionState, the service ability connection state. + * @return Returns RESULT_OK on success, others on failure. + */ + virtual AppMgrResultCode AbilityBehaviorAnalysis(const sptr &token, + const sptr &preToken, const int32_t visibility, const int32_t perceptibility, + const int32_t connectionState); + + /** + * KillProcessByAbilityToken, call KillProcessByAbilityToken() through proxy object, + * kill the process by ability token. + * + * @param token, the unique identification to the ability. + * @return Returns RESULT_OK on success, others on failure. + */ + virtual AppMgrResultCode KillProcessByAbilityToken(const sptr &token); + + /** + * KillApplication, call KillApplication() through proxy object, kill the application. + * + * @param bundleName, bundle name in Application record. + * @return ERR_OK, return back success, others fail. + */ + virtual AppMgrResultCode KillApplication(const std::string &bundleName); + + /** + * ClearUpApplicationData, call ClearUpApplicationData() through proxy project, + * clear the application data. + * + * @param bundleName, bundle name in Application record. + * @return + */ + virtual AppMgrResultCode ClearUpApplicationData(const std::string &bundleName); + + /** + * GetAllRunningProcesses, call GetAllRunningProcesses() through proxy project. + * Obtains information about application processes that are running on the device. + * + * @param runningProcessInfo, app name in Application record. + * @return ERR_OK ,return back success,others fail. + */ + virtual AppMgrResultCode GetAllRunningProcesses(std::shared_ptr &runningProcessInfo); + +private: + void SetServiceManager(std::unique_ptr serviceMgr); + +private: + std::unique_ptr serviceManager_; + sptr remote_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APP_MGR_CLIENT_H \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_core/include/appmgr/app_mgr_constants.h b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_mgr_constants.h new file mode 100644 index 000000000..3ec06f155 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_mgr_constants.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_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_MGR_CONSTANTS_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_MGR_CONSTANTS_H + +namespace OHOS { +namespace AppExecFwk { +namespace Constants { + +const std::string APP_MGR_SERVICE_NAME = "AppMgrService"; + +} // namespace Constants + +enum class ApplicationState { + APP_STATE_BEGIN = 0, + APP_STATE_CREATE = APP_STATE_BEGIN, + APP_STATE_READY, + APP_STATE_FOREGROUND, + APP_STATE_BACKGROUND, + APP_STATE_SUSPENDED, + APP_STATE_TERMINATED, + APP_STATE_END, +}; + +enum class AbilityState { + ABILITY_STATE_BEGIN = 0, + ABILITY_STATE_CREATE = ABILITY_STATE_BEGIN, + ABILITY_STATE_READY, + ABILITY_STATE_FOREGROUND, + ABILITY_STATE_BACKGROUND, + ABILITY_STATE_TERMINATED, + ABILITY_STATE_END, +}; + +enum AppMgrResultCode { + RESULT_OK = 0, + ERROR_SERVICE_NOT_READY, + ERROR_SERVICE_NOT_CONNECTED, +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_MGR_CONSTANTS_H diff --git a/interfaces/innerkits/appexecfwk_core/include/appmgr/app_mgr_interface.h b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_mgr_interface.h new file mode 100644 index 000000000..ce07a2de9 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_mgr_interface.h @@ -0,0 +1,140 @@ +/* + * 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_APPMGR_APP_MGR_INTERFACE_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_MGR_INTERFACE_H + +#include "iremote_broker.h" +#include "iremote_object.h" + +#include "ability_info.h" +#include "application_info.h" +#include "app_record_id.h" +#include "iapp_state_callback.h" +#include "ams_mgr_interface.h" +#include "running_process_info.h" + +namespace OHOS { +namespace AppExecFwk { + +class IAppMgr : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.appexecfwk.AppMgr"); + + /** + * AttachApplication, call AttachApplication() through proxy object, + * get all the information needed to start the Application (data related to the Application ). + * + * @param app, information needed to start the Application. + * @return + */ + virtual void AttachApplication(const sptr &app) = 0; + + /** + * ApplicationForegrounded, call ApplicationForegrounded() through proxy object, + * set the application to Foreground State. + * + * @param recordId, a unique record that identifies this Application from others. + * @return + */ + virtual void ApplicationForegrounded(const int32_t recordId) = 0; + + /** + * ApplicationBackgrounded, call ApplicationBackgrounded() through proxy object, + * set the application to Backgrounded State. + * + * @param recordId, a unique record that identifies this Application from others. + * @return + */ + virtual void ApplicationBackgrounded(const int32_t recordId) = 0; + + /** + * ApplicationTerminated, call ApplicationTerminated() through proxy object, + * terminate the application. + * + * @param recordId, a unique record that identifies this Application from others. + * @return + */ + virtual void ApplicationTerminated(const int32_t recordId) = 0; + + /** + * CheckPermission, call CheckPermission() through proxy object, check the permission. + * + * @param recordId, a unique record that identifies this Application from others. + * @param permission, check the permissions. + * @return ERR_OK, return back success, others fail. + */ + virtual int CheckPermission(const int32_t recordId, const std::string &permission) = 0; + + /** + * AbilityCleaned,call through AbilityCleaned() proxy project, clean Ability record. + * + * @param token, a unique record that identifies AbilityCleaned from others. + * @return + */ + virtual void AbilityCleaned(const sptr &token) = 0; + + /** + * GetAmsMgr, call GetAmsMgr() through proxy object, get AMS interface instance. + * + * @return sptr, return to AMS interface instance. + */ + virtual sptr GetAmsMgr() = 0; + + /** + * ClearUpApplicationData, call ClearUpApplicationData() through proxy project, + * clear the application data. + * + * @param bundleName, bundle name in Application record. + * @return + */ + virtual void ClearUpApplicationData(const std::string &bundleName) = 0; + + /** + * IsBackgroundRunningRestricted, call IsBackgroundRunningRestricted() through proxy project, + * Checks whether the process of this application is forbidden to run in the background. + * + * @param bundleName, bundle name in Application record. + * @return ERR_OK, return back success, others fail. + */ + virtual int IsBackgroundRunningRestricted(const std::string &bundleName) = 0; + + /** + * GetAllRunningProcesses, call GetAllRunningProcesses() through proxy project. + * Obtains information about application processes that are running on the device. + * + * @param runningProcessInfo, app name in Application record. + * @return ERR_OK ,return back success,others fail. + */ + virtual int GetAllRunningProcesses(std::shared_ptr &runningProcessInfo) = 0; + + enum class Message { + AMS_APP_ATTACH_APPLICATION = 0, + AMS_APP_APPLICATION_FOREGROUNDED, + AMS_APP_APPLICATION_BACKGROUNDED, + AMS_APP_APPLICATION_TERMINATED, + AMS_APP_CHECK_PERMISSION, + AMS_APP_ABILITY_CLEANED, + AMS_APP_GET_MGR_INSTANCE, + AMS_APP_CLEAR_UP_APPLICATION_DATA, + AMS_APP_IS_BACKGROUND_RUNNING_RESTRICTED, + AMS_APP_GET_ALL_RUNNING_PROCESSES, + }; +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_MGR_INTERFACE_H diff --git a/interfaces/innerkits/appexecfwk_core/include/appmgr/app_mgr_proxy.h b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_mgr_proxy.h new file mode 100644 index 000000000..9b9cd88c5 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_mgr_proxy.h @@ -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. + */ + +#ifndef FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_MGR_CLIENT_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_MGR_CLIENT_H + +#include "iremote_proxy.h" + +#include "app_mgr_interface.h" + +namespace OHOS { +namespace AppExecFwk { + +class AppMgrProxy : public IRemoteProxy { +public: + explicit AppMgrProxy(const sptr &impl); + virtual ~AppMgrProxy() = default; + + /** + * AttachApplication, call AttachApplication() through proxy object, + * get all the information needed to start the Application (data related to the Application ). + * + * @param app, information needed to start the Application. + * @return + */ + virtual void AttachApplication(const sptr &obj) override; + + /** + * ApplicationForegrounded, call ApplicationForegrounded() through proxy object, + * set the application to Foreground State. + * + * @param recordId, a unique record that identifies this Application from others. + * @return + */ + virtual void ApplicationForegrounded(const int32_t recordId) override; + + /** + * ApplicationBackgrounded, call ApplicationBackgrounded() through proxy object, + * set the application to Backgrounded State. + * + * @param recordId, a unique record that identifies this Application from others. + * @return + */ + virtual void ApplicationBackgrounded(const int32_t recordId) override; + + /** + * ApplicationTerminated, call ApplicationTerminated() through proxy object, + * terminate the application. + * + * @param recordId, a unique record that identifies this Application from others. + * @return + */ + virtual void ApplicationTerminated(const int32_t recordId) override; + + /** + * CheckPermission, call CheckPermission() through proxy object, check the permission. + * + * @param recordId, a unique record that identifies this Application from others. + * @param permission, check the permissions. + * @return ERR_OK, return back success, others fail. + */ + virtual int32_t CheckPermission(const int32_t recordId, const std::string &permission) override; + + /** + * AbilityCleaned,call through AbilityCleaned() proxy project, clean Ability record. + * + * @param token, a unique record that identifies AbilityCleaned from others. + * @return + */ + virtual void AbilityCleaned(const sptr &token) override; + + /** + * GetAmsMgr, call GetAmsMgr() through proxy object, get AMS interface instance. + * + * @return sptr, return to AMS interface instance. + */ + virtual sptr GetAmsMgr() override; + + /** + * ClearUpApplicationData, call ClearUpApplicationData() through proxy project, + * clear the application data. + * + * @param bundleName, bundle name in Application record. + * @return + */ + virtual void ClearUpApplicationData(const std::string &bundleName) override; + + /** + * IsBackgroundRunningRestricted, call IsBackgroundRunningRestricted() through proxy project, + * Checks whether the process of this application is forbidden to run in the background. + * + * @param bundleName, bundle name in Application record. + * @return ERR_OK, return back success, others fail. + */ + virtual int32_t IsBackgroundRunningRestricted(const std::string &bundleName) override; + + /** + * GetAllRunningProcesses, call GetAllRunningProcesses() through proxy project. + * Obtains information about application processes that are running on the device. + * + * @param runningProcessInfo, app name in Application record. + * @return ERR_OK ,return back success,others fail. + */ + virtual int32_t GetAllRunningProcesses(std::shared_ptr &runningProcessInfo) override; + +private: + bool SendTransactCmd(IAppMgr::Message code, MessageParcel &data, MessageParcel &reply); + bool WriteInterfaceToken(MessageParcel &data); + static inline BrokerDelegator delegator_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_MGR_CLIENT_H diff --git a/interfaces/innerkits/appexecfwk_core/include/appmgr/app_mgr_stub.h b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_mgr_stub.h new file mode 100644 index 000000000..132b4284f --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_mgr_stub.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_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_MGR_STUB_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_MGR_STUB_H + +#include + +#include "iremote_stub.h" +#include "nocopyable.h" +#include "string_ex.h" +#include "app_mgr_interface.h" + +namespace OHOS { +namespace AppExecFwk { + +class AppMgrStub : public IRemoteStub { +public: + AppMgrStub(); + virtual ~AppMgrStub(); + + virtual int OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + +private: + int32_t HandleAttachApplication(MessageParcel &data, MessageParcel &reply); + int32_t HandleApplicationForegrounded(MessageParcel &data, MessageParcel &reply); + int32_t HandleApplicationBackgrounded(MessageParcel &data, MessageParcel &reply); + int32_t HandleApplicationTerminated(MessageParcel &data, MessageParcel &reply); + int32_t HandleCheckPermission(MessageParcel &data, MessageParcel &reply); + int32_t HandleAbilityCleaned(MessageParcel &data, MessageParcel &reply); + int32_t HandleGetAmsMgr(MessageParcel &data, MessageParcel &reply); + int32_t HandleClearUpApplicationData(MessageParcel &data, MessageParcel &reply); + int32_t HandleIsBackgroundRunningRestricted(MessageParcel &data, MessageParcel &reply); + int32_t HandleGetAllRunningProcesses(MessageParcel &data, MessageParcel &reply); + + using AppMgrFunc = int32_t (AppMgrStub::*)(MessageParcel &data, MessageParcel &reply); + std::map memberFuncMap_; + + DISALLOW_COPY_AND_MOVE(AppMgrStub); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_MGR_STUB_H diff --git a/interfaces/innerkits/appexecfwk_core/include/appmgr/app_process_data.h b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_process_data.h new file mode 100644 index 000000000..8ba81a3d4 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_process_data.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_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_PROCESS_DATA_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_PROCESS_DATA_H + +#include + +#include "parcel.h" + +#include "app_mgr_constants.h" + +namespace OHOS { +namespace AppExecFwk { + +struct AppProcessData : public Parcelable { + /** + * @brief read this Sequenceable object from a Parcel. + * + * @param inParcel Indicates the Parcel object into which the Sequenceable object has been marshaled. + * @return Returns true if read successed; returns false otherwise. + */ + bool ReadFromParcel(Parcel &parcel); + + /** + * @brief Marshals this Sequenceable object into a Parcel. + * + * @param outParcel Indicates the Parcel object to which the Sequenceable object will be marshaled. + */ + virtual bool Marshalling(Parcel &parcel) const override; + + /** + * @brief Unmarshals this Sequenceable object from a Parcel. + * + * @param inParcel Indicates the Parcel object into which the Sequenceable object has been marshaled. + */ + static AppProcessData *Unmarshalling(Parcel &parcel); + + std::string appName; + std::string processName; + ApplicationState appState = ApplicationState::APP_STATE_CREATE; + pid_t pid = 0; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_PROCESS_DATA_H diff --git a/interfaces/innerkits/appexecfwk_core/include/appmgr/app_record_id.h b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_record_id.h new file mode 100644 index 000000000..fa9303e7e --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_record_id.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_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_RECORD_ID_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_RECORD_ID_H + +namespace OHOS { +namespace AppExecFwk { + +class AppRecordId { +public: + /** + * @brief create id for the application. + * + * @return the app record id. + */ + static int32_t Create(); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_RECORD_ID_H diff --git a/interfaces/innerkits/appexecfwk_core/include/appmgr/app_scheduler_host.h b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_scheduler_host.h new file mode 100644 index 000000000..6a6a7f8c4 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_scheduler_host.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_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_SCHEDULER_HOST_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_SCHEDULER_HOST_H + +#include + +#include "iremote_object.h" +#include "iremote_stub.h" +#include "nocopyable.h" +#include "app_scheduler_interface.h" +#include "string_ex.h" + +namespace OHOS { +namespace AppExecFwk { +class AppSchedulerHost : public IRemoteStub { +public: + AppSchedulerHost(); + virtual ~AppSchedulerHost(); + + virtual int OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + +private: + int32_t HandleScheduleForegroundApplication(MessageParcel &data, MessageParcel &reply); + int32_t HandleScheduleBackgroundApplication(MessageParcel &data, MessageParcel &reply); + int32_t HandleScheduleTerminateApplication(MessageParcel &data, MessageParcel &reply); + int32_t HandleScheduleLowMemory(MessageParcel &data, MessageParcel &reply); + int32_t HandleScheduleShrinkMemory(MessageParcel &data, MessageParcel &reply); + int32_t HandleScheduleLaunchAbility(MessageParcel &data, MessageParcel &reply); + int32_t HandleScheduleCleanAbility(MessageParcel &data, MessageParcel &reply); + int32_t HandleScheduleLaunchApplication(MessageParcel &data, MessageParcel &reply); + int32_t HandleScheduleProfileChanged(MessageParcel &data, MessageParcel &reply); + int32_t HandleScheduleConfigurationUpdated(MessageParcel &data, MessageParcel &reply); + int32_t HandleScheduleProcessSecurityExit(MessageParcel &data, MessageParcel &reply); + + using AppSchedulerFunc = int32_t (AppSchedulerHost::*)(MessageParcel &data, MessageParcel &reply); + std::map memberFuncMap_; + + DISALLOW_COPY_AND_MOVE(AppSchedulerHost); +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_SCHEDULER_HOST_H diff --git a/interfaces/innerkits/appexecfwk_core/include/appmgr/app_scheduler_interface.h b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_scheduler_interface.h new file mode 100644 index 000000000..1f1799b74 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_scheduler_interface.h @@ -0,0 +1,144 @@ +/* + * 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_APPMGR_APP_SCHEDULER_INTERFACE_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_SCHEDULER_INTERFACE_H + +#include "iremote_broker.h" +#include "ability_info.h" +#include "app_launch_data.h" +#include "app_launch_data.h" +#include "dummy_configuration.h" + +namespace OHOS { +namespace AppExecFwk { +class IAppScheduler : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.appexecfwk.AppScheduler"); + + /** + * ScheduleForegroundApplication, call ScheduleForegroundApplication() through proxy project, + * Notify application to switch to foreground. + * + * @return + */ + virtual void ScheduleForegroundApplication() = 0; + + /** + * ScheduleBackgroundApplication, call ScheduleBackgroundApplication() through proxy project, + * Notify application to switch to background. + * + * @return + */ + virtual void ScheduleBackgroundApplication() = 0; + + /** + * ScheduleTerminateApplication, call ScheduleTerminateApplication() through proxy project, + * Notify application to terminate. + * + * @return + */ + virtual void ScheduleTerminateApplication() = 0; + + /** + * ScheduleShrinkMemory, call ScheduleShrinkMemory() through proxy project, + * Notifies the application of the memory seen. + * + * @param The memory value. + * + * @return + */ + virtual void ScheduleShrinkMemory(const int) = 0; + + /** + * ScheduleLowMemory, call ScheduleLowMemory() through proxy project, + * Notify application to low memory. + * + * @return + */ + virtual void ScheduleLowMemory() = 0; + + /** + * ScheduleLaunchApplication, call ScheduleLaunchApplication() through proxy project, + * Notify application to launch application. + * + * @param The app data value. + * + * @return + */ + virtual void ScheduleLaunchApplication(const AppLaunchData &) = 0; + + /** + * ScheduleLaunchAbility, call ScheduleLaunchAbility() through proxy project, + * Notify application to launch ability. + * + * @param The ability info. + * @return + */ + virtual void ScheduleLaunchAbility(const AbilityInfo &, const sptr &) = 0; + + /** + * ScheduleCleanAbility, call ScheduleCleanAbility() through proxy project, + * Notify application to clean ability. + * + * @param The ability token. + * @return + */ + virtual void ScheduleCleanAbility(const sptr &) = 0; + + /** + * ScheduleProfileChanged, call ScheduleProfileChanged() through proxy project, + * Notify application to profile update. + * + * @param The profile data. + * @return + */ + virtual void ScheduleProfileChanged(const Profile &) = 0; + + /** + * ScheduleConfigurationUpdated, call ScheduleConfigurationUpdated() through proxy project, + * Notify application to configuration update. + * + * @param The configuration data. + * @return + */ + virtual void ScheduleConfigurationUpdated(const Configuration &config) = 0; + + /** + * ScheduleProcessSecurityExit, call ScheduleProcessSecurityExit() through proxy project, + * Notify application process exit safely. + * + * @return + */ + virtual void ScheduleProcessSecurityExit() = 0; + + enum class Message { + SCHEDULE_FOREGROUND_APPLICATION_TRANSACTION = 0, + SCHEDULE_BACKGROUND_APPLICATION_TRANSACTION, + SCHEDULE_TERMINATE_APPLICATION_TRANSACTION, + SCHEDULE_LOWMEMORY_APPLICATION_TRANSACTION, + SCHEDULE_SHRINK_MEMORY_APPLICATION_TRANSACTION, + SCHEDULE_LAUNCH_ABILITY_TRANSACTION, + SCHEDULE_CLEAN_ABILITY_TRANSACTION, + SCHEDULE_LAUNCH_APPLICATION_TRANSACTION, + SCHEDULE_PROFILE_CHANGED_TRANSACTION, + SCHEDULE_CONFIGURATION_UPDATED, + SCHEDULE_PROCESS_SECURITY_EXIT_TRANSACTION, + }; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_SCHEDULER_INTERFACE_H diff --git a/interfaces/innerkits/appexecfwk_core/include/appmgr/app_scheduler_proxy.h b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_scheduler_proxy.h new file mode 100644 index 000000000..a90508224 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_scheduler_proxy.h @@ -0,0 +1,132 @@ +/* + * 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_APPMGR_APP_SCHEDULER_CLIENT_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_SCHEDULER_CLIENT_H + +#include "iremote_proxy.h" +#include "app_scheduler_interface.h" + +namespace OHOS { +namespace AppExecFwk { +class AppSchedulerProxy : public IRemoteProxy { +public: + explicit AppSchedulerProxy(const sptr &impl); + virtual ~AppSchedulerProxy() = default; + + /** + * ScheduleForegroundApplication, call ScheduleForegroundApplication() through proxy project, + * Notify application to switch to foreground. + * + * @return + */ + virtual void ScheduleForegroundApplication() override; + + /** + * ScheduleBackgroundApplication, call ScheduleBackgroundApplication() through proxy project, + * Notify application to switch to background. + * + * @return + */ + virtual void ScheduleBackgroundApplication() override; + + /** + * ScheduleTerminateApplication, call ScheduleTerminateApplication() through proxy project, + * Notify application to terminate. + * + * @return + */ + virtual void ScheduleTerminateApplication() override; + + /** + * ScheduleShrinkMemory, call ScheduleShrinkMemory() through proxy project, + * Notifies the application of the memory seen. + * + * @param The memory value. + * + * @return + */ + virtual void ScheduleShrinkMemory(const int32_t) override; + + /** + * ScheduleLowMemory, call ScheduleLowMemory() through proxy project, + * Notify application to low memory. + * + * @return + */ + virtual void ScheduleLowMemory() override; + + /** + * ScheduleLaunchApplication, call ScheduleLaunchApplication() through proxy project, + * Notify application to launch application. + * + * @param The app data value. + * + * @return + */ + virtual void ScheduleLaunchApplication(const AppLaunchData &) override; + + /** + * ScheduleLaunchAbility, call ScheduleLaunchAbility() through proxy project, + * Notify application to launch ability. + * + * @param The ability info. + * @return + */ + virtual void ScheduleLaunchAbility(const AbilityInfo &, const sptr &) override; + + /** + * ScheduleCleanAbility, call ScheduleCleanAbility() through proxy project, + * Notify application to clean ability. + * + * @param The ability token. + * @return + */ + virtual void ScheduleCleanAbility(const sptr &) override; + + /** + * ScheduleProfileChanged, call ScheduleProfileChanged() through proxy project, + * Notify application to profile update. + * + * @param The profile data. + * @return + */ + virtual void ScheduleProfileChanged(const Profile &) override; + + /** + * ScheduleConfigurationUpdated, call ScheduleConfigurationUpdated() through proxy project, + * Notify application to configuration update. + * + * @param The configuration data. + * @return + */ + virtual void ScheduleConfigurationUpdated(const Configuration &config) override; + + /** + * ScheduleProcessSecurityExit, call ScheduleProcessSecurityExit() through proxy project, + * Notify application process exit safely. + * + * @return + */ + virtual void ScheduleProcessSecurityExit() override; + +private: + bool WriteInterfaceToken(MessageParcel &data); + static inline BrokerDelegator delegator_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_SCHEDULER_CLIENT_H diff --git a/interfaces/innerkits/appexecfwk_core/include/appmgr/app_service_manager.h b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_service_manager.h new file mode 100644 index 000000000..6cca44e06 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_service_manager.h @@ -0,0 +1,39 @@ +/* + * 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_APP_SERVICE_MANAGER_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APP_SERVICE_MANAGER_H + +#include "iremote_object.h" + +namespace OHOS { +namespace AppExecFwk { + +class AppServiceManager { +public: + AppServiceManager() = default; + virtual ~AppServiceManager() = default; + + /** + * @brief Obtains the AMS interface instance. + * + * @return Returns the AMS interface instance. + */ + virtual sptr GetAppMgrService() const; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APP_SERVICE_MANAGER_H \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_core/include/appmgr/app_state_callback_host.h b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_state_callback_host.h new file mode 100644 index 000000000..0c4ce2bb6 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_state_callback_host.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_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_STATE_CALLBACK_HOST_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_STATE_CALLBACK_HOST_H + +#include + +#include "iremote_stub.h" +#include "nocopyable.h" +#include "string_ex.h" +#include "app_mgr_constants.h" +#include "iapp_state_callback.h" + +namespace OHOS { +namespace AppExecFwk { + +class AppStateCallbackHost : public IRemoteStub { +public: + AppStateCallbackHost(); + virtual ~AppStateCallbackHost(); + + virtual int OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + + /** + * AbilityMgr's request is done. + * + * @param token Ability token. + * @param state Application state. + */ + virtual void OnAbilityRequestDone(const sptr &, const AbilityState) override; + + /** + * Application state changed callback. + * + * @param appProcessData Process data + */ + virtual void OnAppStateChanged(const AppProcessData &) override; + +private: + int32_t HandleOnAppStateChanged(MessageParcel &data, MessageParcel &reply); + int32_t HandleOnAbilityRequestDone(MessageParcel &data, MessageParcel &reply); + + using AppStateCallbackFunc = int32_t (AppStateCallbackHost::*)(MessageParcel &data, MessageParcel &reply); + std::map memberFuncMap_; + + DISALLOW_COPY_AND_MOVE(AppStateCallbackHost); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_STATE_CALLBACK_HOST_H diff --git a/interfaces/innerkits/appexecfwk_core/include/appmgr/app_state_callback_proxy.h b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_state_callback_proxy.h new file mode 100644 index 000000000..f563c110f --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_state_callback_proxy.h @@ -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. + */ + +#ifndef FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_STATE_CALLBACK_PROXY_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_STATE_CALLBACK_PROXY_H + +#include "iremote_proxy.h" + +#include "app_mgr_constants.h" +#include "iapp_state_callback.h" + +namespace OHOS { +namespace AppExecFwk { + +class AppStateCallbackProxy : public IRemoteProxy { +public: + explicit AppStateCallbackProxy(const sptr &impl); + virtual ~AppStateCallbackProxy() = default; + + /** + * AbilityMgr's request is done. + * + * @param token Ability token. + * @param state Application state. + */ + virtual void OnAbilityRequestDone(const sptr &token, const AbilityState state) override; + + /** + * Application state changed callback. + * + * @param appProcessData Process data + */ + virtual void OnAppStateChanged(const AppProcessData &appProcessData) override; + +private: + bool WriteInterfaceToken(MessageParcel &data); + static inline BrokerDelegator delegator_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_STATE_CALLBACK_PROXY_H diff --git a/interfaces/innerkits/appexecfwk_core/include/appmgr/app_task_info.h b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_task_info.h new file mode 100644 index 000000000..653107c7c --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/appmgr/app_task_info.h @@ -0,0 +1,116 @@ +/* + * 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_APPMGR_APP_TASK_INFO_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_TASK_INFO_H + +#include +#include + +#include "parcel.h" + +namespace OHOS { +namespace AppExecFwk { + +class AppTaskInfo : public Parcelable { +public: + /** + * @brief Obtains the app name. + * + * @return Returns the app name. + */ + const std::string &GetName() const; + + /** + * @brief Obtains the process name. + * + * @return Returns the process name. + */ + const std::string &GetProcessName() const; + + /** + * @brief Obtains the app pid. + * + * @return Returns the app pid. + */ + pid_t GetPid() const; + + /** + * @brief Obtains the app record id. + * + * @return Returns app record id. + */ + int32_t GetRecordId() const; + + /** + * @brief Setting name for app. + * + * @param appName, the app name. + */ + void SetName(const std::string &appName); + + /** + * @brief Setting name for process. + * + * @param int32_t, the process name. + */ + void SetProcessName(const std::string &processName); + + /** + * @brief Setting pid for app. + * + * @param int32_t, the app pid. + */ + void SetPid(const pid_t pid); + + /** + * @brief Setting id for app record. + * + * @param int32_t, the app record id. + */ + void SetRecordId(const int32_t appRecordId); + + /** + * @brief read this Sequenceable object from a Parcel. + * + * @param inParcel Indicates the Parcel object into which the Sequenceable object has been marshaled. + * @return Returns true if read succeeded; returns false otherwise. + */ + bool ReadFromParcel(Parcel &parcel); + + /** + * @brief Marshals this Sequenceable object into a Parcel. + * + * @param outParcel Indicates the Parcel object to which the Sequenceable object will be marshaled. + */ + virtual bool Marshalling(Parcel &parcel) const override; + + /** + * @brief Unmarshals this Sequenceable object from a Parcel. + * + * @param inParcel Indicates the Parcel object into which the Sequenceable object has been marshaled. + */ + static AppTaskInfo *Unmarshalling(Parcel &parcel); + +private: + std::string appName_; + std::string processName_; + pid_t pid_ = 0; + int32_t appRecordId_ = 0; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_APP_TASK_INFO_H diff --git a/interfaces/innerkits/appexecfwk_core/include/appmgr/dummy_configuration.h b/interfaces/innerkits/appexecfwk_core/include/appmgr/dummy_configuration.h new file mode 100644 index 000000000..aafe7767b --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/appmgr/dummy_configuration.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_OHOS_CONFIGURATION_H +#define FOUNDATION_APPEXECFWK_OHOS_CONFIGURATION_H + +#include + +#include "nocopyable.h" +#include "parcel.h" + +namespace OHOS { +namespace AppExecFwk { + +class Configuration : public Parcelable { +public: + Configuration() = default; + explicit Configuration(const std::string &name); + virtual ~Configuration() = default; + + /** + * @brief Obtains the name of the Configuration. + * + * @return Returns the Configuration name. + */ + inline const std::string &GetName() const + { + return testInfostr_; + } + + /** + * @brief read this Sequenceable object from a Parcel. + * + * @param inParcel Indicates the Parcel object into which the Sequenceable object has been marshaled. + * @return Returns true if read successed; returns false otherwise. + */ + bool ReadFromParcel(Parcel &parcel); + + /** + * @brief Marshals this Sequenceable object into a Parcel. + * + * @param outParcel Indicates the Parcel object to which the Sequenceable object will be marshaled. + */ + virtual bool Marshalling(Parcel &parcel) const override; + + /** + * @brief Unmarshals this Sequenceable object from a Parcel. + * + * @param inParcel Indicates the Parcel object into which the Sequenceable object has been marshaled. + */ + static Configuration *Unmarshalling(Parcel &parcel); + +private: + std::string testInfostr_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_OHOS_CONFIGURATION_H \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_core/include/appmgr/iapp_state_callback.h b/interfaces/innerkits/appexecfwk_core/include/appmgr/iapp_state_callback.h new file mode 100644 index 000000000..e9fdfe6d3 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/appmgr/iapp_state_callback.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_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_IAPP_STATE_CALLBACK_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_IAPP_STATE_CALLBACK_H + +#include "iremote_broker.h" +#include "iremote_object.h" + +#include "app_mgr_constants.h" +#include "app_process_data.h" + +namespace OHOS { +namespace AppExecFwk { + +class IAppStateCallback : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.appexecfwk.AppStateCallback"); + + /** + * Application state changed callback. + * + * @param appProcessData Process data + */ + virtual void OnAppStateChanged(const AppProcessData &appProcessData) = 0; + + /** + * AbilityMgr's request is done. + * + * @param token Ability token. + * @param state Application state. + */ + virtual void OnAbilityRequestDone(const sptr &token, const AbilityState state) = 0; + + enum class Message { + TRANSACT_ON_APP_STATE_CHANGED = 0, + TRANSACT_ON_ABILITY_REQUEST_DONE, + }; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_IAPP_STATE_CALLBACK_H diff --git a/interfaces/innerkits/appexecfwk_core/include/appmgr/priority_object.h b/interfaces/innerkits/appexecfwk_core/include/appmgr/priority_object.h new file mode 100644 index 000000000..64e71f357 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/appmgr/priority_object.h @@ -0,0 +1,167 @@ +/* + * 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_PRIORITY_OBJECT_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_PRIORITY_OBJECT_H + +#include +#include + +#include "nocopyable.h" +#include "parcel.h" + +namespace OHOS { + +namespace AppExecFwk { + +class PriorityObject : public Parcelable { +public: + PriorityObject() = default; + virtual ~PriorityObject() = default; + + /** + * @brief Obtains the app pid. + * + * @return Returns the app pid. + */ + pid_t GetPid() const; + + /** + * @brief Obtains the app max adj. + * + * @return Returns the app max adj. + */ + int32_t GetMaxAdj() const; + + /** + * @brief Obtains the app cur adj. + * + * @return Returns the app cur adj. + */ + int32_t GetCurAdj() const; + + /** + * @brief Obtains the app cur cgroup. + * + * @return Returns the app cur cgroup. + */ + int32_t GetCurCgroup() const; + + /** + * @brief Obtains the app time level. + * + * @return Returns the app time level. + */ + int32_t GetTimeLevel() const; + + /** + * @brief Obtains the ability visible status. + * + * @return Returns the ability visible status. + */ + bool GetVisibleStatus() const; + + /** + * @brief Obtains the ability preceptible status. + * + * @return Returns the ability preceptible status. + */ + bool GetPerceptibleStatus() const; + + /** + * @brief Setting pid for app. + * + * @param appName, the app pid. + */ + void SetPid(const pid_t pid); + + /** + * @brief Setting max adj for app. + * + * @param appName, the app max adj. + */ + void SetMaxAdj(const int32_t maxAdj); + + /** + * @brief Setting cur adj for app. + * + * @param appName, the app cur adj. + */ + void SetCurAdj(const int32_t curAdj); + + /** + * @brief Setting cur cgroup for app. + * + * @param appName, the app cur cgroup. + */ + void SetCurCgroup(const int32_t curCgroup); + + /** + * @brief Setting time level for app. + * + * @param appName, the app time level. + */ + void SetTimeLevel(const int32_t timeLevel); + + /** + * @brief Setting visible status for ability. + * + * @param status, the visible status. + */ + void SetVisibleStatus(bool status); + + /** + * @brief Setting perceptible status for ability. + * + * @param status, the perceptible status. + */ + void SetPerceptibleStatus(bool status); + + /** + * @brief read this Sequenceable object from a Parcel. + * + * @param inParcel Indicates the Parcel object into which the Sequenceable object has been marshaled. + * @return Returns true if read successed; returns false otherwise. + */ + bool ReadFromParcel(Parcel &parcel); + + /** + * @brief Marshals this Sequenceable object into a Parcel. + * + * @param outParcel Indicates the Parcel object to which the Sequenceable object will be marshaled. + */ + virtual bool Marshalling(Parcel &parcel) const override; + + /** + * @brief Unmarshals this Sequenceable object from a Parcel. + * + * @param inParcel Indicates the Parcel object into which the Sequenceable object has been marshaled. + */ + static PriorityObject *Unmarshalling(Parcel &parcel); + +private: + pid_t pid_ = 0; + int32_t maxAdj_ = 0; + int32_t curAdj_ = 0; + int32_t curCgroup_ = 0; + int32_t timeLevel_ = 0; + bool visibleStatus_ = false; + bool perceptibleStatus_ = false; +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_PRIORITY_OBJECT_H \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_core/include/appmgr/process_info.h b/interfaces/innerkits/appexecfwk_core/include/appmgr/process_info.h new file mode 100644 index 000000000..969772a45 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/appmgr/process_info.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_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_PROCESS_INFO_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_PROCESS_INFO_H + +#include +#include + +#include "nocopyable.h" +#include "parcel.h" + +namespace OHOS { +namespace AppExecFwk { + +class ProcessInfo : public Parcelable { +public: + ProcessInfo() = default; + explicit ProcessInfo(const std::string &name, const pid_t &pid); + virtual ~ProcessInfo() = default; + + /** + * @brief Obtains the name of the current process. + * + * @return Returns the current process name. + */ + inline const std::string &GetProcessName() const + { + return processName_; + } + + /** + * @brief Obtains the id of the current process. + * + * @return Returns the current process id. + */ + inline pid_t GetPid() const + { + return pid_; + } + + /** + * @brief read this Sequenceable object from a Parcel. + * + * @param inParcel Indicates the Parcel object into which the Sequenceable object has been marshaled. + * @return Returns true if read successed; returns false otherwise. + */ + bool ReadFromParcel(Parcel &parcel); + + /** + * @brief Marshals this Sequenceable object into a Parcel. + * + * @param outParcel Indicates the Parcel object to which the Sequenceable object will be marshaled. + */ + virtual bool Marshalling(Parcel &parcel) const override; + + /** + * @brief Unmarshals this Sequenceable object from a Parcel. + * + * @param inParcel Indicates the Parcel object into which the Sequenceable object has been marshaled. + */ + static ProcessInfo *Unmarshalling(Parcel &parcel); + +private: + std::string processName_; + pid_t pid_ = 0; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_PROCESS_INFO_H diff --git a/interfaces/innerkits/appexecfwk_core/include/appmgr/profile.h b/interfaces/innerkits/appexecfwk_core/include/appmgr/profile.h new file mode 100644 index 000000000..6a0e8ca2e --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/appmgr/profile.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_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_PROFILE_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_PROFILE_H + +#include + +#include "nocopyable.h" +#include "parcel.h" + +namespace OHOS { +namespace AppExecFwk { + +class Profile : public Parcelable { +public: + Profile() = default; + explicit Profile(const std::string &name); + virtual ~Profile() = default; + + /** + * @brief Obtains the profile name. + * + * @return Returns profile name. + */ + inline const std::string &GetName() const + { + return profileName_; + } + + /** + * @brief read this Sequenceable object from a Parcel. + * + * @param inParcel Indicates the Parcel object into which the Sequenceable object has been marshaled. + * @return Returns true if read successed; returns false otherwise. + */ + bool ReadFromParcel(Parcel &parcel); + + /** + * @brief Marshals this Sequenceable object into a Parcel. + * + * @param outParcel Indicates the Parcel object to which the Sequenceable object will be marshaled. + */ + virtual bool Marshalling(Parcel &parcel) const override; + + /** + * @brief Unmarshals this Sequenceable object from a Parcel. + * + * @param inParcel Indicates the Parcel object into which the Sequenceable object has been marshaled. + */ + static Profile *Unmarshalling(Parcel &parcel); + +private: + std::string profileName_; // the name of the ability +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_APPMGR_PROFILE_H diff --git a/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_installer_interface.h b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_installer_interface.h new file mode 100644 index 000000000..4746db4dd --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_installer_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_BUNDLEMGR_BUNDLE_INSTALLER_INTERFACE_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_BUNDLEMGR_BUNDLE_INSTALLER_INTERFACE_H + +#include "status_receiver_interface.h" +#include "install_param.h" + +namespace OHOS { +namespace AppExecFwk { + +class IBundleInstaller : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.appexecfwk.BundleInstaller"); + /** + * @brief Installs an application, the final result will be notified from the statusReceiver object. + * @attention Notice that the bundleFilePath should be an absolute path. + * @param bundleFilePath Indicates the path for storing the ohos Ability Package (HAP) of the application + * to install or update. + * @param installParam Indicates the install parameters. + * @param statusReceiver Indicates the callback object that using for notifing the install result. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool Install(const std::string &bundleFilePath, const InstallParam &installParam, + const sptr &statusReceiver) = 0; + + /** + * @brief Uninstalls an application, the result will be notified from the statusReceiver object. + * @param bundleName Indicates the bundle name of the application to uninstall. + * @param installParam Indicates the uninstall parameters. + * @param statusReceiver Indicates the callback object that using for notifing the uninstall result. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool Uninstall(const std::string &bundleName, const InstallParam &installParam, + const sptr &statusReceiver) = 0; + + /** + * @brief Uninstalls a module in an application, the result will be notified from the statusReceiver object. + * @param bundleName Indicates the bundle name of the module to uninstall. + * @param modulePackage Indicates the module package of the module to uninstall. + * @param installParam Indicates the uninstall parameters. + * @param statusReceiver Indicates the callback object that using for notifing the uninstall result. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool Uninstall(const std::string &bundleName, const std::string &modulePackage, + const InstallParam &installParam, const sptr &statusReceiver) = 0; + + enum class Message { + INSTALL, + UNINSTALL, + UNINSTALL_MODULE, + }; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_BUNDLEMGR_BUNDLE_INSTALLER_INTERFACE_H \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_installer_proxy.h b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_installer_proxy.h new file mode 100644 index 000000000..1f4ee61b6 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_installer_proxy.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_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_BUNDLEMGR_BUNDLE_INSTALLER_PROXY_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_BUNDLEMGR_BUNDLE_INSTALLER_PROXY_H + +#include "iremote_proxy.h" + +#include "bundle_installer_interface.h" +#include "status_receiver_interface.h" + +namespace OHOS { +namespace AppExecFwk { + +class BundleInstallerProxy : public IRemoteProxy { +public: + explicit BundleInstallerProxy(const sptr &object); + virtual ~BundleInstallerProxy() override; + /** + * @brief Installs an application through the proxy object. + * @attention Notice that the bundleFilePath should be an absolute path. + * @param bundleFilePath Indicates the path for storing the ohos Ability Package (HAP) of the application + * to install or update. + * @param installParam Indicates the install parameters. + * @param statusReceiver Indicates the callback object that using for notifing the install result. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool Install(const std::string &bundleFilePath, const InstallParam &installParam, + const sptr &statusReceiver) override; + /** + * @brief Uninstalls an application through the proxy object. + * @param bundleName Indicates the bundle name of the application to uninstall. + * @param installParam Indicates the uninstall parameters. + * @param statusReceiver Indicates the callback object that using for notifing the uninstall result. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool Uninstall(const std::string &bundleName, const InstallParam &installParam, + const sptr &statusReceiver) override; + /** + * @brief Uninstalls a module in an application through the proxy object. + * @param bundleName Indicates the bundle name of the module to uninstall. + * @param modulePackage Indicates the module package of the module to uninstall. + * @param installParam Indicates the uninstall parameters. + * @param statusReceiver Indicates the callback object that using for notifing the uninstall result. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool Uninstall(const std::string &bundleName, const std::string &modulePackage, + const InstallParam &installParam, const sptr &statusReceiver) override; + +private: + static inline BrokerDelegator delegator_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_BUNDLEMGR_BUNDLE_INSTALLER_PROXY_H \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_mgr_host.h b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_mgr_host.h new file mode 100644 index 000000000..7733df158 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_mgr_host.h @@ -0,0 +1,301 @@ +/* + * 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_BUNDLEMGR_BUNDLE_MGR_HOST_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_BUNDLEMGR_BUNDLE_MGR_HOST_H + +#include + +#include "iremote_stub.h" +#include "nocopyable.h" + +#include "appexecfwk_errors.h" +#include "bundle_mgr_interface.h" +#include "bundle_mgr_proxy.h" + +namespace OHOS { +namespace AppExecFwk { + +class BundleMgrHost : public IRemoteStub { +public: + BundleMgrHost() = default; + virtual ~BundleMgrHost() = default; + + int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + /** + * @attention This function is implement in the proxy side. + */ + virtual int GetUidByBundleName([[maybe_unused]] const std::string &bundleName, const int userId) override; + /** + * @attention This function is implement in the proxy side. + */ + virtual std::string GetAppType([[maybe_unused]] const std::string &bundleName) override; + +private: + /** + * @brief Handles the GetApplicationInfo 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 HandleGetApplicationInfo(Parcel &data, Parcel &reply); + /** + * @brief Handles the GetApplicationInfos 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 HandleGetApplicationInfos(Parcel &data, Parcel &reply); + /** + * @brief Handles the GetBundleInfo 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 HandleGetBundleInfo(Parcel &data, Parcel &reply); + /** + * @brief Handles the GetBundleInfos 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 HandleGetBundleInfos(Parcel &data, Parcel &reply); + /** + * @brief Handles the GetBundleNameForUid 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 HandleGetBundleNameForUid(Parcel &data, Parcel &reply); + /** + * @brief Handles the GetBundleGids 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 HandleGetBundleGids(Parcel &data, Parcel &reply); + /** + * @brief Handles the GetBundleInfosByMetaData 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 HandleGetBundleInfosByMetaData(Parcel &data, Parcel &reply); + /** + * @brief Handles the QueryAbilityInfo 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 HandleQueryAbilityInfo(Parcel &data, Parcel &reply); + /** + * @brief Handles the QueryAbilityInfoByUri 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 HandleQueryAbilityInfoByUri(Parcel &data, Parcel &reply); + /** + * @brief Handles the QueryKeepAliveBundleInfos 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 HandleQueryKeepAliveBundleInfos(Parcel &data, Parcel &reply); + /** + * @brief Handles the GetAbilityLabel 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 HandleGetAbilityLabel(Parcel &data, Parcel &reply); + /** + * @brief Handles the CheckIsSystemAppByUid 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 HandleCheckIsSystemAppByUid(Parcel &data, Parcel &reply); + /** + * @brief Handles the GetBundleArchiveInfo 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 HandleGetBundleArchiveInfo(Parcel &data, Parcel &reply); + /** + * @brief Handles the GetHapModuleInfo 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 HandleGetHapModuleInfo(Parcel &data, Parcel &reply); + /** + * @brief Handles the GetLaunchWantForBundle 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 HandleGetLaunchWantForBundle(Parcel &data, Parcel &reply); + /** + * @brief Handles the CheckPublicKeys 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 HandleCheckPublicKeys(Parcel &data, Parcel &reply); + /** + * @brief Handles the CheckPermission 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 HandleCheckPermission(Parcel &data, Parcel &reply); + /** + * @brief Handles the GetPermissionDef 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 HandleGetPermissionDef(Parcel &data, Parcel &reply); + /** + * @brief Handles the GetAllPermissionGroupDefs 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 HandleGetAllPermissionGroupDefs(Parcel &data, Parcel &reply); + /** + * @brief Handles the GetAppsGrantedPermissions 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 HandleGetAppsGrantedPermissions(Parcel &data, Parcel &reply); + /** + * @brief Handles the HasSystemCapability 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 HandleHasSystemCapability(Parcel &data, Parcel &reply); + /** + * @brief Handles the GetSystemAvailableCapabilities 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 HandleGetSystemAvailableCapabilities(Parcel &data, Parcel &reply); + /** + * @brief Handles the IsSafeMode 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 HandleIsSafeMode(Parcel &data, Parcel &reply); + /** + * @brief Handles the CleanBundleCacheFiles 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 HandleCleanBundleCacheFiles(Parcel &data, Parcel &reply); + /** + * @brief Handles the CleanBundleDataFiles 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 HandleCleanBundleDataFiles(Parcel &data, Parcel &reply); + /** + * @brief Handles the RegisterBundleStatusCallback 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 HandleRegisterBundleStatusCallback(Parcel &data, Parcel &reply); + /** + * @brief Handles the ClearBundleStatusCallback 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 HandleClearBundleStatusCallback(Parcel &data, Parcel &reply); + /** + * @brief Handles the UnregisterBundleStatusCallback 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 HandleUnregisterBundleStatusCallback(Parcel &data, Parcel &reply); + /** + * @brief Handles the DumpInfos 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 HandleDumpInfos(Parcel &data, Parcel &reply); + /** + * @brief Handles the GetBundleInstaller 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 HandleGetBundleInstaller(Parcel &data, Parcel &reply); + /** + * @brief Handles the IsApplicationEnabled 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 HandleIsApplicationEnabled(Parcel &data, Parcel &reply); + /** + * @brief Handles the SetApplicationEnabled 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 HandleSetApplicationEnabled(Parcel &data, Parcel &reply); + /** + * @brief Handles the CanRequestPermission 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 HandleCanRequestPermission(Parcel &data, Parcel &reply); + /** + * @brief Handles the RequestPermissionFromUser 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 HandleRequestPermissionFromUser(Parcel &data, Parcel &reply); + +private: + /** + * @brief Write a parcelabe vector objects to the proxy node. + * @param parcelableVector Indicates the objects to be write. + * @param reply Indicates the reply to be sent; + * @return Returns true if objects send successfully; returns false otherwise. + */ + template + bool WriteParcelableVector(std::vector &parcelableVector, Parcel &reply); + + DISALLOW_COPY_AND_MOVE(BundleMgrHost); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_BUNDLEMGR_BUNDLE_MGR_HOST_H \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_mgr_interface.h b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_mgr_interface.h new file mode 100644 index 000000000..eaedafe69 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_mgr_interface.h @@ -0,0 +1,345 @@ +/* + * 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_BUNDLEMGR_BUNDLE_MGR_INTERFACE_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_BUNDLEMGR_BUNDLE_MGR_INTERFACE_H + +#include "ability_info.h" +#include "application_info.h" +#include "bundle_info.h" +#include "hap_module_info.h" +#include "permission_def.h" +#include "bundle_installer_interface.h" +#include "bundle_status_callback_interface.h" +#include "clean_cache_callback_interface.h" +#include "ohos/aafwk/content/want.h" + +namespace OHOS { +namespace AppExecFwk { + +enum class DumpFlag { + DUMP_BUNDLE_LIST = 1, // corresponse to option "-bundle-list" + DUMP_ALL_BUNDLE_INFO, // corresponse to option "-bundle" + DUMP_BUNDLE_INFO, // corresponse to option "-bundle [name]" +}; + +class IBundleMgr : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.appexecfwk.BundleMgr"); + + using Want = OHOS::AAFwk::Want; + /** + * @brief Obtains the ApplicationInfo based on a given bundle name. + * @param appName 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 appInfo Indicates the obtained ApplicationInfo object. + * @return Returns true if the application is successfully obtained; returns false otherwise. + */ + virtual bool GetApplicationInfo( + const std::string &appName, const ApplicationFlag flag, const int userId, ApplicationInfo &appInfo) = 0; + /** + * @brief Obtains information about all installed applications of a specified user. + * @param flag Indicates the flag used to specify information contained + * in the ApplicationInfo objects that will be returned. + * @param userId Indicates the user ID. + * @param appInfos Indicates all of the obtained ApplicationInfo objects. + * @return Returns true if the application is successfully obtained; returns false otherwise. + */ + virtual bool GetApplicationInfos( + const ApplicationFlag flag, const int userId, std::vector &appInfos) = 0; + /** + * @brief Obtains the BundleInfo based on a given bundle name. + * @param bundleName Indicates the application bundle name to be queried. + * @param flag Indicates the information contained in the BundleInfo object to be returned. + * @param bundleInfo Indicates the obtained BundleInfo object. + * @return Returns true if the BundleInfo is successfully obtained; returns false otherwise. + */ + virtual bool GetBundleInfo(const std::string &bundleName, const BundleFlag flag, BundleInfo &bundleInfo) = 0; + /** + * @brief Obtains BundleInfo of all bundles available in the system. + * @param flag Indicates the flag used to specify information contained in the BundleInfo that will be returned. + * @param bundleInfos Indicates all of the obtained BundleInfo objects. + * @return Returns true if the BundleInfos is successfully obtained; returns false otherwise. + */ + virtual bool GetBundleInfos(const BundleFlag flag, std::vector &bundleInfos) = 0; + /** + * @brief Obtains the application UID based on the given bundle name and user ID. + * @param bundleName Indicates the bundle name of the application. + * @param userId Indicates the user ID. + * @return Returns the uid if successfully obtained; returns -1 otherwise. + */ + virtual int GetUidByBundleName(const std::string &bundleName, const int userId) = 0; + /** + * @brief Obtains the bundle name of a specified application based on the given UID. + * @param uid Indicates the uid. + * @param bundleName Indicates the obtained bundle name. + * @return Returns true if the bundle name is successfully obtained; returns false otherwise. + */ + virtual bool GetBundleNameForUid(const int uid, std::string &bundleName) = 0; + /** + * @brief Obtains an array of all group IDs associated with a specified bundle. + * @param bundleName Indicates the bundle name. + * @param gids Indicates the group IDs associated with the specified bundle. + * @return Returns true if the gids is successfully obtained; returns false otherwise. + */ + virtual bool GetBundleGids(const std::string &bundleName, std::vector &gids) = 0; + /** + * @brief Obtains the type of a specified application based on the given bundle name. + * @param bundleName Indicates the bundle name. + * @return Returns "system" if the bundle is a system application; returns "third-party" otherwise. + */ + virtual std::string GetAppType(const std::string &bundleName) = 0; + /** + * @brief Check whether the app is system app by it's UID. + * @param uid Indicates the uid. + * @return Returns true if the bundle is a system application; returns false otherwise. + */ + virtual bool CheckIsSystemAppByUid(const int uid) = 0; + /** + * @brief Obtains the BundleInfo of application bundles based on the specified metaData. + * @param metaData Indicates the metadata to get in the bundle. + * @param bundleInfos Indicates all of the obtained BundleInfo objects. + * @return Returns true if the BundleInfos is successfully obtained; returns false otherwise. + */ + virtual bool GetBundleInfosByMetaData(const std::string &metaData, std::vector &bundleInfos) = 0; + /** + * @brief Query the AbilityInfo by the given Want. + * @param want Indicates the information of the ability. + * @param abilityInfo Indicates the obtained AbilityInfo object. + * @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 by ability.uri in config.json. + * @param abilityUri Indicates the uri of the ability. + * @param abilityInfo Indicates the obtained AbilityInfo object. + * @return Returns true if the AbilityInfo is successfully obtained; returns false otherwise. + */ + virtual bool QueryAbilityInfoByUri(const std::string &abilityUri, AbilityInfo &abilityInfo) = 0; + /** + * @brief Obtains the BundleInfo of all keep-alive applications in the system. + * @param bundleInfos Indicates all of the obtained BundleInfo objects. + * @return Returns true if the BundleInfos is successfully obtained; returns false otherwise. + */ + virtual bool QueryKeepAliveBundleInfos(std::vector &bundleInfos) = 0; + /** + * @brief Obtains the label of a specified ability. + * @param bundleName Indicates the bundle name. + * @param className Indicates the ability class name. + * @return Returns the label of the ability if exist; returns empty string otherwise. + */ + virtual std::string GetAbilityLabel(const std::string &bundleName, const std::string &className) = 0; + /** + * @brief Obtains information about an application bundle contained in an ohos Ability Package (HAP). + * @param hapFilePath Indicates the absolute file path of the HAP. + * @param flag Indicates the information contained in the BundleInfo object to be returned. + * @param bundleInfo Indicates the obtained BundleInfo object. + * @return Returns true if the BundleInfo is successfully obtained; returns false otherwise. + */ + virtual bool GetBundleArchiveInfo( + const std::string &hapFilePath, const BundleFlag flag, BundleInfo &bundleInfo) = 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) = 0; + /** + * @brief Obtains the Want for starting the main ability of an application based on the given bundle name. + * @param bundleName Indicates the bundle name. + * @param want Indicates the obtained launch Want object. + * @return Returns true if the launch Want object is successfully obtained; returns false otherwise. + */ + virtual bool GetLaunchWantForBundle(const std::string &bundleName, Want &want) = 0; + /** + * @brief Checks whether the publickeys of two bundles are the same. + * @param firstBundleName Indicates the first bundle name. + * @param secondBundleName Indicates the second bundle name. + * @return Returns SIGNATURE_UNKNOWN_BUNDLE if at least one of the given bundles is not found; + * returns SIGNATURE_NOT_MATCHED if their publickeys are different; + * returns SIGNATURE_MATCHED if their publickeys are the same. + */ + virtual int CheckPublicKeys(const std::string &firstBundleName, const std::string &secondBundleName) = 0; + /** + * @brief Checks whether a specified bundle has been granted a specific permission. + * @param bundleName Indicates the name of the bundle to check. + * @param permission Indicates the permission to check. + * @return Returns 0 if the bundle has the permission; returns -1 otherwise. + */ + virtual int CheckPermission(const std::string &bundleName, const std::string &permission) = 0; + /** + * @brief Obtains detailed information about a specified permission. + * @param permissionName Indicates the name of the ohos permission. + * @param permissionDef Indicates the object containing detailed information about the given ohos permission. + * @return Returns true if the PermissionDef object is successfully obtained; returns false otherwise. + */ + virtual bool GetPermissionDef(const std::string &permissionName, PermissionDef &permissionDef) = 0; + /** + * @brief Obtains all known permission groups in the system. + * @param permissionDefs Indicates the list of objects containing the permission group information. + * @return Returns true if the PermissionDef objects is successfully obtained; returns false otherwise. + */ + virtual bool GetAllPermissionGroupDefs(std::vector &permissionDefs) = 0; + /** + * @brief Obtains all known permission groups in the system. + * @param permissions Indicates the permission array. + * @param appNames Indicates the list of application names that have the specified permissions. + * @return Returns true if the application names is successfully obtained; returns false otherwise. + */ + virtual bool GetAppsGrantedPermissions( + const std::vector &permissions, std::vector &appNames) = 0; + /** + * @brief Checks whether the system has a specified capability. + * @param capName Indicates the name of the system feature to check. + * @return Returns true if the given feature specified by name is available in the system; returns false otherwise. + */ + virtual bool HasSystemCapability(const std::string &capName) = 0; + /** + * @brief Obtains the capabilities that are available in the system. + * @param systemCaps Indicates the list of capabilities available in the system. + * @return Returns true if capabilities in the system are successfully obtained; returns false otherwise. + */ + virtual bool GetSystemAvailableCapabilities(std::vector &systemCaps) = 0; + /** + * @brief Checks whether the current device has been started in safe mode. + * @return Returns true if the device is in safe mode; returns false otherwise. + */ + virtual bool IsSafeMode() = 0; + /** + * @brief Clears cache data of a specified application. + * @param bundleName Indicates the bundle name of the application whose cache data is to be cleared. + * @param cleanCacheCallback Indicates the callback to be invoked for returning the operation result. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool CleanBundleCacheFiles( + const std::string &bundleName, const sptr &cleanCacheCallback) = 0; + /** + * @brief Clears application running data of a specified application. + * @param bundleName Indicates the bundle name of the application whose data is to be cleared. + * @return Returns true if the data cleared successfully; returns false otherwise. + */ + virtual bool CleanBundleDataFiles(const std::string &bundleName) = 0; + /** + * @brief Register the specific bundle status callback. + * @param bundleStatusCallback Indicates the callback to be invoked for returning the bundle status changed result. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool RegisterBundleStatusCallback(const sptr &bundleStatusCallback) = 0; + /** + * @brief Clear the specific bundle status callback. + * @param bundleStatusCallback Indicates the callback to be cleared. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool ClearBundleStatusCallback(const sptr &bundleStatusCallback) = 0; + /** + * @brief Unregister all the callbacks of status changed. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool UnregisterBundleStatusCallback() = 0; + /** + * @brief Dump the bundle informations with specific flags. + * @param flag Indicates the information contained in the dump result. + * @param bundleName Indicates the bundle name if needed. + * @param result Indicates the dump information result. + * @return Returns true if the dump result is successfully obtained; returns false otherwise. + */ + virtual bool DumpInfos(const DumpFlag flag, const std::string &bundleName, std::string &result) = 0; + /** + * @brief Checks whether a specified application is enabled. + * @param bundleName Indicates the bundle name of the application. + * @return Returns true if the application is enabled; returns false otherwise. + */ + virtual bool IsApplicationEnabled(const std::string &bundleName) = 0; + /** + * @brief Sets whether to enable a specified application. + * @param bundleName Indicates the bundle name of the application. + * @param isEnable Specifies whether to enable the application. + * The value true means to enable it, and the value false means to disable it. + * @return Returns true if the application is enabled; returns false otherwise. + */ + virtual bool SetApplicationEnabled(const std::string &bundleName, bool isEnable) = 0; + /** + * @brief Confirms with the permission management module to check whether a request prompt is required for granting + * a certain permission. + * @param bundleName Indicates the name of the bundle to check. + * @param permission Indicates the permission to check. + * @param userId Indicates the user id. + * @return Returns true if the current application does not have the permission and the user does not turn off + * further requests; returns false if the current application already has the permission, the permission is rejected + * by the system, or the permission is denied by the user and the user has turned off further requests. + */ + virtual bool CanRequestPermission( + const std::string &bundleName, const std::string &permissionName, const int userId) = 0; + /** + * @brief Requests a certain permission from user. + * @param bundleName Indicates the name of the bundle to request permission. + * @param permission Indicates the permission to request permission. + * @param userId Indicates the user id. + * @return Returns true if the permission request successfully; returns false otherwise. + */ + virtual bool RequestPermissionFromUser( + const std::string &bundleName, const std::string &permission, const int userId) = 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; + + enum class Message { + GET_APPLICATION_INFO, + GET_APPLICATION_INFOS, + GET_BUNDLE_INFO, + GET_BUNDLE_INFOS, + GET_UID_BY_BUNDLE_NAME, + GET_BUNDLE_NAME_FOR_UID, + GET_BUNDLE_GIDS, + GET_APP_TYPE, + CHECK_IS_SYSTEM_APP_BY_UID, + GET_BUNDLE_INFOS_BY_METADATA, + QUERY_ABILITY_INFO, + QUERY_ABILITY_INFO_BY_URI, + QUERY_KEEPALIVE_BUNDLE_INFOS, + GET_ABILITY_LABEL, + GET_BUNDLE_ARCHIVE_INFO, + GET_HAP_MODULE_INFO, + GET_LAUNCH_WANT_FOR_BUNDLE, + CHECK_PUBLICKEYS, + CHECK_PERMISSION, + GET_PERMISSION_DEF, + GET_ALL_PERMISSION_GROUP_DEFS, + GET_APPS_GRANTED_PERMISSIONS, + HAS_SYSTEM_CAPABILITY, + GET_SYSTEM_AVAILABLE_CAPABILITIES, + IS_SAFE_MODE, + CLEAN_BUNDLE_CACHE_FILES, + CLEAN_BUNDLE_DATA_FILES, + REGISTER_BUNDLE_STATUS_CALLBACK, + CLEAR_BUNDLE_STATUS_CALLBACK, + UNREGISTER_BUNDLE_STATUS_CALLBACK, + DUMP_INFOS, + IS_APPLICATION_ENABLED, + SET_APPLICATION_ENABLED, + CAN_REQUEST_PERMISSION, + REQUEST_PERMISSION_FROM_USER, + GET_BUNDLE_INSTALLER, + }; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_BUNDLEMGR_BUNDLE_MGR_INTERFACE_H diff --git a/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_mgr_proxy.h b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_mgr_proxy.h new file mode 100644 index 000000000..39a945fde --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_mgr_proxy.h @@ -0,0 +1,329 @@ +/* + * 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_BUNDLEMGR_BUNDLE_MGR_PROXY_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_BUNDLEMGR_BUNDLE_MGR_PROXY_H + +#include + +#include "iremote_proxy.h" + +#include "bundle_mgr_interface.h" +#include "element_name.h" +#include "bundle_status_callback_interface.h" +#include "clean_cache_callback_interface.h" + +namespace OHOS { +namespace AppExecFwk { + +class BundleMgrProxy : public IRemoteProxy { +public: + explicit BundleMgrProxy(const sptr &impl); + virtual ~BundleMgrProxy() override; + /** + * @brief Obtains the ApplicationInfo based on a given bundle name through the proxy object. + * @param appName 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 appInfo Indicates the obtained ApplicationInfo object. + * @return Returns true if the application is successfully obtained; returns false otherwise. + */ + virtual bool GetApplicationInfo( + const std::string &appName, const ApplicationFlag flag, const int userId, ApplicationInfo &appInfo) override; + /** + * @brief Obtains information about all installed applications of a specified user through the proxy object. + * @param flag Indicates the flag used to specify information contained + * in the ApplicationInfo objects that will be returned. + * @param userId Indicates the user ID. + * @param appInfos Indicates all of the obtained ApplicationInfo objects. + * @return Returns true if the application is successfully obtained; returns false otherwise. + */ + virtual bool GetApplicationInfos( + const ApplicationFlag flag, const int userId, std::vector &appInfos) override; + /** + * @brief Obtains the BundleInfo based on a given bundle name through the proxy object. + * @param bundleName Indicates the application bundle name to be queried. + * @param flag Indicates the information contained in the BundleInfo object to be returned. + * @param bundleInfo Indicates the obtained BundleInfo object. + * @return Returns true if the BundleInfo is successfully obtained; returns false otherwise. + */ + virtual bool GetBundleInfo(const std::string &bundleName, const BundleFlag flag, BundleInfo &bundleInfo) override; + /** + * @brief Obtains BundleInfo of all bundles available in the system through the proxy object. + * @param flag Indicates the flag used to specify information contained in the BundleInfo that will be returned. + * @param bundleInfos Indicates all of the obtained BundleInfo objects. + * @return Returns true if the BundleInfos is successfully obtained; returns false otherwise. + */ + virtual bool GetBundleInfos(const BundleFlag flag, std::vector &bundleInfos) override; + /** + * @brief Obtains the application UID based on the given bundle name and user ID through the proxy object. + * @param bundleName Indicates the bundle name of the application. + * @param userId Indicates the user ID. + * @return Returns the uid if successfully obtained; returns -1 otherwise. + */ + virtual int GetUidByBundleName(const std::string &bundleName, const int userId) override; + /** + * @brief Obtains the bundle name of a specified application based on the given UID through the proxy object. + * @param uid Indicates the uid. + * @param bundleName Indicates the obtained bundle name. + * @return Returns true if the bundle name is successfully obtained; returns false otherwise. + */ + virtual bool GetBundleNameForUid(const int uid, std::string &bundleName) override; + /** + * @brief Obtains an array of all group IDs associated with a specified bundle through the proxy object. + * @param bundleName Indicates the bundle name. + * @param gids Indicates the group IDs associated with the specified bundle. + * @return Returns true if the gids is successfully obtained; returns false otherwise. + */ + virtual bool GetBundleGids(const std::string &bundleName, std::vector &gids) override; + /** + * @brief Obtains the type of a specified application based on the given bundle name through the proxy object. + * @param bundleName Indicates the bundle name. + * @return Returns "system" if the bundle is a system application; returns "third-party" otherwise. + */ + virtual std::string GetAppType(const std::string &bundleName) override; + /** + * @brief Check whether the app is system app by it's UID through the proxy object. + * @param uid Indicates the uid. + * @return Returns true if the bundle is a system application; returns false otherwise. + */ + virtual bool CheckIsSystemAppByUid(const int uid) override; + /** + * @brief Obtains the BundleInfo of application bundles based on the specified metaData through the proxy object. + * @param metaData Indicates the metadata to get in the bundle. + * @param bundleInfos Indicates all of the obtained BundleInfo objects. + * @return Returns true if the BundleInfos is successfully obtained; returns false otherwise. + */ + virtual bool GetBundleInfosByMetaData(const std::string &metaData, std::vector &bundleInfos) override; + /** + * @brief Query the AbilityInfo by the given Want through the proxy object. + * @param want Indicates the information of the ability. + * @param abilityInfo Indicates the obtained AbilityInfo object. + * @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 by ability.uri in config.json through the proxy object. + * @param abilityUri Indicates the uri of the ability. + * @param abilityInfo Indicates the obtained AbilityInfo object. + * @return Returns true if the AbilityInfo is successfully obtained; returns false otherwise. + */ + virtual bool QueryAbilityInfoByUri(const std::string &abilityUri, AbilityInfo &abilityInfo) override; + /** + * @brief Obtains the BundleInfo of all keep-alive applications in the system through the proxy object. + * @param bundleInfos Indicates all of the obtained BundleInfo objects. + * @return Returns true if the BundleInfos is successfully obtained; returns false otherwise. + */ + virtual bool QueryKeepAliveBundleInfos(std::vector &bundleInfos) override; + /** + * @brief Obtains the label of a specified ability through the proxy object. + * @param bundleName Indicates the bundle name. + * @param className Indicates the ability class name. + * @return Returns the label of the ability if exist; returns empty string otherwise. + */ + virtual std::string GetAbilityLabel(const std::string &bundleName, const std::string &className) override; + /** + * @brief Obtains information about an application bundle contained + * in an ohos Ability Package (HAP) through the proxy object. + * @param hapFilePath Indicates the absolute file path of the HAP. + * @param flag Indicates the information contained in the BundleInfo object to be returned. + * @param bundleInfo Indicates the obtained BundleInfo object. + * @return Returns true if the BundleInfo is successfully obtained; returns false otherwise. + */ + virtual bool GetBundleArchiveInfo( + const std::string &hapFilePath, const BundleFlag flag, BundleInfo &bundleInfo) override; + /** + * @brief Obtain the HAP module info of a specific ability through the proxy object. + * @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; + /** + * @brief Obtains the Want for starting the main ability of an application + * based on the given bundle name through the proxy object. + * @param bundleName Indicates the bundle name. + * @param want Indicates the obtained launch Want object. + * @return Returns true if the launch Want object is successfully obtained; returns false otherwise. + */ + virtual bool GetLaunchWantForBundle(const std::string &bundleName, Want &want) override; + /** + * @brief Checks whether the publickeys of two bundles are the same through the proxy object. + * @param firstBundleName Indicates the first bundle name. + * @param secondBundleName Indicates the second bundle name. + * @return Returns SIGNATURE_UNKNOWN_BUNDLE if at least one of the given bundles is not found; + * returns SIGNATURE_NOT_MATCHED if their publickeys are different; + * returns SIGNATURE_MATCHED if their publickeys are the same. + */ + virtual int CheckPublicKeys(const std::string &firstBundleName, const std::string &secondBundleName) override; + /** + * @brief Checks whether a specified bundle has been granted a specific permission through the proxy object. + * @param bundleName Indicates the name of the bundle to check. + * @param permission Indicates the permission to check. + * @return Returns 0 if the bundle has the permission; returns -1 otherwise. + */ + virtual int CheckPermission(const std::string &bundleName, const std::string &permission) override; + /** + * @brief Obtains detailed information about a specified permission through the proxy object. + * @param permissionName Indicates the name of the ohos permission. + * @param permissionDef Indicates the object containing detailed information about the given ohos permission. + * @return Returns true if the PermissionDef object is successfully obtained; returns false otherwise. + */ + virtual bool GetPermissionDef(const std::string &permissionName, PermissionDef &permissionDef) override; + /** + * @brief Obtains all known permission groups in the system through the proxy object. + * @param permissionDefs Indicates the list of objects containing the permission group information. + * @return Returns true if the PermissionDef objects is successfully obtained; returns false otherwise. + */ + virtual bool GetAllPermissionGroupDefs(std::vector &permissionDefs) override; + /** + * @brief Obtains all known permission groups in the system through the proxy object. + * @param permissions Indicates the permission array. + * @param appNames Indicates the list of application names that have the specified permissions. + * @return Returns true if the application names is successfully obtained; returns false otherwise. + */ + virtual bool GetAppsGrantedPermissions( + const std::vector &permissions, std::vector &appNames) override; + /** + * @brief Checks whether the system has a specified capability through the proxy object. + * @param capName Indicates the name of the system feature to check. + * @return Returns true if the given feature specified by name is available in the system; returns false otherwise. + */ + virtual bool HasSystemCapability(const std::string &capName) override; + /** + * @brief Obtains the capabilities that are available in the system through the proxy object. + * @param systemCaps Indicates the list of capabilities available in the system. + * @return Returns true if capabilities in the system are successfully obtained; returns false otherwise. + */ + virtual bool GetSystemAvailableCapabilities(std::vector &systemCaps) override; + /** + * @brief Checks whether the current device has been started in safe mode through the proxy object. + * @return Returns true if the device is in safe mode; returns false otherwise. + */ + virtual bool IsSafeMode() override; + /** + * @brief Clears cache data of a specified application through the proxy object. + * @param bundleName Indicates the bundle name of the application whose cache data is to be cleared. + * @param cleanCacheCallback Indicates the callback to be invoked for returning the operation result. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool CleanBundleCacheFiles( + const std::string &bundleName, const sptr &cleanCacheCallback) override; + /** + * @brief Clears application running data of a specified application through the proxy object. + * @param bundleName Indicates the bundle name of the application whose data is to be cleared. + * @return Returns true if the data cleared successfully; returns false otherwise. + */ + virtual bool CleanBundleDataFiles(const std::string &bundleName) override; + /** + * @brief Register the specific bundle status callback through the proxy object. + * @param bundleStatusCallback Indicates the callback to be invoked for returning the bundle status changed result. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool RegisterBundleStatusCallback(const sptr &bundleStatusCallback) override; + /** + * @brief Clear the specific bundle status callback through the proxy object. + * @param bundleStatusCallback Indicates the callback to be cleared. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool ClearBundleStatusCallback(const sptr &bundleStatusCallback) override; + /** + * @brief Unregister all the callbacks of status changed through the proxy object. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool UnregisterBundleStatusCallback() override; + /** + * @brief Dump the bundle informations with specific flags through the proxy object. + * @param flag Indicates the information contained in the dump result. + * @param bundleName Indicates the bundle name if needed. + * @param result Indicates the dump information result. + * @return Returns true if the dump result is successfully obtained; returns false otherwise. + */ + virtual bool DumpInfos(const DumpFlag flag, const std::string &bundleName, std::string &result) override; + /** + * @brief Checks whether a specified application is enabled through the proxy object. + * @param bundleName Indicates the bundle name of the application. + * @return Returns true if the application is enabled; returns false otherwise. + */ + virtual bool IsApplicationEnabled(const std::string &bundleName) override; + /** + * @brief Sets whether to enable a specified application through the proxy object. + * @param bundleName Indicates the bundle name of the application. + * @param isEnable Specifies whether to enable the application. + * The value true means to enable it, and the value false means to disable it. + * @return Returns true if the application is enabled; returns false otherwise. + */ + virtual bool SetApplicationEnabled(const std::string &bundleName, bool isEnable) override; + /** + * @brief Obtains the interface used to install and uninstall bundles through the proxy object. + * @return Returns a pointer to IBundleInstaller class if exist; returns nullptr otherwise. + */ + virtual sptr GetBundleInstaller() override; + /** + * @brief Confirms with the permission management module to check whether a request prompt is required for granting + * a certain permission. + * @param bundleName Indicates the name of the bundle to check through the proxy object. + * @param permission Indicates the permission to check. + * @param userId Indicates the user id. + * @return Returns true if the current application does not have the permission and the user does not turn off + * further requests; returns false if the current application already has the permission, the permission is rejected + * by the system, or the permission is denied by the user and the user has turned off further requests. + */ + virtual bool CanRequestPermission( + const std::string &bundleName, const std::string &permissionName, const int userId) override; + /** + * @brief Requests a certain permission from user through the proxy object. + * @param bundleName Indicates the name of the bundle to request permission. + * @param permission Indicates the permission to request permission. + * @param userId Indicates the user id. + * @return Returns true if the permission request successfully; returns false otherwise. + */ + virtual bool RequestPermissionFromUser( + const std::string &bundleName, const std::string &permission, const int userId) override; + +private: + /** + * @brief Send a command message from the proxy object. + * @param code Indicates the message code to be sent. + * @param data Indicates the objects to be sent. + * @param reply Indicates the reply to be sent; + * @return Returns true if message send successfully; returns false otherwise. + */ + bool SendTransactCmd(IBundleMgr::Message code, MessageParcel &data, MessageParcel &reply); + /** + * @brief Send a command message and then get a parcelable information object from the reply. + * @param code Indicates the message code to be sent. + * @param data Indicates the objects to be sent. + * @param parcelableInfo Indicates the object to be got; + * @return Returns true if objects get successfully; returns false otherwise. + */ + template + bool GetParcelableInfo(IBundleMgr::Message code, MessageParcel &data, T &parcelableInfo); + /** + * @brief Send a command message and then get a vector of parcelable information objects from the reply. + * @param code Indicates the message code to be sent. + * @param data Indicates the objects to be sent. + * @param parcelableInfos Indicates the vector objects to be got; + * @return Returns true if the vector get successfully; returns false otherwise. + */ + template + bool GetParcelableInfos(IBundleMgr::Message code, MessageParcel &data, std::vector &parcelableInfos); + static inline BrokerDelegator delegator_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_BUNDLEMGR_BUNDLE_MGR_PROXY_H \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_status_callback_host.h b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_status_callback_host.h new file mode 100644 index 000000000..1292d4a5e --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_status_callback_host.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_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_BUNDLE_STATUS_CALLBACK_HOST_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_BUNDLE_STATUS_CALLBACK_HOST_H + +#include "iremote_stub.h" +#include "nocopyable.h" + +#include "bundle_status_callback_interface.h" + +namespace OHOS { +namespace AppExecFwk { + +class BundleStatusCallbackHost : public IRemoteStub { +public: + BundleStatusCallbackHost(); + virtual ~BundleStatusCallbackHost() override; + + int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + +private: + DISALLOW_COPY_AND_MOVE(BundleStatusCallbackHost); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_BUNDLE_STATUS_CALLBACK_HOST_H 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 new file mode 100644 index 000000000..7764cff7c --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_status_callback_interface.h @@ -0,0 +1,66 @@ +/* + * 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_BUNDLE_STATUS_CALLBACK_INTERFACE_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_BUNDLE_STATUS_CALLBACK_INTERFACE_H + +#include "iremote_broker.h" + +namespace OHOS { +namespace AppExecFwk { + +const std::string INSTALL_SUCCESS = "install success !"; +const std::string UNINSTALL_SUCCESS = "uninstall success !"; + +enum class InstallType { INSTALL_CALLBACK, UNINSTALL_CALLBACK }; + +class IBundleStatusCallback : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.appexecfwk.BundleStatusCallback"); + /** + * @brief Called when the installation, update, or uninstallation state of an application changes. + * @param installType Indicates the installation, update, or uninstallation state. + * The value 0 indicates that the application is being installed or updated, + * and 1 indicates that the application is being uninstalled. + * @param resultCode Indicates the status code returned for the application installation, update, or uninstallation + * result. + * @param resultMessage Indicates the result message returned with the status code. + * @param bundleName Indicates the name of the bundle whose state has changed. + */ + virtual void OnBundleStateChanged(const uint8_t installType, const int32_t resultCode, const std::string &resultMsg, + const std::string &bundleName) = 0; + + enum class Message { + ON_BUNDLE_STATE_CHANGED, + }; + + std::string GetBundleName() + { + return bundleName_; + } + + void SetBundleName(const std::string &bundleName) + { + bundleName_ = bundleName; + } + +private: + std::string bundleName_; +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_BUNDLE_STATUS_CALLBACK_INTERFACE_H 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 new file mode 100644 index 000000000..ad8a0dedc --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/bundle_status_callback_proxy.h @@ -0,0 +1,50 @@ +/* + * 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_BUNDLE_STATUS_CALLBACK_PROXY_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_BUNDLE_STATUS_CALLBACK_PROXY_H + +#include "iremote_proxy.h" + +#include "bundle_status_callback_interface.h" + +namespace OHOS { +namespace AppExecFwk { + +class BundleStatusCallbackProxy : public IRemoteProxy { +public: + explicit BundleStatusCallbackProxy(const sptr &object); + virtual ~BundleStatusCallbackProxy() override; + /** + * @brief Called when the installation, update, or uninstallation state of an application changes from proxy side. + * @param installType Indicates the installation, update, or uninstallation state. + * The value 0 indicates that the application is being installed or updated, + * and 1 indicates that the application is being uninstalled. + * @param resultCode Indicates the status code returned for the application installation, update, or uninstallation + * result. + * @param resultMessage Indicates the result message returned with the status code. + * @param bundleName Indicates the name of the bundle whose state has changed. + */ + virtual void OnBundleStateChanged(const uint8_t installType, const int32_t resultCode, const std::string &resultMsg, + const std::string &bundleName) override; + +private: + static inline BrokerDelegator delegator_; +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_BUNDLE_STATUS_CALLBACK_PROXY_H diff --git a/interfaces/innerkits/appexecfwk_core/include/bundlemgr/clean_cache_callback_host.h b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/clean_cache_callback_host.h new file mode 100644 index 000000000..25ea0174a --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/clean_cache_callback_host.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_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_CLEAN_CACHE_CALLBACK_HOST_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_CLEAN_CACHE_CALLBACK_HOST_H + +#include "iremote_stub.h" +#include "nocopyable.h" + +#include "clean_cache_callback_interface.h" + +namespace OHOS { +namespace AppExecFwk { + +class CleanCacheCallbackHost : public IRemoteStub { +public: + CleanCacheCallbackHost(); + virtual ~CleanCacheCallbackHost() override; + + int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + +private: + DISALLOW_COPY_AND_MOVE(CleanCacheCallbackHost); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_CLEAN_CACHE_CALLBACK_HOST_H diff --git a/interfaces/innerkits/appexecfwk_core/include/bundlemgr/clean_cache_callback_interface.h b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/clean_cache_callback_interface.h new file mode 100644 index 000000000..26f92550f --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/clean_cache_callback_interface.h @@ -0,0 +1,42 @@ +/* + * 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_CLEAN_CACHE_CALLBACK_INTERFACE_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_CLEAN_CACHE_CALLBACK_INTERFACE_H + +#include "iremote_broker.h" + +namespace OHOS { +namespace AppExecFwk { + +class ICleanCacheCallback : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.appexecfwk.CleanCacheCallback"); + + /** + * @brief Called when clean cache files progress finished. + * @param succeeded Indicates the result of the clean cache files progress. + */ + virtual void OnCleanCacheFinished(bool succeeded) = 0; + + enum class Message { + ON_CLEAN_CACHE_CALLBACK, + }; +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_CLEAN_CACHE_CALLBACK_INTERFACE_H diff --git a/interfaces/innerkits/appexecfwk_core/include/bundlemgr/clean_cache_callback_proxy.h b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/clean_cache_callback_proxy.h new file mode 100644 index 000000000..319af4a7b --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/clean_cache_callback_proxy.h @@ -0,0 +1,43 @@ +/* + * 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_CLEAN_CACHE_CALLBACK_PROXY_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_CLEAN_CACHE_CALLBACK_PROXY_H + +#include "iremote_proxy.h" + +#include "clean_cache_callback_interface.h" + +namespace OHOS { +namespace AppExecFwk { + +class CleanCacheCallbackProxy : public IRemoteProxy { +public: + explicit CleanCacheCallbackProxy(const sptr &object); + virtual ~CleanCacheCallbackProxy() override; + /** + * @brief Called when clean cache files progress finished through the proxy object. + * @param succeeded Indicates the result of the clean cache files progress. + */ + virtual void OnCleanCacheFinished(bool succeeded) override; + +private: + static inline BrokerDelegator delegator_; +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_CLEAN_CACHE_CALLBACK_PROXY_H diff --git a/interfaces/innerkits/appexecfwk_core/include/bundlemgr/status_receiver_host.h b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/status_receiver_host.h new file mode 100644 index 000000000..c139ab25d --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/status_receiver_host.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_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_BUNDLEMGR_STATUS_RECEIVER_HOST_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_BUNDLEMGR_STATUS_RECEIVER_HOST_H + +#include "iremote_stub.h" +#include "nocopyable.h" + +#include "status_receiver_interface.h" + +namespace OHOS { +namespace AppExecFwk { + +class StatusReceiverHost : public IRemoteStub { +public: + StatusReceiverHost(); + virtual ~StatusReceiverHost() override; + + int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + +private: + DISALLOW_COPY_AND_MOVE(StatusReceiverHost); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_BUNDLEMGR_STATUS_RECEIVER_HOST_H \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_core/include/bundlemgr/status_receiver_interface.h b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/status_receiver_interface.h new file mode 100644 index 000000000..f97a3bf12 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/status_receiver_interface.h @@ -0,0 +1,100 @@ +/* + * 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_BUNDLEMGR_STATUS_RECEIVER_INTERFACE_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_BUNDLEMGR_STATUS_RECEIVER_INTERFACE_H + +#include "iremote_broker.h" + +namespace OHOS { +namespace AppExecFwk { + +class IStatusReceiver : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.appexecfwk.StatusReceiver"); + + /** + * @brief Called when install status changed, with the percentage of installation progress + * @param progress Indicates the percentage of the installation progress. + */ + virtual void OnStatusNotify(const int progress) = 0; + /** + * @brief Called when an application is installed, updated, or uninstalled. + * @param resultCode Indicates the status code returned for the application installation, update, or uninstallation + * result. + * @param resultMsg Indicates the result message returned with the status code. + */ + virtual void OnFinished(const int32_t resultCode, const std::string &resultMsg) = 0; + + enum class Message { + ON_STATUS_NOTIFY, + ON_FINISHED, + }; + + enum { + SUCCESS = 0, + ERR_INSTALL_INTERNAL_ERROR, + ERR_INSTALL_HOST_INSTALLER_FAILED, + ERR_INSTALL_PARSE_FAILED, + ERR_INSTALL_VERSION_DOWNGRADE, + ERR_INSTALL_VERIFICATION_FAILED, + ERR_INSTALL_NO_SIGNATURE_INFO, + ERR_INSTALL_UPDATE_INCOMPATIBLE, + ERR_INSTALL_PARAM_ERROR, + ERR_INSTALL_PERMISSION_DENIED, + ERR_INSTALL_ENTRY_ALREADY_EXIST, + ERR_INSTALL_STATE_ERROR, + ERR_INSTALL_FILE_PATH_INVALID, + ERR_INSTALL_INVALID_HAP_NAME, + ERR_INSTALL_INVALID_BUNDLE_FILE, + ERR_INSTALL_GENERATE_UID_ERROR, + ERR_INSTALL_INSTALLD_SERVICE_ERROR, + ERR_INSTALL_BUNDLE_MGR_SERVICE_ERROR, + ERR_INSTALL_ALREADY_EXIST, + + ERR_INSTALL_PARSE_UNEXPECTED, + ERR_INSTALL_PARSE_MISSING_BUNDLE, + ERR_INSTALL_PARSE_MISSING_ABILITY, + ERR_INSTALL_PARSE_NO_PROFILE, + ERR_INSTALL_PARSE_BAD_PROFILE, + ERR_INSTALL_PARSE_PROFILE_PROP_TYPE_ERROR, + ERR_INSTALL_PARSE_PROFILE_MISSING_PROP, + ERR_INSTALL_PARSE_PERMISSION_ERROR, + + ERR_INSTALLD_PARAM_ERROR, + ERR_INSTALLD_GET_PROXY_ERROR, + ERR_INSTALLD_CREATE_DIR_FAILED, + ERR_INSTALLD_CREATE_DIR_EXIST, + ERR_INSTALLD_CHOWN_FAILED, + ERR_INSTALLD_REMOVE_DIR_FAILED, + ERR_INSTALLD_EXTRACT_FILES_FAILED, + ERR_INSTALLD_RNAME_DIR_FAILED, + ERR_INSTALLD_CLEAN_DIR_FAILED, + + ERR_UNINSTALL_SYSTEM_APP_ERROR, + ERR_UNINSTALL_KILLING_APP_ERROR, + ERR_UNINSTALL_INVALID_NAME, + ERR_UNINSTALL_PARAM_ERROR, + ERR_UNINSTALL_PERMISSION_DENIED, + ERR_UNINSTALL_BUNDLE_MGR_SERVICE_ERROR, + ERR_UNINSTALL_MISSING_INSTALLED_BUNDLE, + ERR_UNINSTALL_MISSING_INSTALLED_MODULE, + ERR_UNKNOWN, + }; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_BUNDLEMGR_STATUS_RECEIVER_INTERFACE_H \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_core/include/bundlemgr/status_receiver_proxy.h b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/status_receiver_proxy.h new file mode 100644 index 000000000..1923a035e --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/include/bundlemgr/status_receiver_proxy.h @@ -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. + */ + +#ifndef FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_BUNDLEMGR_STATUS_RECEIVER_PROXY_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_BUNDLEMGR_STATUS_RECEIVER_PROXY_H + +#include "iremote_proxy.h" + +#include "status_receiver_interface.h" + +namespace OHOS { +namespace AppExecFwk { + +class StatusReceiverProxy : public IRemoteProxy { +public: + explicit StatusReceiverProxy(const sptr &object); + virtual ~StatusReceiverProxy() override; + /** + * @brief Called when install status changed, with the percentage of installation progress + * @param progress Indicates the percentage of the installation progress. + */ + virtual void OnStatusNotify(const int32_t progress) override; + /** + * @brief Called when an application is installed, updated, or uninstalled. + * @param resultCode Indicates the status code returned for the application installation, update, or uninstallation + * result. + * @param resultMsg Indicates the result message returned with the status code. + */ + virtual void OnFinished(const int32_t resultCode, const std::string &resultMsg) override; + +private: + void TransformResult(const int32_t resultCode); + +private: + int32_t resultCode_ = -1; + std::string resultMsg_; + static inline BrokerDelegator delegator_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_BUNDLEMGR_STATUS_RECEIVER_PROXY_H \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_core/src/appmgr/ams_mgr_proxy.cpp b/interfaces/innerkits/appexecfwk_core/src/appmgr/ams_mgr_proxy.cpp new file mode 100644 index 000000000..1c45db4b9 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/appmgr/ams_mgr_proxy.cpp @@ -0,0 +1,246 @@ +/* + * 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 "ams_mgr_proxy.h" + +#include "ipc_types.h" +#include "iremote_object.h" + +#include "appexecfwk_errors.h" +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { + +AmsMgrProxy::AmsMgrProxy(const sptr &impl) : IRemoteProxy(impl) +{} + +bool AmsMgrProxy::WriteInterfaceToken(MessageParcel &data) +{ + if (!data.WriteInterfaceToken(AmsMgrProxy::GetDescriptor())) { + APP_LOGE("write interface token failed"); + return false; + } + return true; +} + +void AmsMgrProxy::LoadAbility(const sptr &token, const sptr &preToken, + const std::shared_ptr &abilityInfo, const std::shared_ptr &appInfo) +{ + APP_LOGD("start"); + if (!abilityInfo || !appInfo) { + APP_LOGE("param error"); + return; + } + + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return; + } + data.WriteParcelable(token); + data.WriteParcelable(preToken); + data.WriteParcelable(abilityInfo.get()); + data.WriteParcelable(appInfo.get()); + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is NULL"); + return; + } + int32_t ret = remote->SendRequest(static_cast(IAmsMgr::Message::AMS_LOAD_ABILITY), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGW("SendRequest is failed, error code: %{public}d", ret); + } + APP_LOGD("end"); +} + +void AmsMgrProxy::TerminateAbility(const sptr &token) +{ + APP_LOGD("start"); + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return; + } + data.WriteParcelable(token.GetRefPtr()); + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is NULL"); + return; + } + int32_t ret = + remote->SendRequest(static_cast(IAmsMgr::Message::AMS_TERMINATE_ABILITY), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGW("SendRequest is failed, error code: %{public}d", ret); + } + APP_LOGD("end"); +} + +void AmsMgrProxy::UpdateAbilityState(const sptr &token, const AbilityState state) +{ + APP_LOGD("start"); + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return; + } + data.WriteParcelable(token.GetRefPtr()); + data.WriteInt32(static_cast(state)); + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is NULL"); + return; + } + int32_t ret = + remote->SendRequest(static_cast(IAmsMgr::Message::AMS_UPDATE_ABILITY_STATE), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGW("SendRequest is failed, error code: %{public}d", ret); + } + APP_LOGD("end"); +} + +void AmsMgrProxy::RegisterAppStateCallback(const sptr &callback) +{ + APP_LOGD("start"); + if (!callback) { + APP_LOGE("callback is nullptr"); + return; + } + + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return; + } + data.WriteParcelable(callback->AsObject()); + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is nullptr"); + return; + } + int32_t ret = remote->SendRequest( + static_cast(IAmsMgr::Message::AMS_REGISTER_APP_STATE_CALLBACK), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGW("SendRequest is failed, error code: %{public}d", ret); + } + APP_LOGD("end"); +} + +void AmsMgrProxy::Reset() +{ + APP_LOGD("start"); + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return; + } + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is NULL"); + return; + } + int32_t ret = remote->SendRequest(static_cast(IAmsMgr::Message::AMS_RESET), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGW("SendRequest is failed, error code: %{public}d", ret); + } + APP_LOGD("end"); +} + +void AmsMgrProxy::AbilityBehaviorAnalysis(const sptr &token, const sptr &preToken, + const int32_t visibility, const int32_t perceptibility, const int32_t connectionState) +{ + APP_LOGD("start"); + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return; + } + data.WriteParcelable(token.GetRefPtr()); + data.WriteParcelable(preToken.GetRefPtr()); + data.WriteInt32(static_cast(visibility)); + data.WriteInt32(static_cast(perceptibility)); + data.WriteInt32(static_cast(connectionState)); + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is NULL"); + return; + } + int32_t ret = + remote->SendRequest(static_cast(IAmsMgr::Message::AMS_TERMINATE_ABILITY), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGW("SendRequest is failed, error code: %{public}d", ret); + } + APP_LOGD("end"); +} + +void AmsMgrProxy::KillProcessByAbilityToken(const sptr &token) +{ + APP_LOGD("start"); + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return; + } + data.WriteParcelable(token.GetRefPtr()); + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is NULL"); + return; + } + int32_t ret = + remote->SendRequest(static_cast(IAmsMgr::Message::AMS_TERMINATE_ABILITY), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGW("SendRequest is failed, error code: %{public}d", ret); + } + APP_LOGD("end"); +} + +int32_t AmsMgrProxy::KillApplication(const std::string &bundleName) +{ + APP_LOGD("start"); + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return ERR_INVALID_DATA; + } + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is NULL"); + return ERR_NULL_OBJECT; + } + if (!data.WriteString(bundleName)) { + APP_LOGE("parcel WriteString failed"); + return ERR_FLATTEN_OBJECT; + } + int32_t ret = + remote->SendRequest(static_cast(IAmsMgr::Message::AMS_KILL_APPLICATION), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGW("SendRequest is failed, error code: %{public}d", ret); + return ret; + } + return reply.ReadInt32(); + APP_LOGD("end"); +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_core/src/appmgr/ams_mgr_stub.cpp b/interfaces/innerkits/appexecfwk_core/src/appmgr/ams_mgr_stub.cpp new file mode 100644 index 000000000..be5bfcfc8 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/appmgr/ams_mgr_stub.cpp @@ -0,0 +1,152 @@ +/* + * 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 "ams_mgr_stub.h" + +#include "ipc_skeleton.h" +#include "ipc_types.h" +#include "iremote_object.h" + +#include "ability_info.h" +#include "appexecfwk_errors.h" +#include "app_log_wrapper.h" +#include "app_mgr_proxy.h" +#include "app_scheduler_interface.h" +#include "iapp_state_callback.h" + +namespace OHOS { +namespace AppExecFwk { + +AmsMgrStub::AmsMgrStub() +{ + memberFuncMap_[static_cast(IAmsMgr::Message::AMS_LOAD_ABILITY)] = &AmsMgrStub::HandleLoadAbility; + memberFuncMap_[static_cast(IAmsMgr::Message::AMS_TERMINATE_ABILITY)] = + &AmsMgrStub::HandleTerminateAbility; + memberFuncMap_[static_cast(IAmsMgr::Message::AMS_UPDATE_ABILITY_STATE)] = + &AmsMgrStub::HandleUpdateAbilityState; + memberFuncMap_[static_cast(IAmsMgr::Message::AMS_REGISTER_APP_STATE_CALLBACK)] = + &AmsMgrStub::HandleRegisterAppStateCallback; + memberFuncMap_[static_cast(IAmsMgr::Message::AMS_RESET)] = &AmsMgrStub::HandleReset; + memberFuncMap_[static_cast(IAmsMgr::Message::AMS_ABILITY_BEHAVIOR_ANALYSIS)] = + &AmsMgrStub::HandleAbilityBehaviorAnalysis; + memberFuncMap_[static_cast(IAmsMgr::Message::AMS_KILL_PEOCESS_BY_ABILITY_TOKEN)] = + &AmsMgrStub::HandleKillProcessByAbilityToken; + memberFuncMap_[static_cast(IAmsMgr::Message::AMS_KILL_APPLICATION)] = &AmsMgrStub::HandleKillApplication; +} + +AmsMgrStub::~AmsMgrStub() +{ + memberFuncMap_.clear(); +} + +int AmsMgrStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + APP_LOGI("AmsMgrStub::OnReceived, code = %{public}d, flags= %{public}d.", code, option.GetFlags()); + std::u16string descriptor = AmsMgrStub::GetDescriptor(); + std::u16string remoteDescriptor = data.ReadInterfaceToken(); + if (descriptor != remoteDescriptor) { + APP_LOGE("local descriptor is not equal to remote"); + 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); +} + +ErrCode AmsMgrStub::HandleLoadAbility(MessageParcel &data, MessageParcel &reply) +{ + sptr token = data.ReadParcelable(); + sptr preToke = data.ReadParcelable(); + std::shared_ptr abilityInfo(data.ReadParcelable()); + if (!abilityInfo) { + APP_LOGE("ReadParcelable failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + std::shared_ptr appInfo(data.ReadParcelable()); + if (!appInfo) { + APP_LOGE("ReadParcelable failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + LoadAbility(token, preToke, abilityInfo, appInfo); + return NO_ERROR; +} + +ErrCode AmsMgrStub::HandleTerminateAbility(MessageParcel &data, MessageParcel &reply) +{ + sptr token = data.ReadParcelable(); + TerminateAbility(token); + return NO_ERROR; +} + +ErrCode AmsMgrStub::HandleUpdateAbilityState(MessageParcel &data, MessageParcel &reply) +{ + sptr token = data.ReadParcelable(); + int32_t state = data.ReadInt32(); + UpdateAbilityState(token, static_cast(state)); + return NO_ERROR; +} + +ErrCode AmsMgrStub::HandleRegisterAppStateCallback(MessageParcel &data, MessageParcel &reply) +{ + sptr obj = data.ReadParcelable(); + sptr callback = iface_cast(obj); + RegisterAppStateCallback(callback); + return NO_ERROR; +} + +ErrCode AmsMgrStub::HandleReset(MessageParcel &data, MessageParcel &reply) +{ + Reset(); + return NO_ERROR; +} + +ErrCode AmsMgrStub::HandleAbilityBehaviorAnalysis(MessageParcel &data, MessageParcel &reply) +{ + sptr token = data.ReadParcelable(); + sptr preToke = data.ReadParcelable(); + int32_t visibility = data.ReadInt32(); + int32_t Perceptibility = data.ReadInt32(); + int32_t connectionState = data.ReadInt32(); + + AbilityBehaviorAnalysis(token, preToke, visibility, Perceptibility, connectionState); + return NO_ERROR; +} + +ErrCode AmsMgrStub::HandleKillProcessByAbilityToken(MessageParcel &data, MessageParcel &reply) +{ + sptr token = data.ReadParcelable(); + + KillProcessByAbilityToken(token); + return NO_ERROR; +} + +ErrCode AmsMgrStub::HandleKillApplication(MessageParcel &data, MessageParcel &reply) +{ + std::string bundleName = data.ReadString(); + int32_t result = KillApplication(bundleName); + reply.WriteInt32(result); + return NO_ERROR; +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_core/src/appmgr/app_launch_data.cpp b/interfaces/innerkits/appexecfwk_core/src/appmgr/app_launch_data.cpp new file mode 100644 index 000000000..3913757cd --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/appmgr/app_launch_data.cpp @@ -0,0 +1,94 @@ +/* + * 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_launch_data.h" + +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { + +void AppLaunchData::SetApplicationInfo(const ApplicationInfo &info) +{ + applicationInfo_ = info; +} + +void AppLaunchData::SetProfile(const Profile &profile) +{ + profile_ = profile; +} + +void AppLaunchData::SetProcessInfo(const ProcessInfo &info) +{ + processInfo_ = info; +} + +void AppLaunchData::SetRecordId(const int32_t recordId) +{ + recordId_ = recordId; +} + +void AppLaunchData::SetUId(const int32_t uId) +{ + uId_ = uId; +} + +bool AppLaunchData::Marshalling(Parcel &parcel) const +{ + return (parcel.WriteParcelable(&applicationInfo_) && parcel.WriteParcelable(&profile_) && + parcel.WriteParcelable(&processInfo_) && parcel.WriteInt32(recordId_) && parcel.WriteInt32(uId_)); +} + +bool AppLaunchData::ReadFromParcel(Parcel &parcel) +{ + std::unique_ptr applicationInfoRead(parcel.ReadParcelable()); + if (!applicationInfoRead) { + APP_LOGE("failed, applicationInfoRead is nullptr"); + return false; + } + applicationInfo_ = *applicationInfoRead; + + std::unique_ptr profileRead(parcel.ReadParcelable()); + if (!profileRead) { + APP_LOGE("failed, profileRead is nullptr"); + return false; + } + profile_ = *profileRead; + + std::unique_ptr processInfoRead(parcel.ReadParcelable()); + if (!processInfoRead) { + APP_LOGE("failed, processInfoRead is nullptr"); + return false; + } + processInfo_ = *processInfoRead; + + recordId_ = parcel.ReadInt32(); + uId_ = parcel.ReadInt32(); + return true; +} + +AppLaunchData *AppLaunchData::Unmarshalling(Parcel &parcel) +{ + AppLaunchData *appLaunchData = new (std::nothrow) AppLaunchData(); + if (appLaunchData && !appLaunchData->ReadFromParcel(parcel)) { + APP_LOGW("failed, because ReadFromParcel failed"); + delete appLaunchData; + appLaunchData = nullptr; + } + return appLaunchData; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_core/src/appmgr/app_mgr_client.cpp b/interfaces/innerkits/appexecfwk_core/src/appmgr/app_mgr_client.cpp new file mode 100644 index 000000000..71a67a5da --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/appmgr/app_mgr_client.cpp @@ -0,0 +1,190 @@ +/* + * 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_mgr_client.h" + +#include +#include +#include + +#include "if_system_ability_manager.h" +#include "ipc_skeleton.h" + +#include "app_mgr_interface.h" +#include "app_service_manager.h" + +namespace OHOS { +namespace AppExecFwk { + +AppMgrClient::AppMgrClient() +{ + SetServiceManager(std::make_unique()); +} + +AppMgrClient::~AppMgrClient() +{} + +AppMgrResultCode AppMgrClient::LoadAbility(const sptr &token, const sptr &preToken, + const AbilityInfo &abilityInfo, const ApplicationInfo &appInfo) +{ + sptr service = iface_cast(remote_); + if (service != nullptr) { + sptr amsService = service->GetAmsMgr(); + if (amsService != nullptr) { + // From here, separate AbilityInfo and ApplicationInfo from AA. + std::shared_ptr abilityInfoPtr = std::make_shared(abilityInfo); + std::shared_ptr appInfoPtr = std::make_shared(appInfo); + amsService->LoadAbility(token, preToken, abilityInfoPtr, appInfoPtr); + return AppMgrResultCode::RESULT_OK; + } + } + return AppMgrResultCode::ERROR_SERVICE_NOT_CONNECTED; +} + +AppMgrResultCode AppMgrClient::TerminateAbility(const sptr &token) +{ + sptr service = iface_cast(remote_); + if (service != nullptr) { + sptr amsService = service->GetAmsMgr(); + if (amsService != nullptr) { + amsService->TerminateAbility(token); + return AppMgrResultCode::RESULT_OK; + } + } + return AppMgrResultCode::ERROR_SERVICE_NOT_CONNECTED; +} + +AppMgrResultCode AppMgrClient::UpdateAbilityState(const sptr &token, const AbilityState state) +{ + sptr service = iface_cast(remote_); + if (service != nullptr) { + sptr amsService = service->GetAmsMgr(); + if (amsService != nullptr) { + amsService->UpdateAbilityState(token, state); + return AppMgrResultCode::RESULT_OK; + } + } + return AppMgrResultCode::ERROR_SERVICE_NOT_CONNECTED; +} + +AppMgrResultCode AppMgrClient::RegisterAppStateCallback(const sptr &callback) +{ + sptr service = iface_cast(remote_); + if (service != nullptr) { + sptr amsService = service->GetAmsMgr(); + if (amsService != nullptr) { + amsService->RegisterAppStateCallback(callback); + return AppMgrResultCode::RESULT_OK; + } + } + return AppMgrResultCode::ERROR_SERVICE_NOT_CONNECTED; +} + +AppMgrResultCode AppMgrClient::Reset() +{ + sptr service = iface_cast(remote_); + if (service != nullptr) { + sptr amsService = service->GetAmsMgr(); + if (amsService != nullptr) { + amsService->Reset(); + return AppMgrResultCode::RESULT_OK; + } + } + return AppMgrResultCode::ERROR_SERVICE_NOT_CONNECTED; +} + +AppMgrResultCode AppMgrClient::AbilityBehaviorAnalysis(const sptr &token, + const sptr &preToken, const int32_t visibility, const int32_t perceptibility, + const int32_t connectionState) +{ + sptr service = iface_cast(remote_); + if (service != nullptr) { + sptr amsService = service->GetAmsMgr(); + if (amsService != nullptr) { + amsService->AbilityBehaviorAnalysis(token, preToken, visibility, perceptibility, connectionState); + return AppMgrResultCode::RESULT_OK; + } + } + return AppMgrResultCode::ERROR_SERVICE_NOT_CONNECTED; +} + +AppMgrResultCode AppMgrClient::KillProcessByAbilityToken(const sptr &token) +{ + sptr service = iface_cast(remote_); + if (service != nullptr) { + sptr amsService = service->GetAmsMgr(); + if (amsService != nullptr) { + amsService->KillProcessByAbilityToken(token); + return AppMgrResultCode::RESULT_OK; + } + } + return AppMgrResultCode::ERROR_SERVICE_NOT_CONNECTED; +} + +AppMgrResultCode AppMgrClient::KillApplication(const std::string &bundleName) +{ + sptr service = iface_cast(remote_); + if (service != nullptr) { + sptr amsService = service->GetAmsMgr(); + if (amsService != nullptr) { + int32_t result = amsService->KillApplication(bundleName); + if (result == ERR_OK) { + return AppMgrResultCode::RESULT_OK; + } + return AppMgrResultCode::ERROR_SERVICE_NOT_READY; + } + } + return AppMgrResultCode::ERROR_SERVICE_NOT_CONNECTED; +} + +AppMgrResultCode AppMgrClient::ClearUpApplicationData(const std::string &bundleName) +{ + sptr service = iface_cast(remote_); + if (service != nullptr) { + service->ClearUpApplicationData(bundleName); + return AppMgrResultCode::RESULT_OK; + } + return AppMgrResultCode::ERROR_SERVICE_NOT_CONNECTED; +} + +AppMgrResultCode AppMgrClient::GetAllRunningProcesses(std::shared_ptr &runningProcessInfo) +{ + sptr service = iface_cast(remote_); + if (service != nullptr) { + service->GetAllRunningProcesses(runningProcessInfo); + return AppMgrResultCode::RESULT_OK; + } + return AppMgrResultCode::ERROR_SERVICE_NOT_CONNECTED; +} + +AppMgrResultCode AppMgrClient::ConnectAppMgrService() +{ + if (!serviceManager_) { + return AppMgrResultCode::ERROR_SERVICE_NOT_READY; + } + remote_ = serviceManager_->GetAppMgrService(); + if (!remote_) { + return AppMgrResultCode::ERROR_SERVICE_NOT_READY; + } + return AppMgrResultCode::RESULT_OK; +} + +void AppMgrClient::SetServiceManager(std::unique_ptr serviceMgr) +{ + serviceManager_ = std::move(serviceMgr); +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_core/src/appmgr/app_mgr_proxy.cpp b/interfaces/innerkits/appexecfwk_core/src/appmgr/app_mgr_proxy.cpp new file mode 100644 index 000000000..17d60a501 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/appmgr/app_mgr_proxy.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 "app_mgr_proxy.h" + +#include "app_log_wrapper.h" +#include "appexecfwk_errors.h" + +#include "ipc_types.h" +#include "iremote_object.h" + +namespace OHOS { +namespace AppExecFwk { + +AppMgrProxy::AppMgrProxy(const sptr &impl) : IRemoteProxy(impl) +{} + +bool AppMgrProxy::WriteInterfaceToken(MessageParcel &data) +{ + if (!data.WriteInterfaceToken(AppMgrProxy::GetDescriptor())) { + APP_LOGE("write interface token failed"); + return false; + } + return true; +} + +void AppMgrProxy::AttachApplication(const sptr &obj) +{ + APP_LOGD("AppMgrProxy::AttachApplication start"); + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return; + } + data.WriteParcelable(obj.GetRefPtr()); + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is NULL"); + return; + } + int32_t ret = + remote->SendRequest(static_cast(IAppMgr::Message::AMS_APP_ATTACH_APPLICATION), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGW("SendRequest is failed, error code: %{public}d", ret); + } + APP_LOGD("end"); +} + +void AppMgrProxy::ApplicationForegrounded(const int32_t recordId) +{ + APP_LOGD("start"); + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return; + } + data.WriteInt32(recordId); + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is NULL"); + return; + } + int32_t ret = remote->SendRequest( + static_cast(IAppMgr::Message::AMS_APP_APPLICATION_FOREGROUNDED), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGW("SendRequest is failed, error code: %{public}d", ret); + } + APP_LOGD("end"); +} + +void AppMgrProxy::ApplicationBackgrounded(const int32_t recordId) +{ + APP_LOGD("start"); + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return; + } + data.WriteInt32(recordId); + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is NULL"); + return; + } + int32_t ret = remote->SendRequest( + static_cast(IAppMgr::Message::AMS_APP_APPLICATION_BACKGROUNDED), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGW("SendRequest is failed, error code: %{public}d", ret); + } + APP_LOGD("end"); +} + +void AppMgrProxy::ApplicationTerminated(const int32_t recordId) +{ + APP_LOGD("start"); + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return; + } + data.WriteInt32(recordId); + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is NULL"); + return; + } + int32_t ret = remote->SendRequest( + static_cast(IAppMgr::Message::AMS_APP_APPLICATION_TERMINATED), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGW("SendRequest is failed, error code: %{public}d", ret); + } + APP_LOGD("end"); +} + +int32_t AppMgrProxy::CheckPermission(const int32_t recordId, const std::string &permission) +{ + APP_LOGD("start"); + + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return ERR_PERMISSION_DENIED; + } + data.WriteInt32(recordId); + data.WriteString(permission); + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is NULL"); + return ERR_PERMISSION_DENIED; + } + int32_t ret = + remote->SendRequest(static_cast(IAppMgr::Message::AMS_APP_CHECK_PERMISSION), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGE("SendRequest is failed, error code: %{public}d", ret); + return ERR_PERMISSION_DENIED; + } + APP_LOGD("end"); + return reply.ReadInt32(); +} + +void AppMgrProxy::AbilityCleaned(const sptr &token) +{ + APP_LOGD("start"); + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return; + } + data.WriteParcelable(token.GetRefPtr()); + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is NULL"); + return; + } + int32_t ret = + remote->SendRequest(static_cast(IAppMgr::Message::AMS_APP_ABILITY_CLEANED), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGW("SendRequest is failed, error code: %{public}d", ret); + } + APP_LOGD("end"); +} + +sptr AppMgrProxy::GetAmsMgr() +{ + APP_LOGD("begin to get Ams instance"); + MessageParcel data; + MessageParcel reply; + if (!WriteInterfaceToken(data)) { + return nullptr; + } + if (!SendTransactCmd(IAppMgr::Message::AMS_APP_GET_MGR_INSTANCE, data, reply)) { + return nullptr; + } + sptr object = reply.ReadParcelable(); + sptr amsMgr = iface_cast(object); + if (!amsMgr) { + APP_LOGE("ams instance is nullptr"); + return nullptr; + } + APP_LOGD("get ams instance success"); + return amsMgr; +} + +void AppMgrProxy::ClearUpApplicationData(const std::string &bundleName) +{ + APP_LOGD("start"); + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return; + } + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is NULL"); + return; + } + if (!data.WriteString(bundleName)) { + APP_LOGE("parcel WriteString failed"); + return; + } + int32_t ret = remote->SendRequest( + static_cast(IAppMgr::Message::AMS_APP_CLEAR_UP_APPLICATION_DATA), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGW("SendRequest is failed, error code: %{public}d", ret); + return; + } + APP_LOGD("end"); +} + +int32_t AppMgrProxy::IsBackgroundRunningRestricted(const std::string &bundleName) +{ + APP_LOGD("start"); + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return ERR_FLATTEN_OBJECT; + } + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is NULL"); + return ERR_NULL_OBJECT; + } + if (!data.WriteString(bundleName)) { + APP_LOGE("parcel WriteString failed"); + return ERR_FLATTEN_OBJECT; + } + int32_t ret = remote->SendRequest( + static_cast(IAppMgr::Message::AMS_APP_IS_BACKGROUND_RUNNING_RESTRICTED), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGW("SendRequest is failed, error code: %{public}d", ret); + return ret; + } + APP_LOGD("end"); + return reply.ReadInt32(); +} + +int32_t AppMgrProxy::GetAllRunningProcesses(std::shared_ptr &runningProcessInfo) +{ + APP_LOGD("start"); + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return ERR_FLATTEN_OBJECT; + } + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is NULL"); + return ERR_NULL_OBJECT; + } + if (!data.WriteParcelable(runningProcessInfo.get())) { + APP_LOGE("parcel WriteString failed"); + return ERR_FLATTEN_OBJECT; + } + if (!SendTransactCmd(IAppMgr::Message::AMS_APP_GET_ALL_RUNNING_PROCESSES, data, reply)) { + return ERR_NULL_OBJECT; + } + int result = reply.ReadInt32(); + std::unique_ptr info(reply.ReadParcelable()); + if (!info) { + APP_LOGE("readParcelableInfo failed"); + return ERR_NULL_OBJECT; + } + runningProcessInfo = std::move(info); + APP_LOGD("end"); + return result; +} + +bool AppMgrProxy::SendTransactCmd(IAppMgr::Message code, MessageParcel &data, MessageParcel &reply) +{ + MessageOption option(MessageOption::TF_SYNC); + sptr remote = Remote(); + if (!remote) { + APP_LOGE("fail to send transact cmd %{public}d due to remote object", code); + return false; + } + int32_t result = remote->SendRequest(static_cast(code), data, reply, option); + if (result != NO_ERROR) { + APP_LOGE("receive error transact code %{public}d in transact cmd %{public}d", result, code); + return false; + } + return true; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_core/src/appmgr/app_mgr_stub.cpp b/interfaces/innerkits/appexecfwk_core/src/appmgr/app_mgr_stub.cpp new file mode 100644 index 000000000..11d78c7c6 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/appmgr/app_mgr_stub.cpp @@ -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. + */ + +#include "app_mgr_stub.h" + +#include "ipc_skeleton.h" +#include "ipc_types.h" +#include "iremote_object.h" + +#include "ability_info.h" +#include "appexecfwk_errors.h" +#include "app_log_wrapper.h" +#include "app_mgr_proxy.h" +#include "app_scheduler_interface.h" +#include "iapp_state_callback.h" + +namespace OHOS { +namespace AppExecFwk { + +AppMgrStub::AppMgrStub() +{ + memberFuncMap_[static_cast(IAppMgr::Message::AMS_APP_ATTACH_APPLICATION)] = + &AppMgrStub::HandleAttachApplication; + memberFuncMap_[static_cast(IAppMgr::Message::AMS_APP_APPLICATION_FOREGROUNDED)] = + &AppMgrStub::HandleApplicationForegrounded; + memberFuncMap_[static_cast(IAppMgr::Message::AMS_APP_APPLICATION_BACKGROUNDED)] = + &AppMgrStub::HandleApplicationBackgrounded; + memberFuncMap_[static_cast(IAppMgr::Message::AMS_APP_APPLICATION_TERMINATED)] = + &AppMgrStub::HandleApplicationTerminated; + memberFuncMap_[static_cast(IAppMgr::Message::AMS_APP_CHECK_PERMISSION)] = + &AppMgrStub::HandleCheckPermission; + memberFuncMap_[static_cast(IAppMgr::Message::AMS_APP_ABILITY_CLEANED)] = + &AppMgrStub::HandleAbilityCleaned; + memberFuncMap_[static_cast(IAppMgr::Message::AMS_APP_GET_MGR_INSTANCE)] = &AppMgrStub::HandleGetAmsMgr; + memberFuncMap_[static_cast(IAppMgr::Message::AMS_APP_CLEAR_UP_APPLICATION_DATA)] = + &AppMgrStub::HandleClearUpApplicationData; + memberFuncMap_[static_cast(IAppMgr::Message::AMS_APP_IS_BACKGROUND_RUNNING_RESTRICTED)] = + &AppMgrStub::HandleIsBackgroundRunningRestricted; + memberFuncMap_[static_cast(IAppMgr::Message::AMS_APP_GET_ALL_RUNNING_PROCESSES)] = + &AppMgrStub::HandleGetAllRunningProcesses; +} + +AppMgrStub::~AppMgrStub() +{ + memberFuncMap_.clear(); +} + +int AppMgrStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + APP_LOGI("AppMgrStub::OnReceived, code = %{public}d, flags= %{public}d.", code, option.GetFlags()); + std::u16string descriptor = AppMgrStub::GetDescriptor(); + std::u16string remoteDescriptor = data.ReadInterfaceToken(); + if (descriptor != remoteDescriptor) { + APP_LOGE("local descriptor is not equal to remote"); + 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); +} + +int32_t AppMgrStub::HandleAttachApplication(MessageParcel &data, MessageParcel &reply) +{ + sptr client = data.ReadParcelable(); + AttachApplication(client); + return NO_ERROR; +} + +int32_t AppMgrStub::HandleApplicationForegrounded(MessageParcel &data, MessageParcel &reply) +{ + ApplicationForegrounded(data.ReadInt32()); + return NO_ERROR; +} + +int32_t AppMgrStub::HandleApplicationBackgrounded(MessageParcel &data, MessageParcel &reply) +{ + ApplicationBackgrounded(data.ReadInt32()); + return NO_ERROR; +} + +int32_t AppMgrStub::HandleApplicationTerminated(MessageParcel &data, MessageParcel &reply) +{ + ApplicationTerminated(data.ReadInt32()); + return NO_ERROR; +} + +int32_t AppMgrStub::HandleCheckPermission(MessageParcel &data, MessageParcel &reply) +{ + int32_t recordId = data.ReadInt32(); + std::string permission = data.ReadString(); + int32_t result = CheckPermission(recordId, permission); + reply.WriteInt32(result); + return NO_ERROR; +} + +int32_t AppMgrStub::HandleAbilityCleaned(MessageParcel &data, MessageParcel &reply) +{ + sptr token = data.ReadParcelable(); + AbilityCleaned(token); + return NO_ERROR; +} + +int32_t AppMgrStub::HandleGetAmsMgr(MessageParcel &data, MessageParcel &reply) +{ + int32_t result = NO_ERROR; + sptr amsMgr = GetAmsMgr(); + if (!amsMgr) { + APP_LOGE("ams instance is nullptr"); + result = ERR_NO_INIT; + } else { + if (!reply.WriteParcelable(amsMgr->AsObject())) { + APP_LOGE("failed to reply ams instance to client, for write parcel error"); + result = ERR_APPEXECFWK_PARCEL_ERROR; + } + } + reply.WriteInt32(result); + return NO_ERROR; +} + +int32_t AppMgrStub::HandleClearUpApplicationData(MessageParcel &data, MessageParcel &reply) +{ + std::string bundleName = data.ReadString(); + ClearUpApplicationData(bundleName); + return NO_ERROR; +} + +int32_t AppMgrStub::HandleIsBackgroundRunningRestricted(MessageParcel &data, MessageParcel &reply) +{ + std::string bundleName = data.ReadString(); + int32_t result = IsBackgroundRunningRestricted(bundleName); + reply.WriteInt32(result); + return NO_ERROR; +} + +int32_t AppMgrStub::HandleGetAllRunningProcesses(MessageParcel &data, MessageParcel &reply) +{ + std::shared_ptr runningProcessInfo(data.ReadParcelable()); + int32_t result = GetAllRunningProcesses(runningProcessInfo); + reply.WriteInt32(result); + reply.WriteParcelable(runningProcessInfo.get()); + return NO_ERROR; +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_core/src/appmgr/app_process_data.cpp b/interfaces/innerkits/appexecfwk_core/src/appmgr/app_process_data.cpp new file mode 100644 index 000000000..dfb3cc85d --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/appmgr/app_process_data.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 "app_process_data.h" + +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { + +bool AppProcessData::Marshalling(Parcel &parcel) const +{ + return (parcel.WriteString(appName) && parcel.WriteString(processName) && + parcel.WriteInt32(static_cast(appState)) && parcel.WriteInt32(pid)); +} + +bool AppProcessData::ReadFromParcel(Parcel &parcel) +{ + appName = parcel.ReadString(); + + processName = parcel.ReadString(); + + appState = static_cast(parcel.ReadInt32()); + + pid = parcel.ReadInt32(); + + return true; +} + +AppProcessData *AppProcessData::Unmarshalling(Parcel &parcel) +{ + AppProcessData *appProcessData = new (std::nothrow) AppProcessData(); + if (appProcessData && !appProcessData->ReadFromParcel(parcel)) { + APP_LOGW("failed, because ReadFromParcel failed"); + delete appProcessData; + appProcessData = nullptr; + } + return appProcessData; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_core/src/appmgr/app_record_id.cpp b/interfaces/innerkits/appexecfwk_core/src/appmgr/app_record_id.cpp new file mode 100644 index 000000000..ad465b779 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/appmgr/app_record_id.cpp @@ -0,0 +1,30 @@ +/* + * 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_record_id.h" +namespace OHOS { +namespace AppExecFwk { + +int32_t AppRecordId::Create() +{ + // Make it atomic to avoid multi app creating concurrently. + static std::atomic_int id(0); + return ++id; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_core/src/appmgr/app_scheduler_host.cpp b/interfaces/innerkits/appexecfwk_core/src/appmgr/app_scheduler_host.cpp new file mode 100644 index 000000000..06d8f2ee2 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/appmgr/app_scheduler_host.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 "app_scheduler_host.h" +#include "ipc_types.h" +#include "ability_info.h" +#include "appexecfwk_errors.h" +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { + +AppSchedulerHost::AppSchedulerHost() +{ + memberFuncMap_[static_cast(IAppScheduler::Message::SCHEDULE_FOREGROUND_APPLICATION_TRANSACTION)] = + &AppSchedulerHost::HandleScheduleForegroundApplication; + memberFuncMap_[static_cast(IAppScheduler::Message::SCHEDULE_BACKGROUND_APPLICATION_TRANSACTION)] = + &AppSchedulerHost::HandleScheduleBackgroundApplication; + memberFuncMap_[static_cast(IAppScheduler::Message::SCHEDULE_TERMINATE_APPLICATION_TRANSACTION)] = + &AppSchedulerHost::HandleScheduleTerminateApplication; + memberFuncMap_[static_cast(IAppScheduler::Message::SCHEDULE_LOWMEMORY_APPLICATION_TRANSACTION)] = + &AppSchedulerHost::HandleScheduleLowMemory; + memberFuncMap_[static_cast(IAppScheduler::Message::SCHEDULE_SHRINK_MEMORY_APPLICATION_TRANSACTION)] = + &AppSchedulerHost::HandleScheduleShrinkMemory; + memberFuncMap_[static_cast(IAppScheduler::Message::SCHEDULE_LAUNCH_ABILITY_TRANSACTION)] = + &AppSchedulerHost::HandleScheduleLaunchAbility; + memberFuncMap_[static_cast(IAppScheduler::Message::SCHEDULE_CLEAN_ABILITY_TRANSACTION)] = + &AppSchedulerHost::HandleScheduleCleanAbility; + memberFuncMap_[static_cast(IAppScheduler::Message::SCHEDULE_LAUNCH_APPLICATION_TRANSACTION)] = + &AppSchedulerHost::HandleScheduleLaunchApplication; + memberFuncMap_[static_cast(IAppScheduler::Message::SCHEDULE_PROFILE_CHANGED_TRANSACTION)] = + &AppSchedulerHost::HandleScheduleProfileChanged; + memberFuncMap_[static_cast(IAppScheduler::Message::SCHEDULE_CONFIGURATION_UPDATED)] = + &AppSchedulerHost::HandleScheduleConfigurationUpdated; + memberFuncMap_[static_cast(IAppScheduler::Message::SCHEDULE_PROCESS_SECURITY_EXIT_TRANSACTION)] = + &AppSchedulerHost::HandleScheduleProcessSecurityExit; +} + +AppSchedulerHost::~AppSchedulerHost() +{ + memberFuncMap_.clear(); +} + +int AppSchedulerHost::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + APP_LOGI("AppSchedulerHost::OnReceived, code = %{public}d, flags= %{public}d.", code, option.GetFlags()); + std::u16string descriptor = AppSchedulerHost::GetDescriptor(); + std::u16string remoteDescriptor = data.ReadInterfaceToken(); + if (descriptor != remoteDescriptor) { + APP_LOGE("local descriptor is not equal to remote"); + 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); +} + +int32_t AppSchedulerHost::HandleScheduleForegroundApplication(MessageParcel &data, MessageParcel &reply) +{ + ScheduleForegroundApplication(); + return NO_ERROR; +} + +int32_t AppSchedulerHost::HandleScheduleBackgroundApplication(MessageParcel &data, MessageParcel &reply) +{ + ScheduleBackgroundApplication(); + return NO_ERROR; +} + +int32_t AppSchedulerHost::HandleScheduleTerminateApplication(MessageParcel &data, MessageParcel &reply) +{ + ScheduleTerminateApplication(); + return NO_ERROR; +} + +int32_t AppSchedulerHost::HandleScheduleLowMemory(MessageParcel &data, MessageParcel &reply) +{ + ScheduleLowMemory(); + return NO_ERROR; +} + +int32_t AppSchedulerHost::HandleScheduleShrinkMemory(MessageParcel &data, MessageParcel &reply) +{ + ScheduleShrinkMemory(data.ReadInt32()); + return NO_ERROR; +} + +int32_t AppSchedulerHost::HandleScheduleLaunchAbility(MessageParcel &data, MessageParcel &reply) +{ + std::unique_ptr abilityInfo(data.ReadParcelable()); + if (!abilityInfo) { + APP_LOGE("ReadParcelable failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + sptr token = data.ReadParcelable(); + ScheduleLaunchAbility(*abilityInfo, token); + return NO_ERROR; +} + +int32_t AppSchedulerHost::HandleScheduleCleanAbility(MessageParcel &data, MessageParcel &reply) +{ + sptr token = data.ReadParcelable(); + ScheduleCleanAbility(token); + return NO_ERROR; +} + +int32_t AppSchedulerHost::HandleScheduleLaunchApplication(MessageParcel &data, MessageParcel &reply) +{ + std::unique_ptr launchData(data.ReadParcelable()); + if (!launchData) { + APP_LOGE("ReadParcelable failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + ScheduleLaunchApplication(*launchData); + return NO_ERROR; +} + +int32_t AppSchedulerHost::HandleScheduleProfileChanged(MessageParcel &data, MessageParcel &reply) +{ + std::unique_ptr profile(data.ReadParcelable()); + if (!profile) { + APP_LOGE("ReadParcelable failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + ScheduleProfileChanged(*profile); + return NO_ERROR; +} + +int32_t AppSchedulerHost::HandleScheduleConfigurationUpdated(MessageParcel &data, MessageParcel &reply) +{ + std::unique_ptr configuration(data.ReadParcelable()); + if (!configuration) { + APP_LOGE("ReadParcelable failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + ScheduleConfigurationUpdated(*configuration); + return NO_ERROR; +} + +int32_t AppSchedulerHost::HandleScheduleProcessSecurityExit(MessageParcel &data, MessageParcel &reply) +{ + ScheduleProcessSecurityExit(); + return NO_ERROR; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_core/src/appmgr/app_scheduler_proxy.cpp b/interfaces/innerkits/appexecfwk_core/src/appmgr/app_scheduler_proxy.cpp new file mode 100644 index 000000000..d76de6f14 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/appmgr/app_scheduler_proxy.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 "app_scheduler_proxy.h" + +#include "iremote_object.h" +#include "ipc_types.h" + +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { +AppSchedulerProxy::AppSchedulerProxy(const sptr &impl) : IRemoteProxy(impl) +{} + +bool AppSchedulerProxy::WriteInterfaceToken(MessageParcel &data) +{ + if (!data.WriteInterfaceToken(AppSchedulerProxy::GetDescriptor())) { + APP_LOGE("write interface token failed"); + return false; + } + return true; +} + +void AppSchedulerProxy::ScheduleForegroundApplication() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return; + } + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is NULL"); + return; + } + int32_t ret = + remote->SendRequest(static_cast(IAppScheduler::Message::SCHEDULE_FOREGROUND_APPLICATION_TRANSACTION), + data, + reply, + option); + if (ret != NO_ERROR) { + APP_LOGW("SendRequest is failed, error code: %{public}d", ret); + } +} + +void AppSchedulerProxy::ScheduleBackgroundApplication() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return; + } + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is NULL"); + return; + } + int32_t ret = + remote->SendRequest(static_cast(IAppScheduler::Message::SCHEDULE_BACKGROUND_APPLICATION_TRANSACTION), + data, + reply, + option); + if (ret != NO_ERROR) { + APP_LOGW("SendRequest is failed, error code: %{public}d", ret); + } +} + +void AppSchedulerProxy::ScheduleTerminateApplication() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return; + } + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is NULL"); + return; + } + int32_t ret = remote->SendRequest( + static_cast(IAppScheduler::Message::SCHEDULE_TERMINATE_APPLICATION_TRANSACTION), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGW("SendRequest is failed, error code: %{public}d", ret); + } +} + +void AppSchedulerProxy::ScheduleLowMemory() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return; + } + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is NULL"); + return; + } + int32_t ret = remote->SendRequest( + static_cast(IAppScheduler::Message::SCHEDULE_LOWMEMORY_APPLICATION_TRANSACTION), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGW("SendRequest is failed, error code: %{public}d", ret); + } +} + +void AppSchedulerProxy::ScheduleShrinkMemory(const int32_t level) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return; + } + data.WriteInt32(level); + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is NULL"); + return; + } + int32_t ret = remote->SendRequest( + static_cast(IAppScheduler::Message::SCHEDULE_SHRINK_MEMORY_APPLICATION_TRANSACTION), + data, + reply, + option); + if (ret != NO_ERROR) { + APP_LOGW("SendRequest is failed, error code: %{public}d", ret); + } +} + +void AppSchedulerProxy::ScheduleLaunchAbility(const AbilityInfo &info, const sptr &token) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return; + } + data.WriteParcelable(&info); + data.WriteParcelable(token.GetRefPtr()); + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is NULL"); + return; + } + int32_t ret = remote->SendRequest( + static_cast(IAppScheduler::Message::SCHEDULE_LAUNCH_ABILITY_TRANSACTION), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGW("SendRequest is failed, error code: %{public}d", ret); + } +} + +void AppSchedulerProxy::ScheduleCleanAbility(const sptr &token) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return; + } + data.WriteParcelable(token.GetRefPtr()); + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is NULL"); + return; + } + int32_t ret = remote->SendRequest( + static_cast(IAppScheduler::Message::SCHEDULE_CLEAN_ABILITY_TRANSACTION), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGW("SendRequest is failed, error code: %{public}d", ret); + } +} + +void AppSchedulerProxy::ScheduleLaunchApplication(const AppLaunchData &launchData) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return; + } + data.WriteParcelable(&launchData); + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is NULL"); + return; + } + int32_t ret = remote->SendRequest( + static_cast(IAppScheduler::Message::SCHEDULE_LAUNCH_APPLICATION_TRANSACTION), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGW("SendRequest is failed, error code: %{public}d", ret); + } +} + +void AppSchedulerProxy::ScheduleProfileChanged(const Profile &profile) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return; + } + data.WriteParcelable(&profile); + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is NULL"); + return; + } + int32_t ret = remote->SendRequest( + static_cast(IAppScheduler::Message::SCHEDULE_PROFILE_CHANGED_TRANSACTION), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGW("SendRequest is failed, error code: %{public}d", ret); + } +} + +void AppSchedulerProxy::ScheduleConfigurationUpdated(const Configuration &config) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return; + } + data.WriteParcelable(&config); + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is NULL"); + return; + } + int32_t ret = remote->SendRequest( + static_cast(IAppScheduler::Message::SCHEDULE_CONFIGURATION_UPDATED), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGW("SendRequest is failed, error code: %{public}d", ret); + } +} + +void AppSchedulerProxy::ScheduleProcessSecurityExit() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return; + } + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is NULL"); + return; + } + int32_t ret = remote->SendRequest( + static_cast(IAppScheduler::Message::SCHEDULE_PROCESS_SECURITY_EXIT_TRANSACTION), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGW("SendRequest is failed, error code: %{public}d", ret); + } +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_core/src/appmgr/app_service_manager.cpp b/interfaces/innerkits/appexecfwk_core/src/appmgr/app_service_manager.cpp new file mode 100644 index 000000000..093d421da --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/appmgr/app_service_manager.cpp @@ -0,0 +1,38 @@ +/* + * 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_service_manager.h" + +#include "ipc_skeleton.h" +#include "system_ability_definition.h" +#include "if_system_ability_manager.h" + +#include "iservice_registry.h" +#include "app_mgr_constants.h" + +namespace OHOS { +namespace AppExecFwk { + +sptr AppServiceManager::GetAppMgrService() const +{ + sptr systemAbilityMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (!systemAbilityMgr) { + return nullptr; + } + return systemAbilityMgr->GetSystemAbility(APP_MGR_SERVICE_ID); +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_core/src/appmgr/app_state_callback_host.cpp b/interfaces/innerkits/appexecfwk_core/src/appmgr/app_state_callback_host.cpp new file mode 100644 index 000000000..46888dc23 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/appmgr/app_state_callback_host.cpp @@ -0,0 +1,94 @@ +/* + * 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_state_callback_host.h" + +#include "appexecfwk_errors.h" +#include "app_log_wrapper.h" + +#include "ipc_types.h" +#include "iremote_object.h" + +#include "app_state_callback_proxy.h" + +namespace OHOS { +namespace AppExecFwk { + +AppStateCallbackHost::AppStateCallbackHost() +{ + memberFuncMap_[static_cast(IAppStateCallback::Message::TRANSACT_ON_APP_STATE_CHANGED)] = + &AppStateCallbackHost::HandleOnAppStateChanged; + memberFuncMap_[static_cast(IAppStateCallback::Message::TRANSACT_ON_ABILITY_REQUEST_DONE)] = + &AppStateCallbackHost::HandleOnAbilityRequestDone; +} + +AppStateCallbackHost::~AppStateCallbackHost() +{ + memberFuncMap_.clear(); +} + +int AppStateCallbackHost::OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + APP_LOGI("AppStateCallbackHost::OnReceived, code = %{public}d, flags= %{public}d.", code, option.GetFlags()); + std::u16string descriptor = AppStateCallbackHost::GetDescriptor(); + std::u16string remoteDescriptor = data.ReadInterfaceToken(); + if (descriptor != remoteDescriptor) { + APP_LOGE("local descriptor is not equal to remote"); + 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); +} + +void AppStateCallbackHost::OnAbilityRequestDone(const sptr &, const AbilityState) +{ + APP_LOGD("called"); +} + +void AppStateCallbackHost::OnAppStateChanged(const AppProcessData &) +{ + APP_LOGD("called"); +} + +int32_t AppStateCallbackHost::HandleOnAppStateChanged(MessageParcel &data, MessageParcel &reply) +{ + std::unique_ptr processData(data.ReadParcelable()); + if (!processData) { + APP_LOGE("ReadParcelable failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + OnAppStateChanged(*processData); + return NO_ERROR; +} + +int32_t AppStateCallbackHost::HandleOnAbilityRequestDone(MessageParcel &data, MessageParcel &reply) +{ + sptr obj = data.ReadParcelable(); + int32_t state = data.ReadInt32(); + OnAbilityRequestDone(obj, static_cast(state)); + return NO_ERROR; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_core/src/appmgr/app_state_callback_proxy.cpp b/interfaces/innerkits/appexecfwk_core/src/appmgr/app_state_callback_proxy.cpp new file mode 100644 index 000000000..e3eed8ebd --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/appmgr/app_state_callback_proxy.cpp @@ -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. + */ + +#include "app_state_callback_proxy.h" + +#include "ipc_types.h" + +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { + +AppStateCallbackProxy::AppStateCallbackProxy(const sptr &impl) : IRemoteProxy(impl) +{} + +bool AppStateCallbackProxy::WriteInterfaceToken(MessageParcel &data) +{ + if (!data.WriteInterfaceToken(AppStateCallbackProxy::GetDescriptor())) { + APP_LOGE("write interface token failed"); + return false; + } + return true; +} + +void AppStateCallbackProxy::OnAbilityRequestDone(const sptr &token, const AbilityState state) +{ + APP_LOGD("begin"); + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return; + } + data.WriteParcelable(token.GetRefPtr()); + int32_t abilityState = static_cast(state); + data.WriteInt32(abilityState); + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is NULL"); + return; + } + int32_t ret = remote->SendRequest( + static_cast(IAppStateCallback::Message::TRANSACT_ON_ABILITY_REQUEST_DONE), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGW("SendRequest is failed, error code: %{public}d", ret); + } + APP_LOGD("end"); +} + +void AppStateCallbackProxy::OnAppStateChanged(const AppProcessData &appProcessData) +{ + APP_LOGD("begin"); + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + if (!WriteInterfaceToken(data)) { + return; + } + data.WriteParcelable(&appProcessData); + sptr remote = Remote(); + if (remote == nullptr) { + APP_LOGE("Remote() is NULL"); + return; + } + int32_t ret = remote->SendRequest( + static_cast(IAppStateCallback::Message::TRANSACT_ON_APP_STATE_CHANGED), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGW("SendRequest is failed, error code: %{public}d", ret); + } + APP_LOGD("end"); +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_core/src/appmgr/app_task_info.cpp b/interfaces/innerkits/appexecfwk_core/src/appmgr/app_task_info.cpp new file mode 100644 index 000000000..6af120bb4 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/appmgr/app_task_info.cpp @@ -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. + */ + +#include "app_task_info.h" + +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { + +const std::string &AppTaskInfo::GetName() const +{ + return appName_; +} + +const std::string &AppTaskInfo::GetProcessName() const +{ + return processName_; +} + +pid_t AppTaskInfo::GetPid() const +{ + return pid_; +} + +int32_t AppTaskInfo::GetRecordId() const +{ + return appRecordId_; +} + +void AppTaskInfo::SetName(const std::string &appName) +{ + appName_ = appName; +} + +void AppTaskInfo::SetProcessName(const std::string &processName) +{ + processName_ = processName; +} + +void AppTaskInfo::SetPid(const pid_t pid) +{ + pid_ = pid; +} + +void AppTaskInfo::SetRecordId(const int32_t appRecordId) +{ + appRecordId_ = appRecordId; +} + +bool AppTaskInfo::Marshalling(Parcel &parcel) const +{ + return (parcel.WriteString(appName_) && parcel.WriteString(processName_) && parcel.WriteInt32(pid_) && + parcel.WriteInt32(appRecordId_)); +} + +bool AppTaskInfo::ReadFromParcel(Parcel &parcel) +{ + return (parcel.ReadString(appName_) && parcel.ReadString(processName_) && parcel.ReadInt32(pid_) && + parcel.ReadInt32(appRecordId_)); +} + +AppTaskInfo *AppTaskInfo::Unmarshalling(Parcel &parcel) +{ + AppTaskInfo *appTaskInfo = new (std::nothrow) AppTaskInfo(); + if (appTaskInfo && !appTaskInfo->ReadFromParcel(parcel)) { + APP_LOGW("failed, because ReadFromParcel failed"); + delete appTaskInfo; + appTaskInfo = nullptr; + } + return appTaskInfo; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_core/src/appmgr/dummy_configuration.cpp b/interfaces/innerkits/appexecfwk_core/src/appmgr/dummy_configuration.cpp new file mode 100644 index 000000000..8950ae62e --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/appmgr/dummy_configuration.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 "dummy_configuration.h" + +#include "string_ex.h" + +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { + +Configuration::Configuration(const std::string &name) : testInfostr_(name) +{} + +bool Configuration::ReadFromParcel(Parcel &parcel) +{ + testInfostr_ = Str16ToStr8(parcel.ReadString16()); + return true; +} + +Configuration *Configuration::Unmarshalling(Parcel &parcel) +{ + Configuration *configuration = new (std::nothrow) Configuration(); + if (configuration && !configuration->ReadFromParcel(parcel)) { + APP_LOGW("failed, because ReadFromParcel failed"); + delete configuration; + configuration = nullptr; + } + return configuration; +} + +bool Configuration::Marshalling(Parcel &parcel) const +{ + if (!parcel.WriteString16(Str8ToStr16(testInfostr_))) { + return false; + } + return true; +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_core/src/appmgr/priority_object.cpp b/interfaces/innerkits/appexecfwk_core/src/appmgr/priority_object.cpp new file mode 100644 index 000000000..c5296ab36 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/appmgr/priority_object.cpp @@ -0,0 +1,146 @@ +/* + * 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 "priority_object.h" + +#include "app_log_wrapper.h" + +namespace OHOS { + +namespace AppExecFwk { + +pid_t PriorityObject::GetPid() const +{ + return pid_; +} + +int32_t PriorityObject::GetMaxAdj() const +{ + return maxAdj_; +} + +int32_t PriorityObject::GetCurAdj() const +{ + return curAdj_; +} + +int32_t PriorityObject::GetCurCgroup() const +{ + return curCgroup_; +} + +int32_t PriorityObject::GetTimeLevel() const +{ + return timeLevel_; +} + +bool PriorityObject::GetVisibleStatus() const +{ + return visibleStatus_; +} + +bool PriorityObject::GetPerceptibleStatus() const +{ + return perceptibleStatus_; +} + +void PriorityObject::SetPid(const pid_t pid) +{ + pid_ = pid; +} + +void PriorityObject::SetMaxAdj(const int32_t maxAdj) +{ + maxAdj_ = maxAdj; +} + +void PriorityObject::SetCurAdj(const int32_t curAdj) +{ + curAdj_ = curAdj; +} + +void PriorityObject::SetCurCgroup(const int32_t curCgroup) +{ + curCgroup_ = curCgroup; +} + +void PriorityObject::SetTimeLevel(const int32_t timeLevel) +{ + timeLevel_ = timeLevel; +} + +void PriorityObject::SetVisibleStatus(bool status) +{ + visibleStatus_ = status; +} + +void PriorityObject::SetPerceptibleStatus(bool status) +{ + perceptibleStatus_ = status; +} + +bool PriorityObject::Marshalling(Parcel &parcel) const +{ + if (!parcel.WriteInt32(pid_)) { + return false; + } + if (!parcel.WriteInt32(maxAdj_)) { + return false; + } + if (!parcel.WriteInt32(curAdj_)) { + return false; + } + if (!parcel.WriteInt32(curCgroup_)) { + return false; + } + if (!parcel.WriteInt32(timeLevel_)) { + return false; + } + return true; +} + +bool PriorityObject::ReadFromParcel(Parcel &parcel) +{ + if (!parcel.ReadInt32(pid_)) { + return false; + } + if (!parcel.ReadInt32(maxAdj_)) { + return false; + } + if (!parcel.ReadInt32(curAdj_)) { + return false; + } + if (!parcel.ReadInt32(curCgroup_)) { + return false; + } + if (!parcel.ReadInt32(timeLevel_)) { + return false; + } + return true; +} + +PriorityObject *PriorityObject::Unmarshalling(Parcel &parcel) +{ + PriorityObject *priorityObject = new (std::nothrow) PriorityObject(); + if (priorityObject && !priorityObject->ReadFromParcel(parcel)) { + APP_LOGW("failed, because ReadFromParcel failed"); + delete priorityObject; + priorityObject = nullptr; + } + return priorityObject; +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_core/src/appmgr/process_info.cpp b/interfaces/innerkits/appexecfwk_core/src/appmgr/process_info.cpp new file mode 100644 index 000000000..e68ee62a4 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/appmgr/process_info.cpp @@ -0,0 +1,66 @@ +/* + * 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 "process_info.h" +#include "string_ex.h" +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { + +ProcessInfo::ProcessInfo(const std::string &name, const pid_t &pid) : processName_(name), pid_(pid) +{} + +/** + * @brief read this Sequenceable object from a Parcel. + * + * @param inParcel Indicates the Parcel object into which the Sequenceable object has been marshaled. + * @return Returns true if read successed; returns false otherwise. + */ +bool ProcessInfo::ReadFromParcel(Parcel &parcel) +{ + processName_ = Str16ToStr8(parcel.ReadString16()); + pid_ = parcel.ReadInt32(); + return true; +} + +/** + * @brief Unmarshals this Sequenceable object from a Parcel. + * + * @param inParcel Indicates the Parcel object into which the Sequenceable object has been marshaled. + */ +ProcessInfo *ProcessInfo::Unmarshalling(Parcel &parcel) +{ + ProcessInfo *processInfo = new (std::nothrow) ProcessInfo(); + if (processInfo && !processInfo->ReadFromParcel(parcel)) { + APP_LOGE("ProcessInfo::Unmarshalling ReadFromParcel failed"); + delete processInfo; + processInfo = nullptr; + } + return processInfo; +} + +/** + * @brief Marshals this Sequenceable object into a Parcel. + * + * @param outParcel Indicates the Parcel object to which the Sequenceable object will be marshaled. + */ +bool ProcessInfo::Marshalling(Parcel &parcel) const +{ + return (parcel.WriteString16(Str8ToStr16(processName_)) && parcel.WriteInt32(pid_)); +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_core/src/appmgr/profile.cpp b/interfaces/innerkits/appexecfwk_core/src/appmgr/profile.cpp new file mode 100644 index 000000000..8d6ea3988 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/appmgr/profile.cpp @@ -0,0 +1,52 @@ +/* + * 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 "profile.h" + +#include "string_ex.h" + +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { + +Profile::Profile(const std::string &name) : profileName_(name) +{} + +bool Profile::ReadFromParcel(Parcel &parcel) +{ + profileName_ = Str16ToStr8(parcel.ReadString16()); + + return true; +} + +Profile *Profile::Unmarshalling(Parcel &parcel) +{ + Profile *profile = new (std::nothrow) Profile(); + if (profile && !profile->ReadFromParcel(parcel)) { + APP_LOGW("failed, because ReadFromParcel failed"); + delete profile; + profile = nullptr; + } + return profile; +} + +bool Profile::Marshalling(Parcel &parcel) const +{ + return (parcel.WriteString16(Str8ToStr16(profileName_))); +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_installer_proxy.cpp b/interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_installer_proxy.cpp new file mode 100644 index 000000000..d9644b5fe --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_installer_proxy.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 "bundle_installer_proxy.h" + +#include "ipc_types.h" +#include "parcel.h" +#include "string_ex.h" + +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { + +BundleInstallerProxy::BundleInstallerProxy(const sptr &object) : IRemoteProxy(object) +{ + APP_LOGI("create bundle installer proxy instance"); +} + +BundleInstallerProxy::~BundleInstallerProxy() +{ + APP_LOGI("destroy bundle installer proxy instance"); +} + +bool BundleInstallerProxy::Install( + const std::string &bundlePath, const InstallParam &installParam, const sptr &statusReceiver) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to dump due to write MessageParcel fail"); + return false; + } + if (!data.WriteString16(Str8ToStr16(bundlePath))) { + APP_LOGE("fail to install, for write parcel bundle path failed"); + return false; + } + if (!data.WriteParcelable(&installParam)) { + APP_LOGE("fail to install, for write parcel install param failed"); + return false; + } + if (!statusReceiver) { + APP_LOGE("fail to install, for statusReceiver is nullptr"); + return false; + } + if (!data.WriteParcelable(statusReceiver->AsObject())) { + APP_LOGE("fail to install, for write parcel status receiver failed"); + return false; + } + + sptr remote = Remote(); + if (!remote) { + APP_LOGE("fail to install, for Remote() is nullptr"); + return false; + } + + int32_t ret = remote->SendRequest(static_cast(IBundleInstaller::Message::INSTALL), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGE("fail to install, for transact is failed and error code is: %{public}d", ret); + return false; + } + return true; +} + +bool BundleInstallerProxy::Uninstall( + const std::string &bundleName, const InstallParam &installParam, const sptr &statusReceiver) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to dump due to write MessageParcel fail"); + return false; + } + if (!data.WriteString16(Str8ToStr16(bundleName))) { + APP_LOGE("fail to uninstall, for write parcel bundle name failed"); + return false; + } + if (!data.WriteParcelable(&installParam)) { + APP_LOGE("fail to install, for write parcel install param failed"); + return false; + } + if (!statusReceiver) { + APP_LOGE("fail to uninstall, for statusReceiver is nullptr"); + return false; + } + if (!data.WriteParcelable(statusReceiver->AsObject())) { + APP_LOGE("fail to uninstall, for write parcel status receiver failed"); + return false; + } + + sptr remote = Remote(); + if (!remote) { + APP_LOGE("fail to uninstall, for Remote() is nullptr"); + return false; + } + + int32_t ret = remote->SendRequest(static_cast(IBundleInstaller::Message::UNINSTALL), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGE("fail to uninstall, for transact is failed and error code is: %{public}d", ret); + return false; + } + return true; +} + +bool BundleInstallerProxy::Uninstall(const std::string &bundleName, const std::string &modulePackage, + const InstallParam &installParam, const sptr &statusReceiver) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to dump due to write MessageParcel fail"); + return false; + } + if (!data.WriteString16(Str8ToStr16(bundleName))) { + APP_LOGE("fail to uninstall, for write parcel bundle name failed"); + return false; + } + if (!data.WriteString16(Str8ToStr16(modulePackage))) { + APP_LOGE("fail to uninstall, for write parcel module package failed"); + return false; + } + if (!data.WriteParcelable(&installParam)) { + APP_LOGE("fail to install, for write parcel install param failed"); + return false; + } + if (!statusReceiver) { + APP_LOGE("fail to uninstall, for statusReceiver is nullptr"); + return false; + } + if (!data.WriteParcelable(statusReceiver->AsObject())) { + APP_LOGE("fail to uninstall, for write parcel status receiver failed"); + return false; + } + + sptr remote = Remote(); + if (!remote) { + APP_LOGE("fail to uninstall, for Remote() is nullptr"); + return false; + } + + int32_t ret = + remote->SendRequest(static_cast(IBundleInstaller::Message::UNINSTALL_MODULE), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGE("fail to uninstall, for transact is failed and error code is: %{public}d", ret); + return false; + } + return true; +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_mgr_host.cpp b/interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_mgr_host.cpp new file mode 100755 index 000000000..a4e375c7b --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_mgr_host.cpp @@ -0,0 +1,762 @@ +/* + * 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_mgr_host.h" + +#include + +#include "datetime_ex.h" +#include "ipc_types.h" +#include "string_ex.h" +#include "app_log_wrapper.h" +#include "bundle_constants.h" + +namespace OHOS { +namespace AppExecFwk { +namespace { + +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)); + } +} + +} // namespace + +int BundleMgrHost::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + APP_LOGD("bundle mgr host onReceived message, the message code is %{public}u", code); + std::u16string descripter = BundleMgrHost::GetDescriptor(); + std::u16string remoteDescripter = data.ReadInterfaceToken(); + if (descripter != remoteDescripter) { + APP_LOGE("fail to write reply message in bundle mgr host due to the reply is nullptr"); + return OBJECT_NULL; + } + + ErrCode errCode = ERR_OK; + switch (code) { + case static_cast(IBundleMgr::Message::GET_APPLICATION_INFO): + errCode = HandleGetApplicationInfo(data, reply); + break; + case static_cast(IBundleMgr::Message::GET_APPLICATION_INFOS): + errCode = HandleGetApplicationInfos(data, reply); + break; + case static_cast(IBundleMgr::Message::GET_BUNDLE_INFO): + errCode = HandleGetBundleInfo(data, reply); + break; + case static_cast(IBundleMgr::Message::GET_BUNDLE_INFOS): + errCode = HandleGetBundleInfos(data, reply); + break; + case static_cast(IBundleMgr::Message::GET_BUNDLE_NAME_FOR_UID): + errCode = HandleGetBundleNameForUid(data, reply); + break; + case static_cast(IBundleMgr::Message::GET_BUNDLE_GIDS): + errCode = HandleGetBundleGids(data, reply); + break; + case static_cast(IBundleMgr::Message::GET_BUNDLE_INFOS_BY_METADATA): + errCode = HandleGetBundleInfosByMetaData(data, reply); + break; + case static_cast(IBundleMgr::Message::QUERY_ABILITY_INFO): + errCode = HandleQueryAbilityInfo(data, reply); + break; + case static_cast(IBundleMgr::Message::QUERY_ABILITY_INFO_BY_URI): + errCode = HandleQueryAbilityInfoByUri(data, reply); + break; + case static_cast(IBundleMgr::Message::QUERY_KEEPALIVE_BUNDLE_INFOS): + errCode = HandleQueryKeepAliveBundleInfos(data, reply); + break; + case static_cast(IBundleMgr::Message::GET_ABILITY_LABEL): + errCode = HandleGetAbilityLabel(data, reply); + break; + case static_cast(IBundleMgr::Message::CHECK_IS_SYSTEM_APP_BY_UID): + errCode = HandleCheckIsSystemAppByUid(data, reply); + break; + case static_cast(IBundleMgr::Message::GET_BUNDLE_ARCHIVE_INFO): + errCode = HandleGetBundleArchiveInfo(data, reply); + break; + case static_cast(IBundleMgr::Message::GET_HAP_MODULE_INFO): + errCode = HandleGetHapModuleInfo(data, reply); + break; + case static_cast(IBundleMgr::Message::GET_LAUNCH_WANT_FOR_BUNDLE): + errCode = HandleGetLaunchWantForBundle(data, reply); + break; + case static_cast(IBundleMgr::Message::CHECK_PUBLICKEYS): + errCode = HandleGetApplicationInfo(data, reply); + break; + case static_cast(IBundleMgr::Message::CHECK_PERMISSION): + errCode = HandleCheckPermission(data, reply); + break; + case static_cast(IBundleMgr::Message::GET_PERMISSION_DEF): + errCode = HandleGetPermissionDef(data, reply); + break; + case static_cast(IBundleMgr::Message::GET_ALL_PERMISSION_GROUP_DEFS): + errCode = HandleGetAllPermissionGroupDefs(data, reply); + break; + case static_cast(IBundleMgr::Message::GET_APPS_GRANTED_PERMISSIONS): + errCode = HandleGetAppsGrantedPermissions(data, reply); + break; + case static_cast(IBundleMgr::Message::HAS_SYSTEM_CAPABILITY): + errCode = HandleHasSystemCapability(data, reply); + break; + case static_cast(IBundleMgr::Message::GET_SYSTEM_AVAILABLE_CAPABILITIES): + errCode = HandleGetSystemAvailableCapabilities(data, reply); + break; + case static_cast(IBundleMgr::Message::IS_SAFE_MODE): + errCode = HandleIsSafeMode(data, reply); + break; + case static_cast(IBundleMgr::Message::CLEAN_BUNDLE_CACHE_FILES): + errCode = HandleCleanBundleCacheFiles(data, reply); + break; + case static_cast(IBundleMgr::Message::CLEAN_BUNDLE_DATA_FILES): + errCode = HandleCleanBundleDataFiles(data, reply); + break; + case static_cast(IBundleMgr::Message::REGISTER_BUNDLE_STATUS_CALLBACK): + errCode = HandleRegisterBundleStatusCallback(data, reply); + break; + case static_cast(IBundleMgr::Message::CLEAR_BUNDLE_STATUS_CALLBACK): + errCode = HandleClearBundleStatusCallback(data, reply); + break; + case static_cast(IBundleMgr::Message::UNREGISTER_BUNDLE_STATUS_CALLBACK): + errCode = HandleUnregisterBundleStatusCallback(data, reply); + break; + case static_cast(IBundleMgr::Message::DUMP_INFOS): + errCode = HandleDumpInfos(data, reply); + break; + case static_cast(IBundleMgr::Message::GET_BUNDLE_INSTALLER): + errCode = HandleGetBundleInstaller(data, reply); + break; + case static_cast(IBundleMgr::Message::CAN_REQUEST_PERMISSION): + errCode = HandleCanRequestPermission(data, reply); + break; + case static_cast(IBundleMgr::Message::REQUEST_PERMISSION_FROM_USER): + errCode = HandleRequestPermissionFromUser(data, reply); + break; + default: + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); + } + // if ERR_OK return ipc NO_ERROR, else return ipc UNKNOW_ERROR + return (errCode == ERR_OK) ? NO_ERROR : UNKNOWN_ERROR; +} + +int BundleMgrHost::GetUidByBundleName([[maybe_unused]] const std::string &bundleName, const int userId) +{ + APP_LOGD("need not impl for host interface"); + return Constants::INVALID_UID; +} + +std::string BundleMgrHost::GetAppType([[maybe_unused]] const std::string &bundleName) +{ + APP_LOGD("need not impl for host interface"); + return Constants::EMPTY_STRING; +} + +ErrCode BundleMgrHost::HandleGetApplicationInfo(Parcel &data, Parcel &reply) +{ + std::string name = data.ReadString(); + ApplicationFlag flag = static_cast(data.ReadInt32()); + int userId = data.ReadInt32(); + APP_LOGI("name %{public}s, flag %{public}d, userId %{public}d", name.c_str(), flag, userId); + + ApplicationInfo info; + bool ret = GetApplicationInfo(name, flag, userId, info); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (ret) { + if (!reply.WriteParcelable(&info)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleGetApplicationInfos(Parcel &data, Parcel &reply) +{ + ApplicationFlag flag = static_cast(data.ReadInt32()); + int userId = data.ReadInt32(); + std::vector infos; + bool ret = GetApplicationInfos(flag, userId, infos); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (ret) { + if (!WriteParcelableVector(infos, reply)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleGetBundleInfo(Parcel &data, Parcel &reply) +{ + std::string name = data.ReadString(); + BundleFlag flag = static_cast(data.ReadInt32()); + APP_LOGI("name %{public}s, flag %{public}d", name.c_str(), flag); + BundleInfo info; + bool ret = GetBundleInfo(name, flag, info); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (ret) { + if (!reply.WriteParcelable(&info)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleGetBundleInfos(Parcel &data, Parcel &reply) +{ + BundleFlag flag = static_cast(data.ReadInt32()); + + std::vector infos; + bool ret = GetBundleInfos(flag, infos); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (ret) { + if (!WriteParcelableVector(infos, reply)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleGetBundleNameForUid(Parcel &data, Parcel &reply) +{ + int uid = data.ReadInt32(); + std::string name; + bool ret = GetBundleNameForUid(uid, name); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (ret) { + if (!reply.WriteString(name)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleGetBundleGids(Parcel &data, Parcel &reply) +{ + std::string name = data.ReadString(); + + std::vector gids; + bool ret = GetBundleGids(name, gids); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (ret) { + if (!reply.WriteInt32Vector(gids)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleGetBundleInfosByMetaData(Parcel &data, Parcel &reply) +{ + std::string metaData = data.ReadString(); + + std::vector infos; + bool ret = GetBundleInfosByMetaData(metaData, infos); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (ret) { + if (!WriteParcelableVector(infos, reply)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleQueryAbilityInfo(Parcel &data, Parcel &reply) +{ + std::unique_ptr want(data.ReadParcelable()); + if (!want) { + APP_LOGE("ReadParcelable failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + AbilityInfo info; + bool ret = QueryAbilityInfo(*want, info); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (ret) { + if (!reply.WriteParcelable(&info)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleQueryAbilityInfoByUri(Parcel &data, Parcel &reply) +{ + std::string abilityUri = data.ReadString(); + AbilityInfo info; + bool ret = QueryAbilityInfoByUri(abilityUri, info); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (ret) { + if (!reply.WriteParcelable(&info)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleQueryKeepAliveBundleInfos(Parcel &data, Parcel &reply) +{ + std::vector infos; + bool ret = QueryKeepAliveBundleInfos(infos); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (ret) { + if (!WriteParcelableVector(infos, reply)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleGetAbilityLabel(Parcel &data, Parcel &reply) +{ + std::string bundleName = data.ReadString(); + std::string className = data.ReadString(); + + APP_LOGI("bundleName %{public}s, className %{public}s", bundleName.c_str(), className.c_str()); + BundleInfo info; + std::string label = GetAbilityLabel(bundleName, className); + if (!reply.WriteString16(Str8ToStr16(label))) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleCheckIsSystemAppByUid(Parcel &data, Parcel &reply) +{ + int uid = data.ReadInt32(); + bool ret = CheckIsSystemAppByUid(uid); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleGetBundleArchiveInfo(Parcel &data, Parcel &reply) +{ + std::string hapFilePath = data.ReadString(); + BundleFlag flag = static_cast(data.ReadInt32()); + APP_LOGI("name %{public}s, flag %{public}d", hapFilePath.c_str(), flag); + + BundleInfo info; + bool ret = GetBundleArchiveInfo(hapFilePath, flag, info); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (ret) { + if (!reply.WriteParcelable(&info)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleGetHapModuleInfo(Parcel &data, Parcel &reply) +{ + std::unique_ptr abilityInfo(data.ReadParcelable()); + if (!abilityInfo) { + APP_LOGE("ReadParcelable failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + HapModuleInfo info; + bool ret = GetHapModuleInfo(*abilityInfo, info); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (ret) { + if (!reply.WriteParcelable(&info)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleGetLaunchWantForBundle(Parcel &data, Parcel &reply) +{ + std::string bundleName = data.ReadString(); + APP_LOGI("name %{public}s", bundleName.c_str()); + + Want want; + bool ret = GetLaunchWantForBundle(bundleName, want); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (ret) { + if (!reply.WriteParcelable(&want)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleCheckPublicKeys(Parcel &data, Parcel &reply) +{ + std::string firstBundleName = data.ReadString(); + std::string secondBundleName = data.ReadString(); + + APP_LOGI( + "firstBundleName %{public}s, secondBundleName %{public}s", firstBundleName.c_str(), secondBundleName.c_str()); + int ret = CheckPublicKeys(firstBundleName, secondBundleName); + if (!reply.WriteInt32(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleCheckPermission(Parcel &data, Parcel &reply) +{ + std::string bundleName = data.ReadString(); + std::string permission = data.ReadString(); + + APP_LOGI("bundleName %{public}s, permission %{public}s", bundleName.c_str(), permission.c_str()); + int ret = CheckPermission(bundleName, permission); + if (!reply.WriteInt32(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleGetPermissionDef(Parcel &data, Parcel &reply) +{ + std::string permissionName = data.ReadString(); + APP_LOGI("name %{public}s", permissionName.c_str()); + + PermissionDef permissionDef; + bool ret = GetPermissionDef(permissionName, permissionDef); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (ret) { + if (!reply.WriteParcelable(&permissionDef)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleGetAllPermissionGroupDefs(Parcel &data, Parcel &reply) +{ + std::vector permissionDefs; + bool ret = GetAllPermissionGroupDefs(permissionDefs); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (ret) { + if (!WriteParcelableVector(permissionDefs, reply)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleGetAppsGrantedPermissions(Parcel &data, Parcel &reply) +{ + std::vector permissions; + if (data.ReadStringVector(&permissions)) { + APP_LOGE("read failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + + std::vector appNames; + bool ret = GetAppsGrantedPermissions(permissions, appNames); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (ret) { + if (!reply.WriteStringVector(appNames)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleHasSystemCapability(Parcel &data, Parcel &reply) +{ + std::string capName = data.ReadString(); + + bool ret = HasSystemCapability(capName); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleGetSystemAvailableCapabilities(Parcel &data, Parcel &reply) +{ + std::vector caps; + bool ret = GetSystemAvailableCapabilities(caps); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (ret) { + if (!reply.WriteStringVector(caps)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleIsSafeMode(Parcel &data, Parcel &reply) +{ + bool ret = IsSafeMode(); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleCleanBundleCacheFiles(Parcel &data, Parcel &reply) +{ + std::string bundleName = data.ReadString(); + sptr object = data.ReadParcelable(); + sptr cleanCacheCallback = iface_cast(object); + + bool ret = CleanBundleCacheFiles(bundleName, cleanCacheCallback); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleCleanBundleDataFiles(Parcel &data, Parcel &reply) +{ + std::string bundleName = data.ReadString(); + + bool ret = CleanBundleDataFiles(bundleName); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleRegisterBundleStatusCallback(Parcel &data, Parcel &reply) +{ + std::string bundleName = data.ReadString(); + sptr object = data.ReadParcelable(); + sptr BundleStatusCallback = iface_cast(object); + + bool ret = false; + if (bundleName.empty() || !BundleStatusCallback) { + APP_LOGE("Get BundleStatusCallback failed"); + } else { + BundleStatusCallback->SetBundleName(bundleName); + ret = RegisterBundleStatusCallback(BundleStatusCallback); + } + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleClearBundleStatusCallback(Parcel &data, Parcel &reply) +{ + sptr object = data.ReadParcelable(); + sptr BundleStatusCallback = iface_cast(object); + + bool ret = ClearBundleStatusCallback(BundleStatusCallback); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleUnregisterBundleStatusCallback(Parcel &data, Parcel &reply) +{ + bool ret = UnregisterBundleStatusCallback(); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleDumpInfos(Parcel &data, Parcel &reply) +{ + DumpFlag flag = static_cast(data.ReadInt32()); + std::string bundleName = data.ReadString(); + + std::string result; + bool ret = DumpInfos(flag, bundleName, result); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + if (ret) { + std::vector dumpInfos; + SplitString(result, dumpInfos); + if (!reply.WriteStringVector(dumpInfos)) { + return ERR_APPEXECFWK_PARCEL_ERROR; + } + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleIsApplicationEnabled(Parcel &data, Parcel &reply) +{ + std::string bundleName = data.ReadString(); + bool ret = IsApplicationEnabled(bundleName); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleSetApplicationEnabled(Parcel &data, Parcel &reply) +{ + std::string bundleName = data.ReadString(); + bool isEnable = data.ReadBool(); + bool ret = SetApplicationEnabled(bundleName, isEnable); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleCanRequestPermission(Parcel &data, Parcel &reply) +{ + std::string bundleName = data.ReadString(); + std::string permission = data.ReadString(); + int32_t userId = data.ReadInt32(); + + APP_LOGI("bundleName %{public}s, permission %{public}s", bundleName.c_str(), permission.c_str()); + bool ret = CanRequestPermission(bundleName, permission, userId); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleRequestPermissionFromUser(Parcel &data, Parcel &reply) +{ + std::string bundleName = data.ReadString(); + std::string permission = data.ReadString(); + int32_t userId = data.ReadInt32(); + + APP_LOGI("bundleName %{public}s, permission %{public}s", bundleName.c_str(), permission.c_str()); + bool ret = RequestPermissionFromUser(bundleName, permission, userId); + if (!reply.WriteBool(ret)) { + APP_LOGE("write failed"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + return ERR_OK; +} + +ErrCode BundleMgrHost::HandleGetBundleInstaller(Parcel &data, Parcel &reply) +{ + sptr installer = GetBundleInstaller(); + if (!installer) { + APP_LOGE("bundle installer is nullptr"); + return ERR_APPEXECFWK_INSTALL_HOST_INSTALLER_FAILED; + } + + if (!reply.WriteParcelable(installer->AsObject())) { + APP_LOGE("failed to reply bundle installer to client, for write parcel error"); + return ERR_APPEXECFWK_PARCEL_ERROR; + } + return ERR_OK; +} + +template +bool BundleMgrHost::WriteParcelableVector(std::vector &parcelableVector, Parcel &reply) +{ + if (!reply.WriteInt32(parcelableVector.size())) { + APP_LOGE("write ParcelableVector failed"); + return false; + } + + for (auto &parcelable : parcelableVector) { + if (!reply.WriteParcelable(&parcelable)) { + APP_LOGE("write ParcelableVector failed"); + return false; + } + } + return true; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_mgr_proxy.cpp b/interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_mgr_proxy.cpp new file mode 100644 index 000000000..4c0027f1b --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_mgr_proxy.cpp @@ -0,0 +1,1022 @@ +/* + * 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_mgr_proxy.h" + +#include "ipc_types.h" +#include "parcel.h" +#include "string_ex.h" + +#include "appexecfwk_errors.h" +#include "app_log_wrapper.h" +#include "bundle_constants.h" + +namespace OHOS { +namespace AppExecFwk { + +BundleMgrProxy::BundleMgrProxy(const sptr &impl) : IRemoteProxy(impl) +{ + APP_LOGI("create bundle mgr proxy instance"); +} + +BundleMgrProxy::~BundleMgrProxy() +{ + APP_LOGI("destroy create bundle mgr proxy instance"); +} + +bool BundleMgrProxy::GetApplicationInfo( + const std::string &appName, const ApplicationFlag flag, const int userId, ApplicationInfo &appInfo) +{ + APP_LOGI("begin to GetApplicationInfo of %{public}s", appName.c_str()); + if (appName.empty()) { + APP_LOGE("fail to GetApplicationInfo due to params empty"); + return false; + } + + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to GetApplicationInfo due to write MessageParcel fail"); + return false; + } + if (!data.WriteString(appName)) { + APP_LOGE("fail to GetApplicationInfo due to write appName fail"); + return false; + } + if (!data.WriteInt32(static_cast(flag))) { + APP_LOGE("fail to GetApplicationInfo due to write flag fail"); + return false; + } + if (!data.WriteInt32(userId)) { + APP_LOGE("fail to GetApplicationInfo due to write userId fail"); + return false; + } + + if (!GetParcelableInfo(IBundleMgr::Message::GET_APPLICATION_INFO, data, appInfo)) { + APP_LOGE("fail to GetApplicationInfo from server"); + return false; + } + return true; +} + +bool BundleMgrProxy::GetApplicationInfos( + const ApplicationFlag flag, const int userId, std::vector &appInfos) +{ + APP_LOGD("begin to get GetApplicationInfos of specific userId id %{private}d", userId); + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to GetApplicationInfo due to write MessageParcel fail"); + return false; + } + if (!data.WriteInt32(static_cast(flag))) { + APP_LOGE("fail to GetApplicationInfo due to write flag fail"); + return false; + } + if (!data.WriteInt32(userId)) { + APP_LOGE("fail to GetApplicationInfos due to write userId error"); + return false; + } + + if (!GetParcelableInfos(IBundleMgr::Message::GET_APPLICATION_INFOS, data, appInfos)) { + APP_LOGE("fail to GetApplicationInfos from server"); + return false; + } + return true; +} + +bool BundleMgrProxy::GetBundleInfo(const std::string &bundleName, const BundleFlag flag, BundleInfo &bundleInfo) +{ + APP_LOGI("begin to get bundle info of %{public}s", bundleName.c_str()); + if (bundleName.empty()) { + APP_LOGE("fail to GetBundleInfo due to params empty"); + return false; + } + + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to GetBundleInfo due to write InterfaceToken fail"); + return false; + } + if (!data.WriteString(bundleName)) { + APP_LOGE("fail to GetBundleInfo due to write bundleName fail"); + return false; + } + if (!data.WriteInt32(static_cast(flag))) { + APP_LOGE("fail to GetBundleInfo due to write flag fail"); + return false; + } + + if (!GetParcelableInfo(IBundleMgr::Message::GET_BUNDLE_INFO, data, bundleInfo)) { + APP_LOGE("fail to GetBundleInfo from server"); + return false; + } + return true; +} + +bool BundleMgrProxy::GetBundleInfos(const BundleFlag flag, std::vector &bundleInfos) +{ + APP_LOGD("begin to get bundle infos"); + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to GetBundleInfos due to write InterfaceToken fail"); + return false; + } + if (!data.WriteInt32(static_cast(flag))) { + APP_LOGE("fail to GetBundleInfos due to write flag fail"); + return false; + } + + if (!GetParcelableInfos(IBundleMgr::Message::GET_BUNDLE_INFOS, data, bundleInfos)) { + APP_LOGE("fail to GetBundleInfos from server"); + return false; + } + return true; +} + +int BundleMgrProxy::GetUidByBundleName(const std::string &bundleName, const int userId) +{ + APP_LOGI("begin to get uid of %{public}s", bundleName.c_str()); + BundleInfo bundleInfo; + int uid = Constants::INVALID_UID; + bool ret = GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); + if (ret) { + uid = bundleInfo.uid; + APP_LOGD("get bundle uid success"); + } else { + APP_LOGE("can not get bundleInfo's uid"); + } + return uid; +} + +bool BundleMgrProxy::GetBundleNameForUid(const int uid, std::string &bundleName) +{ + APP_LOGI("begin to GetBundleNameForUid of %{public}d", uid); + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to GetBundleNameForUid due to write InterfaceToken fail"); + return false; + } + if (!data.WriteInt32(uid)) { + APP_LOGE("fail to GetBundleNameForUid due to write uid fail"); + return false; + } + + MessageParcel reply; + if (!SendTransactCmd(IBundleMgr::Message::GET_BUNDLE_NAME_FOR_UID, data, reply)) { + APP_LOGE("fail to GetBundleNameForUid from server"); + return false; + } + if (!reply.ReadBool()) { + APP_LOGE("reply result false"); + return false; + } + bundleName = reply.ReadString(); + return true; +} + +bool BundleMgrProxy::GetBundleGids(const std::string &bundleName, std::vector &gids) +{ + APP_LOGI("begin to GetBundleGids of %{public}s", bundleName.c_str()); + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to GetBundleGids due to write InterfaceToken fail"); + return false; + } + if (!data.WriteString(bundleName)) { + APP_LOGE("fail to GetBundleGids due to write bundleName fail"); + return false; + } + + MessageParcel reply; + if (!SendTransactCmd(IBundleMgr::Message::GET_BUNDLE_GIDS, data, reply)) { + APP_LOGE("fail to GetBundleGids from server"); + return false; + } + + if (!reply.ReadInt32Vector(&gids)) { + APP_LOGE("fail to GetBundleGids from reply"); + return false; + } + return true; +} + +std::string BundleMgrProxy::GetAppType(const std::string &bundleName) +{ + APP_LOGI("begin to GetAppType of %{public}s", bundleName.c_str()); + BundleInfo bundleInfo; + bool ret = GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); + if (ret) { + bool isSystemApp = bundleInfo.applicationInfo.isSystemApp; + APP_LOGD("get GetAppType success"); + if (isSystemApp) { + return Constants::SYSTEM_APP; + } else { + return Constants::THIRD_PARTY_APP; + } + } + APP_LOGE("can not GetAppType"); + return Constants::EMPTY_STRING; +} + +bool BundleMgrProxy::CheckIsSystemAppByUid(const int uid) +{ + APP_LOGI("begin to CheckIsSystemAppByUid of %{public}d", uid); + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to CheckIsSystemAppByUid due to write InterfaceToken fail"); + return false; + } + if (!data.WriteInt32(uid)) { + APP_LOGE("fail to CheckIsSystemAppByUid due to write uid fail"); + return false; + } + + MessageParcel reply; + if (!SendTransactCmd(IBundleMgr::Message::CHECK_IS_SYSTEM_APP_BY_UID, data, reply)) { + APP_LOGE("fail to CheckIsSystemAppByUid from server"); + return false; + } + return reply.ReadBool(); +} + +bool BundleMgrProxy::GetBundleInfosByMetaData(const std::string &metaData, std::vector &bundleInfos) +{ + APP_LOGI("begin to GetBundleInfosByMetaData of %{public}s", metaData.c_str()); + if (metaData.empty()) { + APP_LOGE("fail to GetBundleInfosByMetaData due to params empty"); + return false; + } + + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to GetBundleInfosByMetaData due to write InterfaceToken fail"); + return false; + } + if (!data.WriteString(metaData)) { + APP_LOGE("fail to GetBundleInfosByMetaData due to write metaData fail"); + return false; + } + + if (!GetParcelableInfos(IBundleMgr::Message::GET_BUNDLE_INFOS_BY_METADATA, data, bundleInfos)) { + APP_LOGE("fail to GetBundleInfosByMetaData from server"); + return false; + } + return true; +} + +bool BundleMgrProxy::QueryAbilityInfo(const Want &want, AbilityInfo &abilityInfo) +{ + 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 (!GetParcelableInfo(IBundleMgr::Message::QUERY_ABILITY_INFO, data, abilityInfo)) { + APP_LOGE("fail to query ability info from server"); + return false; + } + return true; +} + +bool BundleMgrProxy::QueryAbilityInfoByUri(const std::string &abilityUri, AbilityInfo &abilityInfo) +{ + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to QueryAbilityInfoByUri due to write MessageParcel fail"); + return false; + } + if (!data.WriteString(abilityUri)) { + APP_LOGE("fail to QueryAbilityInfoByUri due to write abilityUri fail"); + return false; + } + + if (!GetParcelableInfo(IBundleMgr::Message::QUERY_ABILITY_INFO_BY_URI, data, abilityInfo)) { + APP_LOGE("fail to QueryAbilityInfoByUri from server"); + return false; + } + return true; +} + +bool BundleMgrProxy::QueryKeepAliveBundleInfos(std::vector &bundleInfos) +{ + APP_LOGI("begin to QueryKeepAliveBundleInfos"); + + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to QueryKeepAliveBundleInfos due to write InterfaceToken fail"); + return false; + } + + if (!GetParcelableInfos(IBundleMgr::Message::QUERY_KEEPALIVE_BUNDLE_INFOS, data, bundleInfos)) { + APP_LOGE("fail to QueryKeepAliveBundleInfos from server"); + return false; + } + return true; +} + +std::string BundleMgrProxy::GetAbilityLabel(const std::string &bundleName, const std::string &className) +{ + APP_LOGI("begin to get bundle info of %{public}s", bundleName.c_str()); + if (bundleName.empty()) { + APP_LOGE("fail to GetAbilityLabel due to params empty"); + return Constants::EMPTY_STRING; + } + + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to GetAbilityLabel due to write InterfaceToken fail"); + return Constants::EMPTY_STRING; + } + if (!data.WriteString(bundleName)) { + APP_LOGE("fail to GetAbilityLabel due to write bundleName fail"); + return Constants::EMPTY_STRING; + } + if (!data.WriteString(className)) { + APP_LOGE("fail to GetAbilityLabel due to write className fail"); + return Constants::EMPTY_STRING; + } + + MessageParcel reply; + if (!SendTransactCmd(IBundleMgr::Message::GET_ABILITY_LABEL, data, reply)) { + APP_LOGE("fail to GetAbilityLabel from server"); + return Constants::EMPTY_STRING; + } + return reply.ReadString(); +} + +bool BundleMgrProxy::GetBundleArchiveInfo(const std::string &hapFilePath, const BundleFlag flag, BundleInfo &bundleInfo) +{ + APP_LOGI("begin to GetBundleArchiveInfo of %{public}s", hapFilePath.c_str()); + if (hapFilePath.empty()) { + APP_LOGE("fail to GetBundleArchiveInfo due to params empty"); + return false; + } + + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to GetBundleArchiveInfo due to write InterfaceToken fail"); + return false; + } + if (!data.WriteString(hapFilePath)) { + APP_LOGE("fail to GetBundleArchiveInfo due to write hapFilePath fail"); + return false; + } + if (!data.WriteInt32(static_cast(flag))) { + APP_LOGE("fail to GetBundleArchiveInfo due to write flag fail"); + return false; + } + + if (!GetParcelableInfo(IBundleMgr::Message::GET_BUNDLE_ARCHIVE_INFO, data, bundleInfo)) { + APP_LOGE("fail to GetBundleArchiveInfo from server"); + return false; + } + return true; +} + +bool BundleMgrProxy::GetHapModuleInfo(const AbilityInfo &abilityInfo, HapModuleInfo &hapModuleInfo) +{ + APP_LOGI("begin to GetHapModuleInfo of %{public}s", abilityInfo.package.c_str()); + if (abilityInfo.bundleName.empty() || abilityInfo.package.empty()) { + APP_LOGE("fail to GetHapModuleInfo due to params empty"); + return false; + } + + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to GetHapModuleInfo due to write InterfaceToken fail"); + return false; + } + if (!data.WriteParcelable(&abilityInfo)) { + APP_LOGE("fail to GetHapModuleInfo due to write abilityInfo fail"); + return false; + } + + if (!GetParcelableInfo(IBundleMgr::Message::GET_HAP_MODULE_INFO, data, hapModuleInfo)) { + APP_LOGE("fail to GetHapModuleInfo from server"); + return false; + } + return true; +} + +bool BundleMgrProxy::GetLaunchWantForBundle(const std::string &bundleName, Want &want) +{ + APP_LOGI("begin to GetLaunchWantForBundle of %{public}s", bundleName.c_str()); + if (bundleName.empty()) { + APP_LOGE("fail to GetHapModuleInfo due to params empty"); + return false; + } + + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to GetLaunchWantForBundle due to write InterfaceToken fail"); + return false; + } + if (!data.WriteString(bundleName)) { + APP_LOGE("fail to GetLaunchWantForBundle due to write bundleName fail"); + return false; + } + + if (!GetParcelableInfo(IBundleMgr::Message::GET_LAUNCH_WANT_FOR_BUNDLE, data, want)) { + APP_LOGE("fail to GetLaunchWantForBundle from server"); + return false; + } + return true; +} + +int BundleMgrProxy::CheckPublicKeys(const std::string &firstBundleName, const std::string &secondBundleName) +{ + APP_LOGI( + "begin to CheckPublicKeys of %{public}s and %{public}s", firstBundleName.c_str(), secondBundleName.c_str()); + if (firstBundleName.empty() || secondBundleName.empty()) { + APP_LOGE("fail to CheckPublicKeys due to params empty"); + return Constants::SIGNATURE_UNKNOWN_BUNDLE; + } + + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to GetBundleInfo due to write MessageParcel fail"); + return Constants::SIGNATURE_UNKNOWN_BUNDLE; + } + if (!data.WriteString(firstBundleName)) { + APP_LOGE("fail to GetBundleInfo due to write firstBundleName fail"); + return Constants::SIGNATURE_UNKNOWN_BUNDLE; + } + if (!data.WriteString(secondBundleName)) { + APP_LOGE("fail to GetBundleInfo due to write secondBundleName fail"); + return Constants::SIGNATURE_UNKNOWN_BUNDLE; + } + + MessageParcel reply; + if (!SendTransactCmd(IBundleMgr::Message::CHECK_PUBLICKEYS, data, reply)) { + APP_LOGE("fail to CheckPublicKeys from server"); + return Constants::SIGNATURE_UNKNOWN_BUNDLE; + } + return reply.ReadInt32(); +} + +int BundleMgrProxy::CheckPermission(const std::string &bundleName, const std::string &permission) +{ + APP_LOGI("begin to CheckPublicKeys of %{public}s and %{public}s", bundleName.c_str(), permission.c_str()); + if (bundleName.empty() || permission.empty()) { + APP_LOGE("fail to CheckPermission due to params empty"); + return Constants::PERMISSION_NOT_GRANTED; + } + + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to CheckPermission due to write InterfaceToken fail"); + return Constants::PERMISSION_NOT_GRANTED; + } + if (!data.WriteString(bundleName)) { + APP_LOGE("fail to CheckPermission due to write bundleName fail"); + return Constants::PERMISSION_NOT_GRANTED; + } + if (!data.WriteString(permission)) { + APP_LOGE("fail to CheckPermission due to write permission fail"); + return Constants::PERMISSION_NOT_GRANTED; + } + + MessageParcel reply; + if (!SendTransactCmd(IBundleMgr::Message::CHECK_PERMISSION, data, reply)) { + APP_LOGE("fail to CheckPermission from server"); + return Constants::PERMISSION_NOT_GRANTED; + } + return reply.ReadInt32(); +} + +bool BundleMgrProxy::GetPermissionDef(const std::string &permissionName, PermissionDef &permissionDef) +{ + APP_LOGI("begin to GetPermissionDef of %{public}s", permissionName.c_str()); + if (permissionName.empty()) { + APP_LOGE("fail to GetPermissionDef due to params empty"); + return false; + } + + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to GetPermissionDef due to write InterfaceToken fail"); + return false; + } + if (!data.WriteString(permissionName)) { + APP_LOGE("fail to GetPermissionDef due to write permissionName fail"); + return false; + } + + if (!GetParcelableInfo(IBundleMgr::Message::GET_PERMISSION_DEF, data, permissionDef)) { + APP_LOGE("fail to GetPermissionDef from server"); + return false; + } + return true; +} + +bool BundleMgrProxy::GetAllPermissionGroupDefs(std::vector &permissionDefs) +{ + APP_LOGI("begin to GetPermissionDefs"); + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to GetAllPermissionGroupDefs due to write InterfaceToken fail"); + return false; + } + + if (!GetParcelableInfos(IBundleMgr::Message::GET_ALL_PERMISSION_GROUP_DEFS, data, permissionDefs)) { + APP_LOGE("fail to GetAllPermissionGroupDefs from server"); + return false; + } + return true; +} + +bool BundleMgrProxy::GetAppsGrantedPermissions( + const std::vector &permissions, std::vector &appNames) +{ + APP_LOGI("begin to GetAppsGrantedPermissions"); + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to GetAppsGrantedPermissions due to write InterfaceToken fail"); + return false; + } + if (!data.WriteStringVector(permissions)) { + APP_LOGE("fail to GetAppsGrantedPermissions due to write permissions fail"); + return false; + } + + MessageParcel reply; + if (!SendTransactCmd(IBundleMgr::Message::GET_APPS_GRANTED_PERMISSIONS, data, reply)) { + APP_LOGE("fail to GetAppsGrantedPermissions from server"); + return false; + } + + if (!reply.ReadStringVector(&appNames)) { + APP_LOGE("fail to GetAppsGrantedPermissions from reply"); + return false; + } + + return true; +} + +bool BundleMgrProxy::HasSystemCapability(const std::string &capName) +{ + APP_LOGI("begin to HasSystemCapability of %{public}s", capName.c_str()); + if (capName.empty()) { + APP_LOGE("fail to HasSystemCapability due to params empty"); + return false; + } + + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to HasSystemCapability due to write InterfaceToken fail"); + return false; + } + if (!data.WriteString(capName)) { + APP_LOGE("fail to HasSystemCapability due to write capName fail"); + return false; + } + + MessageParcel reply; + if (!SendTransactCmd(IBundleMgr::Message::HAS_SYSTEM_CAPABILITY, data, reply)) { + APP_LOGE("fail to HasSystemCapability from server"); + return false; + } + return reply.ReadBool(); +} + +bool BundleMgrProxy::GetSystemAvailableCapabilities(std::vector &systemCaps) +{ + APP_LOGI("begin to GetSystemAvailableCapabilities"); + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to GetSystemAvailableCapabilities due to write InterfaceToken fail"); + return false; + } + + MessageParcel reply; + if (!SendTransactCmd(IBundleMgr::Message::GET_SYSTEM_AVAILABLE_CAPABILITIES, data, reply)) { + APP_LOGE("fail to GetSystemAvailableCapabilities from server"); + return false; + } + + if (!reply.ReadStringVector(&systemCaps)) { + APP_LOGE("fail to GetSystemAvailableCapabilities from reply"); + return false; + } + + return true; +} + +bool BundleMgrProxy::IsSafeMode() +{ + APP_LOGI("begin to IsSafeMode"); + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to IsSafeMode due to write InterfaceToken fail"); + return false; + } + + MessageParcel reply; + if (!SendTransactCmd(IBundleMgr::Message::IS_SAFE_MODE, data, reply)) { + APP_LOGE("fail to IsSafeMode from server"); + return false; + } + return reply.ReadBool(); +} + +bool BundleMgrProxy::CleanBundleCacheFiles( + const std::string &bundleName, const sptr &cleanCacheCallback) +{ + APP_LOGI("begin to CleanBundleCacheFiles of %{public}s", bundleName.c_str()); + if (bundleName.empty() || !cleanCacheCallback) { + APP_LOGE("fail to CleanBundleCacheFiles due to params error"); + return false; + } + + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to CleanBundleCacheFiles due to write InterfaceToken fail"); + return false; + } + if (!data.WriteString(bundleName)) { + APP_LOGE("fail to CleanBundleCacheFiles due to write bundleName fail"); + return false; + } + + if (!data.WriteParcelable(cleanCacheCallback->AsObject())) { + APP_LOGE("fail to CleanBundleCacheFiles, for write parcel failed"); + return false; + } + + MessageParcel reply; + if (!SendTransactCmd(IBundleMgr::Message::CLEAN_BUNDLE_CACHE_FILES, data, reply)) { + APP_LOGE("fail to CleanBundleCacheFiles from server"); + return false; + } + return reply.ReadBool(); +} + +bool BundleMgrProxy::CleanBundleDataFiles(const std::string &bundleName) +{ + APP_LOGI("begin to CleanBundleDataFiles of %{public}s", bundleName.c_str()); + if (bundleName.empty()) { + APP_LOGE("fail to CleanBundleDataFiles due to params empty"); + return false; + } + + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to CleanBundleDataFiles due to write InterfaceToken fail"); + return false; + } + if (!data.WriteString(bundleName)) { + APP_LOGE("fail to CleanBundleDataFiles due to write hapFilePath fail"); + return false; + } + + MessageParcel reply; + if (!SendTransactCmd(IBundleMgr::Message::CLEAN_BUNDLE_DATA_FILES, data, reply)) { + APP_LOGE("fail to CleanBundleDataFiles from server"); + return false; + } + return reply.ReadBool(); +} + +bool BundleMgrProxy::RegisterBundleStatusCallback(const sptr &bundleStatusCallback) +{ + APP_LOGI("begin to RegisterBundleStatusCallback"); + if (!bundleStatusCallback || bundleStatusCallback->GetBundleName().empty()) { + APP_LOGE("fail to RegisterBundleStatusCallback"); + return false; + } + + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to RegisterBundleStatusCallback due to write InterfaceToken fail"); + return false; + } + if (!data.WriteString(bundleStatusCallback->GetBundleName())) { + APP_LOGE("fail to RegisterBundleStatusCallback due to write bundleName fail"); + return false; + } + if (!data.WriteParcelable(bundleStatusCallback->AsObject())) { + APP_LOGE("fail to RegisterBundleStatusCallback, for write parcel failed"); + return false; + } + + MessageParcel reply; + if (!SendTransactCmd(IBundleMgr::Message::REGISTER_BUNDLE_STATUS_CALLBACK, data, reply)) { + APP_LOGE("fail to RegisterBundleStatusCallback from server"); + return false; + } + return reply.ReadBool(); +} + +bool BundleMgrProxy::ClearBundleStatusCallback(const sptr &bundleStatusCallback) +{ + APP_LOGI("begin to ClearBundleStatusCallback"); + if (!bundleStatusCallback) { + APP_LOGE("fail to ClearBundleStatusCallback, for bundleStatusCallback is nullptr"); + return false; + } + + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to ClearBundleStatusCallback due to write InterfaceToken fail"); + return false; + } + if (!data.WriteParcelable(bundleStatusCallback->AsObject())) { + APP_LOGE("fail to ClearBundleStatusCallback, for write parcel failed"); + return false; + } + + MessageParcel reply; + if (!SendTransactCmd(IBundleMgr::Message::CLEAR_BUNDLE_STATUS_CALLBACK, data, reply)) { + APP_LOGE("fail to CleanBundleCacheFiles from server"); + return false; + } + return reply.ReadBool(); +} + +bool BundleMgrProxy::UnregisterBundleStatusCallback() +{ + APP_LOGI("begin to UnregisterBundleStatusCallback"); + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to UnregisterBundleStatusCallback due to write InterfaceToken fail"); + return false; + } + + MessageParcel reply; + if (!SendTransactCmd(IBundleMgr::Message::UNREGISTER_BUNDLE_STATUS_CALLBACK, data, reply)) { + APP_LOGE("fail to UnregisterBundleStatusCallback from server"); + return false; + } + return reply.ReadBool(); +} + +bool BundleMgrProxy::DumpInfos(const DumpFlag flag, const std::string &bundleName, std::string &result) +{ + APP_LOGD("begin to dump"); + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to dump due to write InterfaceToken fail"); + return false; + } + if (!data.WriteInt32(static_cast(flag))) { + APP_LOGE("fail to dump due to write flag fail"); + return false; + } + if (!data.WriteString(bundleName)) { + APP_LOGE("fail to dump due to write bundleName fail"); + return false; + } + + MessageParcel reply; + if (!SendTransactCmd(IBundleMgr::Message::DUMP_INFOS, data, reply)) { + APP_LOGE("fail to dump from server"); + return false; + } + if (!reply.ReadBool()) { + APP_LOGE("readParcelableInfo failed"); + return false; + } + std::vector dumpInfos; + if (!reply.ReadStringVector(&dumpInfos)) { + APP_LOGE("fail to dump from reply"); + return false; + } + for (auto &dumpinfo : dumpInfos) { + result += dumpinfo; + } + return true; +} + +bool BundleMgrProxy::IsApplicationEnabled(const std::string &bundleName) +{ + APP_LOGI("begin to IsApplicationEnabled of %{public}s", bundleName.c_str()); + if (bundleName.empty()) { + APP_LOGE("fail to IsApplicationEnabled due to params empty"); + return false; + } + + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to IsApplicationEnabled due to write InterfaceToken fail"); + return false; + } + if (!data.WriteString(bundleName)) { + APP_LOGE("fail to IsApplicationEnabled due to write bundleName fail"); + return false; + } + + MessageParcel reply; + if (!SendTransactCmd(IBundleMgr::Message::IS_APPLICATION_ENABLED, data, reply)) { + APP_LOGE("fail to IsApplicationEnabled from server"); + return false; + } + return reply.ReadBool(); +} + +bool BundleMgrProxy::SetApplicationEnabled(const std::string &bundleName, bool isEnable) +{ + APP_LOGI("begin to SetApplicationEnabled of %{public}s", bundleName.c_str()); + if (bundleName.empty()) { + APP_LOGE("fail to SetApplicationEnabled due to params empty"); + return false; + } + + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to SetApplicationEnabled due to write InterfaceToken fail"); + return false; + } + if (!data.WriteString(bundleName)) { + APP_LOGE("fail to SetApplicationEnabled due to write bundleName fail"); + return false; + } + if (!data.WriteBool(isEnable)) { + APP_LOGE("fail to IsApplicationEnabled due to write isEnable fail"); + return false; + } + + MessageParcel reply; + if (!SendTransactCmd(IBundleMgr::Message::SET_APPLICATION_ENABLED, data, reply)) { + APP_LOGE("fail to SetApplicationEnabled from server"); + return false; + } + return reply.ReadBool(); +} + +sptr BundleMgrProxy::GetBundleInstaller() +{ + APP_LOGD("begin to get bundle installer"); + MessageParcel data; + MessageParcel reply; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to GetBundleInstaller due to write InterfaceToken fail"); + return nullptr; + } + if (!SendTransactCmd(IBundleMgr::Message::GET_BUNDLE_INSTALLER, data, reply)) { + return nullptr; + } + + sptr object = reply.ReadParcelable(); + sptr installer = iface_cast(object); + if (!installer) { + APP_LOGE("bundle installer is nullptr"); + } + + APP_LOGD("get bundle installer success"); + return installer; +} + +bool BundleMgrProxy::CanRequestPermission( + const std::string &bundleName, const std::string &permissionName, const int userId) +{ + APP_LOGI("begin to CanRequestPermission of %{public}s and %{public}s", bundleName.c_str(), permissionName.c_str()); + if (bundleName.empty() || permissionName.empty()) { + APP_LOGE("fail to CanRequestPermission due to params empty"); + return false; + } + + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to CanRequestPermission due to write InterfaceToken fail"); + return false; + } + if (!data.WriteString(bundleName)) { + APP_LOGE("fail to CanRequestPermission due to write bundleName fail"); + return false; + } + if (!data.WriteString(permissionName)) { + APP_LOGE("fail to CanRequestPermission due to write permission fail"); + return false; + } + if (!data.WriteInt32(userId)) { + APP_LOGE("fail to CanRequestPermission due to write userId fail"); + return false; + } + + MessageParcel reply; + if (!SendTransactCmd(IBundleMgr::Message::CAN_REQUEST_PERMISSION, data, reply)) { + APP_LOGE("fail to CanRequestPermission from server"); + return false; + } + return reply.ReadBool(); +} + +bool BundleMgrProxy::RequestPermissionFromUser( + const std::string &bundleName, const std::string &permission, const int userId) +{ + APP_LOGI("begin to RequestPermissionsFromUser of %{public}s", bundleName.c_str()); + if (bundleName.empty() || permission.empty()) { + APP_LOGE("fail to RequestPermissionsFromUser due to params empty"); + return false; + } + + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to RequestPermissionsFromUser due to write InterfaceToken fail"); + return false; + } + if (!data.WriteString(bundleName)) { + APP_LOGE("fail to RequestPermissionsFromUser due to write bundleName fail"); + return false; + } + if (!data.WriteString(permission)) { + APP_LOGE("fail to RequestPermissionsFromUser due to write permission fail"); + return false; + } + if (!data.WriteInt32(userId)) { + APP_LOGE("fail to RequestPermissionsFromUser due to write userId fail"); + return false; + } + + MessageParcel reply; + if (!SendTransactCmd(IBundleMgr::Message::CAN_REQUEST_PERMISSION, data, reply)) { + APP_LOGE("fail to RequestPermissionsFromUser from server"); + return false; + } + return reply.ReadBool(); +} + +template +bool BundleMgrProxy::GetParcelableInfo(IBundleMgr::Message code, MessageParcel &data, T &parcelableInfo) +{ + MessageParcel reply; + if (!SendTransactCmd(code, data, reply)) { + return false; + } + + if (!reply.ReadBool()) { + APP_LOGE("reply result false"); + return false; + } + + std::unique_ptr info(reply.ReadParcelable()); + if (!info) { + APP_LOGE("readParcelableInfo failed"); + return false; + } + parcelableInfo = *info; + APP_LOGD("get parcelable info success"); + return true; +} + +template +bool BundleMgrProxy::GetParcelableInfos(IBundleMgr::Message code, MessageParcel &data, std::vector &parcelableInfos) +{ + MessageParcel reply; + if (!SendTransactCmd(code, data, reply)) { + return false; + } + + if (!reply.ReadBool()) { + APP_LOGE("readParcelableInfo failed"); + return false; + } + + int32_t infoSize = reply.ReadInt32(); + for (int32_t i = 0; i < infoSize; i++) { + std::unique_ptr info(reply.ReadParcelable()); + if (!info) { + APP_LOGE("Read Parcelable infos failed"); + return false; + } + parcelableInfos.emplace_back(*info); + } + APP_LOGD("get parcelable infos success"); + return true; +} + +bool BundleMgrProxy::SendTransactCmd(IBundleMgr::Message code, MessageParcel &data, MessageParcel &reply) +{ + MessageOption option(MessageOption::TF_SYNC); + + sptr remote = Remote(); + if (!remote) { + APP_LOGE("fail to send transact cmd %{public}d due to remote object", code); + return false; + } + int32_t result = remote->SendRequest(static_cast(code), data, reply, option); + if (result != NO_ERROR) { + APP_LOGE("receive error transact code %{public}d in transact cmd %{public}d", result, code); + return false; + } + return true; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_status_callback_host.cpp b/interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_status_callback_host.cpp new file mode 100644 index 000000000..9ed33bc86 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_status_callback_host.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 "bundle_status_callback_host.h" + +#include "ipc_types.h" +#include "string_ex.h" + +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { + +BundleStatusCallbackHost::BundleStatusCallbackHost() +{ + APP_LOGI("create bundle status callback host instance"); +} + +BundleStatusCallbackHost::~BundleStatusCallbackHost() +{ + APP_LOGI("destroy bundle status callback host instance"); +} + +int BundleStatusCallbackHost::OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + APP_LOGD("bundle status callback host onReceived message, the message code is %{public}u", code); + switch (code) { + case static_cast(IBundleStatusCallback::Message::ON_BUNDLE_STATE_CHANGED): { + uint8_t installType = data.ReadUint8(); + int32_t resultCode = data.ReadInt32(); + std::string resultMsg = Str16ToStr8(data.ReadString16()); + std::string bundleName = Str16ToStr8(data.ReadString16()); + OnBundleStateChanged(installType, resultCode, resultMsg, bundleName); + break; + } + default: + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); + } + return NO_ERROR; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_status_callback_proxy.cpp b/interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_status_callback_proxy.cpp new file mode 100644 index 000000000..9601fd2ee --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/bundlemgr/bundle_status_callback_proxy.cpp @@ -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. + */ + +#include "bundle_status_callback_proxy.h" + +#include "ipc_types.h" +#include "parcel.h" +#include "string_ex.h" + +#include "appexecfwk_errors.h" +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { +namespace { + +std::string TransformResult(ErrCode resultCode) +{ + switch (resultCode) { + case ERR_OK: + return "SUCCESS"; + case ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR: + return "ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR"; + case ERR_APPEXECFWK_INSTALL_HOST_INSTALLER_FAILED: + return "ERR_APPEXECFWK_INSTALL_HOST_INSTALLER_FAILED"; + case ERR_APPEXECFWK_INSTALL_PARSE_FAILED: + return "ERR_APPEXECFWK_INSTALL_PARSE_FAILED"; + case ERR_APPEXECFWK_INSTALL_VERSION_DOWNGRADE: + return "ERR_APPEXECFWK_INSTALL_VERSION_DOWNGRADE"; + case ERR_APPEXECFWK_INSTALL_VERIFICATION_FAILED: + return "ERR_APPEXECFWK_INSTALL_VERIFICATION_FAILED"; + case ERR_APPEXECFWK_INSTALL_NO_SIGNATURE_INFO: + return "ERR_APPEXECFWK_INSTALL_NO_SIGNATURE_INFO"; + case ERR_APPEXECFWK_INSTALL_UPDATE_INCOMPATIBLE: + return "ERR_APPEXECFWK_INSTALL_UPDATE_INCOMPATIBLE"; + case ERR_APPEXECFWK_INSTALL_PARAM_ERROR: + return "ERR_APPEXECFWK_INSTALL_PARAM_ERROR"; + case ERR_APPEXECFWK_INSTALL_PERMISSION_DENIED: + return "ERR_APPEXECFWK_INSTALL_PERMISSION_DENIED"; + case ERR_APPEXECFWK_INSTALL_ENTRY_ALREADY_EXIST: + return "ERR_APPEXECFWK_INSTALL_ENTRY_ALREADY_EXIST"; + case ERR_APPEXECFWK_INSTALL_STATE_ERROR: + return "ERR_APPEXECFWK_INSTALL_STATE_ERROR"; + case ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID: + return "ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID"; + case ERR_APPEXECFWK_INSTALL_INVALID_HAP_NAME: + return "ERR_APPEXECFWK_INSTALL_INVALID_HAP_NAME"; + case ERR_APPEXECFWK_INSTALL_INVALID_BUNDLE_FILE: + return "ERR_APPEXECFWK_INSTALL_INVALID_BUNDLE_FILE"; + case ERR_APPEXECFWK_INSTALL_GENERATE_UID_ERROR: + return "ERR_APPEXECFWK_INSTALL_GENERATE_UID_ERROR"; + case ERR_APPEXECFWK_INSTALL_INSTALLD_SERVICE_ERROR: + return "ERR_APPEXECFWK_INSTALL_INSTALLD_SERVICE_ERROR"; + case ERR_APPEXECFWK_INSTALL_BUNDLE_MGR_SERVICE_ERROR: + return "ERR_APPEXECFWK_INSTALL_BUNDLE_MGR_SERVICE_ERROR"; + case ERR_APPEXECFWK_INSTALL_ALREADY_EXIST: + return "ERR_APPEXECFWK_INSTALL_ALREADY_EXIST"; + case ERR_APPEXECFWK_PARSE_UNEXPECTED: + return "ERR_APPEXECFWK_PARSE_UNEXPECTED"; + case ERR_APPEXECFWK_PARSE_MISSING_BUNDLE: + return "ERR_APPEXECFWK_PARSE_MISSING_BUNDLE"; + case ERR_APPEXECFWK_PARSE_MISSING_ABILITY: + return "ERR_APPEXECFWK_PARSE_MISSING_ABILITY"; + case ERR_APPEXECFWK_PARSE_NO_PROFILE: + return "ERR_APPEXECFWK_PARSE_NO_PROFILE"; + case ERR_APPEXECFWK_PARSE_BAD_PROFILE: + return "ERR_APPEXECFWK_PARSE_BAD_PROFILE"; + case ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR: + return "ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR"; + case ERR_APPEXECFWK_PARSE_PROFILE_MISSING_PROP: + return "ERR_APPEXECFWK_PARSE_PROFILE_MISSING_PROP"; + case ERR_APPEXECFWK_PARSE_PERMISSION_ERROR: + return "ERR_APPEXECFWK_PARSE_PERMISSION_ERROR"; + case ERR_APPEXECFWK_INSTALLD_PARAM_ERROR: + return "ERR_APPEXECFWK_INSTALLD_PARAM_ERROR"; + case ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR: + return "ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR"; + case ERR_APPEXECFWK_INSTALLD_CREATE_DIR_FAILED: + return "ERR_APPEXECFWK_INSTALLD_CREATE_DIR_FAILED"; + case ERR_APPEXECFWK_INSTALLD_CREATE_DIR_EXIST: + return "ERR_APPEXECFWK_INSTALLD_CREATE_DIR_EXIST"; + case ERR_APPEXECFWK_INSTALLD_CHOWN_FAILED: + return "ERR_APPEXECFWK_INSTALLD_CHOWN_FAILED"; + case ERR_APPEXECFWK_INSTALLD_REMOVE_DIR_FAILED: + return "ERR_APPEXECFWK_INSTALLD_REMOVE_DIR_FAILED"; + case ERR_APPEXECFWK_INSTALLD_EXTRACT_FILES_FAILED: + return "ERR_APPEXECFWK_INSTALLD_EXTRACT_FILES_FAILED"; + case ERR_APPEXECFWK_INSTALLD_RNAME_DIR_FAILED: + return "ERR_APPEXECFWK_INSTALLD_RNAME_DIR_FAILED"; + case ERR_APPEXECFWK_INSTALLD_CLEAN_DIR_FAILED: + return "ERR_APPEXECFWK_INSTALLD_CLEAN_DIR_FAILED"; + case ERR_APPEXECFWK_UNINSTALL_SYSTEM_APP_ERROR: + return "ERR_APPEXECFWK_UNINSTALL_SYSTEM_APP_ERROR"; + case ERR_APPEXECFWK_UNINSTALL_KILLING_APP_ERROR: + return "ERR_APPEXECFWK_UNINSTALL_KILLING_APP_ERROR"; + case ERR_APPEXECFWK_UNINSTALL_INVALID_NAME: + return "ERR_APPEXECFWK_UNINSTALL_INVALID_NAME"; + case ERR_APPEXECFWK_UNINSTALL_PARAM_ERROR: + return "ERR_APPEXECFWK_UNINSTALL_PARAM_ERROR"; + case ERR_APPEXECFWK_UNINSTALL_PERMISSION_DENIED: + return "ERR_APPEXECFWK_UNINSTALL_PERMISSION_DENIED"; + case ERR_APPEXECFWK_UNINSTALL_BUNDLE_MGR_SERVICE_ERROR: + return "ERR_APPEXECFWK_UNINSTALL_BUNDLE_MGR_SERVICE_ERROR"; + case ERR_APPEXECFWK_UNINSTALL_MISSING_INSTALLED_BUNDLE: + return "ERR_APPEXECFWK_UNINSTALL_MISSING_INSTALLED_BUNDLE"; + case ERR_APPEXECFWK_UNINSTALL_MISSING_INSTALLED_MODULE: + return "ERR_APPEXECFWK_UNINSTALL_MISSING_INSTALLED_MODULE"; + default: + return ""; + } +} + +} // namespace + +BundleStatusCallbackProxy::BundleStatusCallbackProxy(const sptr &object) + : IRemoteProxy(object) +{ + APP_LOGI("create bundle status callback proxy instance"); +} + +BundleStatusCallbackProxy::~BundleStatusCallbackProxy() +{ + APP_LOGI("destroy bundle status callback proxy instance"); +} + +void BundleStatusCallbackProxy::OnBundleStateChanged( + const uint8_t installType, const int32_t resultCode, const std::string &resultMsg, const std::string &bundleName) +{ + APP_LOGI("bundle state changed %{public}s", bundleName.c_str()); + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + + if (!data.WriteUint8(installType)) { + APP_LOGE("fail to call OnBundleStateChanged, for write installType failed"); + return; + } + if (!data.WriteInt32(resultCode)) { + APP_LOGE("fail to call OnBundleStateChanged, for write resultCode failed"); + return; + } + std::string msg = TransformResult(resultCode); + if (!data.WriteString16(Str8ToStr16(msg))) { + APP_LOGE("fail to call OnBundleStateChanged, for write resultMsg failed"); + return; + } + if (!data.WriteString16(Str8ToStr16(bundleName))) { + APP_LOGE("fail to call OnBundleStateChanged, for write bundleName failed"); + return; + } + + sptr remote = Remote(); + if (!remote) { + APP_LOGE("fail to call OnBundleStateChanged, for Remote() is nullptr"); + return; + } + + int32_t ret = remote->SendRequest( + static_cast(IBundleStatusCallback::Message::ON_BUNDLE_STATE_CHANGED), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGW("fail to call OnBundleStateChanged, for transact is failed, error code is: %{public}d", ret); + } +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_core/src/bundlemgr/clean_cache_callback_host.cpp b/interfaces/innerkits/appexecfwk_core/src/bundlemgr/clean_cache_callback_host.cpp new file mode 100644 index 000000000..203f50540 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/bundlemgr/clean_cache_callback_host.cpp @@ -0,0 +1,52 @@ +/* + * 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 "clean_cache_callback_host.h" + +#include "ipc_types.h" + +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { + +CleanCacheCallbackHost::CleanCacheCallbackHost() +{ + APP_LOGI("create clean cache callback host instance"); +} + +CleanCacheCallbackHost::~CleanCacheCallbackHost() +{ + APP_LOGI("destroyclean cache callback host instance"); +} + +int CleanCacheCallbackHost::OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + APP_LOGD("clean cache callback host onReceived message, the message code is %{public}u", code); + switch (code) { + case static_cast(ICleanCacheCallback::Message::ON_CLEAN_CACHE_CALLBACK): { + bool succeed = data.ReadBool(); + OnCleanCacheFinished(succeed); + break; + } + default: + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); + } + return NO_ERROR; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_core/src/bundlemgr/clean_cache_callback_proxy.cpp b/interfaces/innerkits/appexecfwk_core/src/bundlemgr/clean_cache_callback_proxy.cpp new file mode 100644 index 000000000..14df464d4 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/bundlemgr/clean_cache_callback_proxy.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 "clean_cache_callback_proxy.h" + +#include "ipc_types.h" +#include "parcel.h" + +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { + +CleanCacheCallbackProxy::CleanCacheCallbackProxy(const sptr &object) + : IRemoteProxy(object) +{ + APP_LOGI("create clean cache callback proxy instance"); +} + +CleanCacheCallbackProxy::~CleanCacheCallbackProxy() +{ + APP_LOGI("destroy clean cache callback proxy instance"); +} + +void CleanCacheCallbackProxy::OnCleanCacheFinished(bool succeeded) +{ + APP_LOGI("clean cache result %{public}d", succeeded); + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + + if (!data.WriteBool(succeeded)) { + APP_LOGE("fail to call OnCleanCacheFinished​, for write parcel code failed"); + return; + } + + sptr remote = Remote(); + if (!remote) { + APP_LOGE("fail to call OnCleanCacheFinished​, for Remote() is nullptr"); + return; + } + + int32_t ret = remote->SendRequest( + static_cast(ICleanCacheCallback::Message::ON_CLEAN_CACHE_CALLBACK), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGW("fail to call OnCleanCacheFinished​, for transact is failed, error code is: %{public}d", ret); + } +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/interfaces/innerkits/appexecfwk_core/src/bundlemgr/status_receiver_host.cpp b/interfaces/innerkits/appexecfwk_core/src/bundlemgr/status_receiver_host.cpp new file mode 100644 index 000000000..d85cb6b6c --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/bundlemgr/status_receiver_host.cpp @@ -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. + */ + +#include "status_receiver_host.h" + +#include "ipc_types.h" +#include "string_ex.h" + +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { + +StatusReceiverHost::StatusReceiverHost() +{ + APP_LOGI("create status receiver host instance"); +} + +StatusReceiverHost::~StatusReceiverHost() +{ + APP_LOGI("destroy status receiver host instance"); +} + +int StatusReceiverHost::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + APP_LOGI("status receiver host onReceived message, the message code is %{public}u", code); + switch (code) { + case static_cast(IStatusReceiver::Message::ON_FINISHED): { + int32_t resultCode = data.ReadInt32(); + std::string resultMsg = Str16ToStr8(data.ReadString16()); + OnFinished(resultCode, resultMsg); + break; + } + case static_cast(IStatusReceiver::Message::ON_STATUS_NOTIFY): { + int32_t progress = data.ReadInt32(); + OnStatusNotify(progress); + break; + } + default: + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); + } + return NO_ERROR; +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/innerkits/appexecfwk_core/src/bundlemgr/status_receiver_proxy.cpp b/interfaces/innerkits/appexecfwk_core/src/bundlemgr/status_receiver_proxy.cpp new file mode 100644 index 000000000..dc45d7fd4 --- /dev/null +++ b/interfaces/innerkits/appexecfwk_core/src/bundlemgr/status_receiver_proxy.cpp @@ -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. + */ + +#include "status_receiver_proxy.h" + +#include + +#include "ipc_types.h" +#include "parcel.h" +#include "string_ex.h" + +#include "appexecfwk_errors.h" +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { +namespace { + +// struct for transform internal error code/message to result which open to developer +struct ReceivedResult { + int32_t clientCode = -1; + std::string clientMessage; +}; + +const std::string MSG_SUCCESS = "[SUCCESS]"; +const std::string MSG_ERR_INSTALL_INTERNAL_ERROR = "[ERR_INSTALL_INTERNAL_ERROR]"; +const std::string MSG_ERR_INSTALL_HOST_INSTALLER_FAILED = "[ERR_INSTALL_HOST_INSTALLER_FAILED]"; +const std::string MSG_ERR_INSTALL_PARSE_FAILED = "[ERR_INSTALL_PARSE_FAILED]"; +const std::string MSG_ERR_INSTALL_VERSION_DOWNGRADE = "[ERR_INSTALL_VERSION_DOWNGRADE]"; +const std::string MSG_ERR_INSTALL_VERIFICATION_FAILED = "[ERR_INSTALL_VERIFICATION_FAILED]"; +const std::string MSG_ERR_INSTALL_NO_SIGNATURE_INFO = "[ERR_INSTALL_NO_SIGNATURE_INFO]"; +const std::string MSG_ERR_INSTALL_UPDATE_INCOMPATIBLE = "[ERR_INSTALL_UPDATE_INCOMPATIBLE]"; +const std::string MSG_ERR_INSTALL_PARAM_ERROR = "[MSG_ERR_INSTALL_PARAM_ERROR]"; +const std::string MSG_ERR_INSTALL_PERMISSION_DENIED = "[MSG_ERR_INSTALL_PERMISSION_DENIED]"; +const std::string MSG_ERR_INSTALL_ENTRY_ALREADY_EXIST = "[MSG_ERR_INSTALL_ENTRY_ALREADY_EXIST]"; +const std::string MSG_ERR_INSTALL_STATE_ERROR = "[MSG_ERR_INSTALL_STATE_ERROR]"; +const std::string MSG_ERR_INSTALL_FILE_PATH_INVALID = "[MSG_ERR_INSTALL_FILE_PATH_INVALID]"; +const std::string MSG_ERR_INSTALL_INVALID_BUNDLE_FILE = "[ERR_INSTALL_INVALID_BUNDLE_FILE]"; +const std::string MSG_ERR_INSTALL_GENERATE_UID_ERROR = "[ERR_INSTALL_GENERATE_UID_ERROR]"; +const std::string MSG_ERR_INSTALL_INSTALLD_SERVICE_ERROR = "[ERR_INSTALL_INSTALLD_SERVICE_ERROR]"; +const std::string MSG_ERR_INSTALL_BUNDLE_MGR_SERVICE_ERROR = "[ERR_INSTALL_BUNDLE_MGR_SERVICE_ERROR]"; +const std::string MSG_ERR_INSTALL_ALREADY_EXIST = "[ERR_INSTALL_ALREADY_EXIST]"; + +const std::string MSG_ERR_INSTALL_PARSE_UNEXPECTED = "[ERR_INSTALL_PARSE_UNEXPECTED]"; +const std::string MSG_ERR_INSTALL_PARSE_MISSING_BUNDLE = "[ERR_INSTALL_PARSE_MISSING_BUNDLE]"; +const std::string MSG_ERR_INSTALL_PARSE_MISSING_ABILITY = "[ERR_INSTALL_PARSE_MISSING_ABILITY]"; +const std::string MSG_ERR_INSTALL_PARSE_NO_PROFILE = "[ERR_INSTALL_PARSE_NO_PROFILE]"; +const std::string MSG_ERR_INSTALL_PARSE_BAD_PROFILE = "[ERR_INSTALL_PARSE_BAD_PROFILE]"; +const std::string MSG_ERR_INSTALL_PARSE_PROFILE_PROP_TYPE_ERROR = "[ERR_INSTALL_PARSE_PROFILE_PROP_TYPE_ERROR]"; +const std::string MSG_ERR_INSTALL_PARSE_PROFILE_MISSING_PROP = "[ERR_INSTALL_PARSE_PROFILE_MISSING_PROP]"; +const std::string MSG_ERR_INSTALL_PARSE_PERMISSION_ERROR = "[ERR_INSTALL_PARSE_PERMISSION_ERROR]"; + +const std::string MSG_ERR_INSTALLD_CLEAN_DIR_FAILED = "[MSG_ERR_INSTALLD_CLEAN_DIR_FAILED]"; +const std::string MSG_ERR_INSTALLD_RNAME_DIR_FAILED = "[MSG_ERR_INSTALLD_RNAME_DIR_FAILED]"; +const std::string MSG_ERR_INSTALLD_EXTRACT_FILES_FAILED = "[MSG_ERR_INSTALLD_EXTRACT_FILES_FAILED]"; +const std::string MSG_ERR_INSTALLD_REMOVE_DIR_FAILED = "[ERR_INSTALLD_REMOVE_DIR_FAILED]"; +const std::string MSG_ERR_INSTALLD_CHOWN_FAILED = "[ERR_INSTALLD_CHOWN_FAILED,]"; +const std::string MSG_ERR_INSTALLD_CREATE_DIR_EXIST = "[ERR_INSTALLD_CREATE_DIR_EXIST]"; +const std::string MSG_ERR_INSTALLD_CREATE_DIR_FAILED = "[ERR_INSTALLD_CREATE_DIR_FAILED]"; +const std::string MSG_ERR_INSTALLD_GET_PROXY_ERROR = "[ERR_INSTALLD_GET_PROXY_ERROR]"; +const std::string MSG_ERR_INSTALLD_PARAM_ERROR = "[ERR_INSTALLD_PARAM_ERROR]"; + +const std::string MSG_ERR_INSTALL_INVALID_HAP_NAME = "[ERR_INSTALL_INVALID_HAP_NAME]"; +const std::string MSG_ERR_UNINSTALL_PARAM_ERROR = "[ERR_UNINSTALL_PARAM_ERROR]"; +const std::string MSG_ERR_UNINSTALL_PERMISSION_DENIED = "[MSG_ERR_UNINSTALL_PERMISSION_DENIED]"; +const std::string MSG_ERR_UNINSTALL_INVALID_NAME = "[ERR_UNINSTALL_INVALID_NAME]"; +const std::string MSG_ERR_UNINSTALL_BUNDLE_MGR_SERVICE_ERROR = "[ERR_UNINSTALL_BUNDLE_MGR_SERVICE_ERROR,]"; +const std::string MSG_ERR_UNINSTALL_MISSING_INSTALLED_BUNDLE = "[ERR_UNINSTALL_MISSING_INSTALLED_BUNDLE]"; +const std::string MSG_ERR_UNINSTALL_MISSING_INSTALLED_MODULE = "[ERR_UNINSTALL_MISSING_INSTALLED_MODULE]"; +const std::string MSG_ERR_UNINSTALL_KILLING_APP_ERROR = "[ERR_UNINSTALL_KILLING_APP_ERROR]"; +const std::string MSG_ERR_UNINSTALL_SYSTEM_APP_ERROR = "[MSG_ERR_UNINSTALL_SYSTEM_APP_ERROR]"; +const std::string MSG_ERR_UNKNOWN = "[ERR_UNKNOWN]"; + +const std::map MAP_RECEIVED_RESULTS{ + {ERR_OK, {IStatusReceiver::SUCCESS, MSG_SUCCESS}}, + {ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR, + {IStatusReceiver::ERR_INSTALL_INTERNAL_ERROR, MSG_ERR_INSTALL_INTERNAL_ERROR}}, + {ERR_APPEXECFWK_INSTALL_HOST_INSTALLER_FAILED, + {IStatusReceiver::ERR_INSTALL_HOST_INSTALLER_FAILED, MSG_ERR_INSTALL_HOST_INSTALLER_FAILED}}, + {ERR_APPEXECFWK_INSTALL_PARSE_FAILED, {IStatusReceiver::ERR_INSTALL_PARSE_FAILED, MSG_ERR_INSTALL_PARSE_FAILED}}, + {ERR_APPEXECFWK_INSTALL_VERSION_DOWNGRADE, + {IStatusReceiver::ERR_INSTALL_VERSION_DOWNGRADE, MSG_ERR_INSTALL_VERSION_DOWNGRADE}}, + {ERR_APPEXECFWK_INSTALL_VERIFICATION_FAILED, + {IStatusReceiver::ERR_INSTALL_VERIFICATION_FAILED, MSG_ERR_INSTALL_VERIFICATION_FAILED}}, + {ERR_APPEXECFWK_INSTALL_NO_SIGNATURE_INFO, + {IStatusReceiver::ERR_INSTALL_NO_SIGNATURE_INFO, MSG_ERR_INSTALL_NO_SIGNATURE_INFO}}, + {ERR_APPEXECFWK_INSTALL_UPDATE_INCOMPATIBLE, + {IStatusReceiver::ERR_INSTALL_UPDATE_INCOMPATIBLE, MSG_ERR_INSTALL_UPDATE_INCOMPATIBLE}}, + {ERR_APPEXECFWK_INSTALL_PARAM_ERROR, {IStatusReceiver::ERR_INSTALL_PARAM_ERROR, MSG_ERR_INSTALL_PARAM_ERROR}}, + {ERR_APPEXECFWK_INSTALL_PERMISSION_DENIED, + {IStatusReceiver::ERR_INSTALL_PERMISSION_DENIED, MSG_ERR_INSTALL_PERMISSION_DENIED}}, + {ERR_APPEXECFWK_INSTALL_ENTRY_ALREADY_EXIST, + {IStatusReceiver::ERR_INSTALL_ENTRY_ALREADY_EXIST, MSG_ERR_INSTALL_ENTRY_ALREADY_EXIST}}, + {ERR_APPEXECFWK_INSTALL_STATE_ERROR, {IStatusReceiver::ERR_INSTALL_STATE_ERROR, MSG_ERR_INSTALL_STATE_ERROR}}, + {ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID, + {IStatusReceiver::ERR_INSTALL_FILE_PATH_INVALID, MSG_ERR_INSTALL_FILE_PATH_INVALID}}, + {ERR_APPEXECFWK_INSTALL_INVALID_HAP_NAME, + {IStatusReceiver::ERR_INSTALL_INVALID_HAP_NAME, MSG_ERR_INSTALL_INVALID_HAP_NAME}}, + {ERR_APPEXECFWK_INSTALL_INVALID_BUNDLE_FILE, + {IStatusReceiver::ERR_INSTALL_INVALID_BUNDLE_FILE, MSG_ERR_INSTALL_INVALID_BUNDLE_FILE}}, + {ERR_APPEXECFWK_INSTALL_GENERATE_UID_ERROR, + {IStatusReceiver::ERR_INSTALL_GENERATE_UID_ERROR, MSG_ERR_INSTALL_GENERATE_UID_ERROR}}, + {ERR_APPEXECFWK_INSTALL_INSTALLD_SERVICE_ERROR, + {IStatusReceiver::ERR_INSTALL_INSTALLD_SERVICE_ERROR, MSG_ERR_INSTALL_INSTALLD_SERVICE_ERROR}}, + {ERR_APPEXECFWK_INSTALL_BUNDLE_MGR_SERVICE_ERROR, + {IStatusReceiver::ERR_INSTALL_BUNDLE_MGR_SERVICE_ERROR, MSG_ERR_INSTALL_BUNDLE_MGR_SERVICE_ERROR}}, + {ERR_APPEXECFWK_INSTALL_ALREADY_EXIST, {IStatusReceiver::ERR_INSTALL_ALREADY_EXIST, MSG_ERR_INSTALL_ALREADY_EXIST}}, + + {ERR_APPEXECFWK_PARSE_UNEXPECTED, + {IStatusReceiver::ERR_INSTALL_PARSE_UNEXPECTED, MSG_ERR_INSTALL_PARSE_UNEXPECTED}}, + {ERR_APPEXECFWK_PARSE_MISSING_BUNDLE, + {IStatusReceiver::ERR_INSTALL_PARSE_MISSING_BUNDLE, MSG_ERR_INSTALL_PARSE_MISSING_BUNDLE}}, + {ERR_APPEXECFWK_PARSE_MISSING_ABILITY, + {IStatusReceiver::ERR_INSTALL_PARSE_MISSING_ABILITY, MSG_ERR_INSTALL_PARSE_MISSING_ABILITY}}, + {ERR_APPEXECFWK_PARSE_NO_PROFILE, + {IStatusReceiver::ERR_INSTALL_PARSE_NO_PROFILE, MSG_ERR_INSTALL_PARSE_NO_PROFILE}}, + {ERR_APPEXECFWK_PARSE_BAD_PROFILE, + {IStatusReceiver::ERR_INSTALL_PARSE_BAD_PROFILE, MSG_ERR_INSTALL_PARSE_BAD_PROFILE}}, + {ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR, + {IStatusReceiver::ERR_INSTALL_PARSE_PROFILE_PROP_TYPE_ERROR, MSG_ERR_INSTALL_PARSE_PROFILE_PROP_TYPE_ERROR}}, + {ERR_APPEXECFWK_PARSE_PROFILE_MISSING_PROP, + {IStatusReceiver::ERR_INSTALL_PARSE_PROFILE_MISSING_PROP, MSG_ERR_INSTALL_PARSE_PROFILE_MISSING_PROP}}, + {ERR_APPEXECFWK_PARSE_PERMISSION_ERROR, + {IStatusReceiver::ERR_INSTALL_PARSE_PERMISSION_ERROR, MSG_ERR_INSTALL_PARSE_PERMISSION_ERROR}}, + + {ERR_APPEXECFWK_INSTALLD_CLEAN_DIR_FAILED, + {IStatusReceiver::ERR_INSTALLD_CLEAN_DIR_FAILED, MSG_ERR_INSTALLD_CLEAN_DIR_FAILED}}, + {ERR_APPEXECFWK_INSTALLD_RNAME_DIR_FAILED, + {IStatusReceiver::ERR_INSTALLD_RNAME_DIR_FAILED, MSG_ERR_INSTALLD_RNAME_DIR_FAILED}}, + {ERR_APPEXECFWK_INSTALLD_EXTRACT_FILES_FAILED, + {IStatusReceiver::ERR_INSTALLD_EXTRACT_FILES_FAILED, MSG_ERR_INSTALLD_EXTRACT_FILES_FAILED}}, + {ERR_APPEXECFWK_INSTALLD_REMOVE_DIR_FAILED, + {IStatusReceiver::ERR_INSTALLD_REMOVE_DIR_FAILED, MSG_ERR_INSTALLD_REMOVE_DIR_FAILED}}, + {ERR_APPEXECFWK_INSTALLD_CHOWN_FAILED, {IStatusReceiver::ERR_INSTALLD_CHOWN_FAILED, MSG_ERR_INSTALLD_CHOWN_FAILED}}, + {ERR_APPEXECFWK_INSTALLD_CREATE_DIR_EXIST, + {IStatusReceiver::ERR_INSTALLD_CREATE_DIR_EXIST, MSG_ERR_INSTALLD_CREATE_DIR_EXIST}}, + {ERR_APPEXECFWK_INSTALLD_CREATE_DIR_FAILED, + {IStatusReceiver::ERR_INSTALLD_CREATE_DIR_FAILED, MSG_ERR_INSTALLD_CREATE_DIR_FAILED}}, + {ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR, + {IStatusReceiver::ERR_INSTALLD_GET_PROXY_ERROR, MSG_ERR_INSTALLD_GET_PROXY_ERROR}}, + {ERR_APPEXECFWK_INSTALLD_PARAM_ERROR, {IStatusReceiver::ERR_INSTALLD_PARAM_ERROR, MSG_ERR_INSTALLD_PARAM_ERROR}}, + + {ERR_APPEXECFWK_UNINSTALL_MISSING_INSTALLED_MODULE, + {IStatusReceiver::ERR_UNINSTALL_MISSING_INSTALLED_MODULE, MSG_ERR_UNINSTALL_MISSING_INSTALLED_MODULE}}, + {ERR_APPEXECFWK_UNINSTALL_PARAM_ERROR, {IStatusReceiver::ERR_UNINSTALL_PARAM_ERROR, MSG_ERR_UNINSTALL_PARAM_ERROR}}, + {ERR_APPEXECFWK_UNINSTALL_PERMISSION_DENIED, + {IStatusReceiver::ERR_UNINSTALL_PERMISSION_DENIED, MSG_ERR_UNINSTALL_PERMISSION_DENIED}}, + {ERR_APPEXECFWK_UNINSTALL_BUNDLE_MGR_SERVICE_ERROR, + {IStatusReceiver::ERR_UNINSTALL_BUNDLE_MGR_SERVICE_ERROR, MSG_ERR_UNINSTALL_BUNDLE_MGR_SERVICE_ERROR}}, + {ERR_APPEXECFWK_UNINSTALL_MISSING_INSTALLED_BUNDLE, + {IStatusReceiver::ERR_UNINSTALL_MISSING_INSTALLED_BUNDLE, MSG_ERR_UNINSTALL_MISSING_INSTALLED_BUNDLE}}, + {ERR_APPEXECFWK_UNINSTALL_KILLING_APP_ERROR, + {IStatusReceiver::ERR_UNINSTALL_KILLING_APP_ERROR, MSG_ERR_UNINSTALL_KILLING_APP_ERROR}}, + {ERR_APPEXECFWK_UNINSTALL_SYSTEM_APP_ERROR, + {IStatusReceiver::ERR_UNINSTALL_SYSTEM_APP_ERROR, MSG_ERR_UNINSTALL_SYSTEM_APP_ERROR}}, + {ERR_APPEXECFWK_UNINSTALL_INVALID_NAME, + {IStatusReceiver::ERR_UNINSTALL_INVALID_NAME, MSG_ERR_UNINSTALL_INVALID_NAME}}, +}; + +} // namespace + +StatusReceiverProxy::StatusReceiverProxy(const sptr &object) : IRemoteProxy(object) +{ + APP_LOGI("create status receiver proxy instance"); +} + +StatusReceiverProxy::~StatusReceiverProxy() +{ + APP_LOGI("destroy status receiver proxy instance"); +} + +void StatusReceiverProxy::OnStatusNotify(const int32_t progress) +{ + APP_LOGI("status from service is %{public}d", progress); + + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + + if (!data.WriteInt32(progress)) { + APP_LOGE("fail to call OnStatusNotify, for write progress failed"); + return; + } + + sptr remote = Remote(); + if (!remote) { + APP_LOGE("fail to call OnStatusNotify, for Remote() is nullptr"); + return; + } + + int32_t ret = + remote->SendRequest(static_cast(IStatusReceiver::Message::ON_STATUS_NOTIFY), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGW("fail to call OnStatusNotify, for transact is failed, error code is: %{public}d", ret); + } +} + +void StatusReceiverProxy::OnFinished(const int32_t resultCode, const std::string &resultMsg) +{ + APP_LOGI("result from service is %{public}d, %{public}s", resultCode, resultMsg.c_str()); + // transform service error code to client error code. + TransformResult(resultCode); + + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + + if (!data.WriteInt32(resultCode_)) { + APP_LOGE("fail to call OnFinished, for write resultCode_ failed"); + return; + } + if (!data.WriteString16(Str8ToStr16(resultMsg_))) { + APP_LOGE("fail to call OnFinished, for write resultMsg_ failed"); + return; + } + + sptr remote = Remote(); + if (!remote) { + APP_LOGE("fail to call OnFinished, for Remote() is nullptr"); + return; + } + + int32_t ret = remote->SendRequest(static_cast(IStatusReceiver::Message::ON_FINISHED), data, reply, option); + if (ret != NO_ERROR) { + APP_LOGW("fail to call OnFinished, for transact is failed, error code is: %{public}d", ret); + } +} + +void StatusReceiverProxy::TransformResult(const int32_t resultCode) +{ + auto result = MAP_RECEIVED_RESULTS.find(resultCode); + if (result != MAP_RECEIVED_RESULTS.end()) { + resultCode_ = result->second.clientCode; + resultMsg_ = result->second.clientMessage; + } else { + resultCode_ = ERR_UNKNOWN; + resultMsg_ = MSG_ERR_UNKNOWN; + } + APP_LOGD("result transformed is %{public}d, %{public}s", resultCode_, resultMsg_.c_str()); +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/innerkits/eventhandler_native/BUILD.gn b/interfaces/innerkits/eventhandler_native/BUILD.gn new file mode 100644 index 000000000..518027648 --- /dev/null +++ b/interfaces/innerkits/eventhandler_native/BUILD.gn @@ -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. + +import("//build/ohos.gni") +import("//foundation/appexecfwk/standard/appexecfwk.gni") +import( + "//foundation/appexecfwk/standard/libs/libeventhandler/lib_event_handler_sources.gni") + +config("private_config") { + visibility = [ ":*" ] + include_dirs = [ + "${libs_path}/libeventhandler/src", + "//utils/native/base/include", + ] + + defines = event_handler_log_domain_defines +} + +ohos_shared_library("eventhandler_native") { + sources = [ "eventhandler/native_interface_eventhandler.cpp" ] + + include_dirs = [ + "${libs_path}/libeventhandler/src", + "//utils/native/base/include", + "//base/hiviewdfx/interfaces/innerkits/libhilog/include", + "//base/hiviewdfx/interfaces/innerkits/libhitrace/include", + ] + + cflags = [ "-Wno-error=inconsistent-missing-override" ] + + deps = [ + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler:libeventhandler", + "//utils/native/base:utils", + ] + + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + + subsystem_name = "appexecfwk" + part_name = "appexecfwk_standard" +} + +group("eventhandler_native_target") { + deps = [ ":eventhandler_native" ] +} + +group("eventhandler_native_test") { + testonly = true + deps = [] +} diff --git a/interfaces/innerkits/eventhandler_native/eventhandler/native_interface_eventhandler.cpp b/interfaces/innerkits/eventhandler_native/eventhandler/native_interface_eventhandler.cpp new file mode 100644 index 000000000..317e0b630 --- /dev/null +++ b/interfaces/innerkits/eventhandler_native/eventhandler/native_interface_eventhandler.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 "native_interface_eventhandler.h" +#include "native_implement_eventhandler.h" +#include "hilog/log.h" +#include + +using OHOS::ErrCode; +using OHOS::HiviewDFX::HiLog; +using OHOS::HiviewDFX::HiLogLabel; + +namespace { +constexpr HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "EventRunnerNativeInterface"}; +} + +const EventRunnerNativeImplement *GetEventRunnerNativeObjForThread() +{ + return EventRunnerNativeImplement::GetEventRunnerNativeObj(); +} + +const EventRunnerNativeImplement *CreateEventRunnerNativeObj() +{ + return EventRunnerNativeImplement::CreateEventRunnerNativeObj(); +} + +int EventRunnerRun(const EventRunnerNativeImplement *nativeObj) +{ + if (nativeObj == nullptr) { + HiLog::Error(LABEL, "Input nkd object is null"); + return OHOS::AppExecFwk::EVENT_HANDLER_ERR_INVALID_PARAM; + } + return nativeObj->RunEventRunnerNativeObj(); +} + +int EventRunnerStop(const EventRunnerNativeImplement *nativeObj) +{ + if (nativeObj == nullptr) { + HiLog::Error(LABEL, "Input nkd object is null"); + return OHOS::AppExecFwk::EVENT_HANDLER_ERR_INVALID_PARAM; + } + return nativeObj->StopEventRunnerNativeObj(); +} + +int EventRunnerAddFileDescriptorListener(const EventRunnerNativeImplement *nativeObj, int32_t fileDescriptor, + uint32_t events, const FileDescriptorCallbacks *fileDescriptorCallbacks) +{ + if (nativeObj == nullptr) { + HiLog::Error(LABEL, "Input nkd object is null"); + return OHOS::AppExecFwk::EVENT_HANDLER_ERR_INVALID_PARAM; + } + return nativeObj->AddFileDescriptorListener(fileDescriptor, events, fileDescriptorCallbacks); +} + +void EventRunnerRemoveFileDescriptorListener(const EventRunnerNativeImplement *nativeObj, int32_t fileDescriptor) +{ + if (nativeObj == nullptr) { + HiLog::Error(LABEL, "Input nkd object is null"); + return; + } + nativeObj->RemoveFileDescriptorListener(fileDescriptor); +} diff --git a/interfaces/innerkits/eventhandler_native/eventhandler/native_interface_eventhandler.h b/interfaces/innerkits/eventhandler_native/eventhandler/native_interface_eventhandler.h new file mode 100644 index 000000000..03e02ba6f --- /dev/null +++ b/interfaces/innerkits/eventhandler_native/eventhandler/native_interface_eventhandler.h @@ -0,0 +1,166 @@ +/* + * 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. + */ + +/** + * @addtogroup Native_EventHandler + * @{ + * + * @brief Provides EventHandler-specific functions, including functions for obtaining + * EventRunnerNativeImplement instances and adding a file descriptor listener. + * + * @since 3 + * @version 2.0 + */ + +/** + * @file native_interface_eventhandler.h + * + * @brief Declares the EventHandler-specific functions, including functions for obtaining + * EventRunnerNativeImplement instances and adding a file descriptor listener. + * + * @since 3 + * @version 2.0 + */ + +#ifndef AAFWK_APPEXECFWK_NATIVE_INTERFACE_EVENTHANDLER_H +#define AAFWK_APPEXECFWK_NATIVE_INTERFACE_EVENTHANDLER_H + +#ifdef __cplusplus +extern "C" { +#endif + +namespace OHOS { +namespace AppExecFwk { +struct EventRunnerNativeImplement; +using EventRunnerNativeImplement = struct EventRunnerNativeImplement; + +using FileFDCallback = void (*)(int); + +/** + * @brief Defines file descriptor callbacks. + * + * You should implement this structure before adding a file descriptor listener. + * + * @since 3 + * @version 2.0 + */ +struct FileDescriptorCallbacks { + /** Callback invoked when the file descriptor is readable */ + FileFDCallback readableCallback_; + /** Callback invoked when the file descriptor is writable */ + FileFDCallback writableCallback_; + /** Callback invoked when the file descriptor is closed */ + FileFDCallback shutdownCallback_; + /** Callback invoked when the file descriptor encounters an exception */ + FileFDCallback exceptionCallback_; +}; + +/** + * @brief Obtains the {@link EventRunnerNativeImplement} instance of the current thread. + * + * You should call this function or {@link CreateEventRunnerNativeObj} to obtain or create an + * {@link EventRunnerNativeImplement} instance so that the instance will be passed as an input parameter + * to other EventHandler-specific functions you will call. + * + * @return Returns a non-NULL value if the instance is obtained; returns NULL otherwise. + * @since 3 + * @version 2.0 + */ +const EventRunnerNativeImplement *GetEventRunnerNativeObjForThread(); + +/** + * @brief Creates an {@link EventRunnerNativeImplement} instance in a new thread. + * + * You should call this function or {@link GetEventRunnerNativeObjForThread} to obtain or create an + * {@link EventRunnerNativeImplement} instance so that the instance will be passed as an input parameter + * to other EventHandler-specific functions you will call. + * + * @return Returns a non-NULL value if the instance is created; returns NULL otherwise. + * @since 3 + * @version 2.0 + */ +const EventRunnerNativeImplement *CreateEventRunnerNativeObj(); + +/** + * @brief Starts the {@link EventRunnerNativeImplement} instance. + * + * If a file descriptor listener has been added, particular callbacks can be triggered upon corresponding + * operations only when the {@link EventRunnerNativeImplement} instance is running. + * + * @param nativeObj Indicates the pointer to the {@link EventRunnerNativeImplement} instance obtained + * by calling {@link GetEventRunnerNativeObjForThread} or {@link CreateEventRunnerNativeObj}. + * + * @return Returns 0 if the instance starts running; returns another value otherwise. + * @see EventRunnerAddFileDescriptorListener + * @since 3 + * @version 2.0 + */ +int EventRunnerRun(const EventRunnerNativeImplement *nativeObj); + +/** + * @brief Stops the {@link EventRunnerNativeImplement} instance. + * + * @param nativeObj Indicates the pointer to the {@link EventRunnerNativeImplement} instance obtained + * by calling {@link GetEventRunnerNativeObjForThread} or {@link CreateEventRunnerNativeObj}. + * + * @return Returns 0 if the instance stops running; returns another value otherwise. + * @see EventRunnerRun + * @since 3 + * @version 2.0 + */ +int EventRunnerStop(const EventRunnerNativeImplement *nativeObj); + +/** + * @brief Adds a file descriptor listener for the {@link EventRunnerNativeImplement} instance. + * + * The file descriptor listener includes callbacks that can be invoked when the file descriptor is + * readable, writable, or closed, or when it encounters an exception. + * + * @param nativeObj Indicates the pointer to the {@link EventRunnerNativeImplement} instance obtained + * by calling {@link GetEventRunnerNativeObjForThread} or {@link CreateEventRunnerNativeObj}. + * @param fileDescriptor Indicates the file descriptor for which the listener is to add. + * @param events Indicates the file descriptor events, including input, output, and error events. + * @param fileDescriptorCallbacks Indicates the pointer to the {@link FileDescriptorCallbacks} structure + * containing file descriptor-related callbacks. You must implement this structure. + * + * @return Returns 0 if the file descriptor listener is added; returns another value otherwise. + * @see EventRunnerRemoveFileDescriptorListener + * @see FileDescriptorCallbacks + * @since 3 + * @version 2.0 + */ +int EventRunnerAddFileDescriptorListener(const EventRunnerNativeImplement *nativeObj, int fileDescriptor, + unsigned int events, const FileDescriptorCallbacks *fileDescriptorCallbacks); + +/** + * @brief Removes the listener for a given file descriptor from the {@link EventRunnerNativeImplement} instance. + * + * @param nativeObj Indicates the pointer to the {@link EventRunnerNativeImplement} instance obtained by + * calling {@link GetEventRunnerNativeObjForThread} or {@link CreateEventRunnerNativeObj}. + * @param fileDescriptor Indicates the file descriptor for which the listener is to remove. + * @see EventRunnerAddFileDescriptorListener + * @since 3 + * @version 2.0 + */ +void EventRunnerRemoveFileDescriptorListener(const EventRunnerNativeImplement *nativeObj, int fileDescriptor); +} // namespace AppExecFwk +} // namespace OHOS + +#ifdef __cplusplus +}; +#endif + +/** @} */ +#endif // AAFWK_APPEXECFWK_NATIVE_INTERFACE_EVENTHANDLER_H \ No newline at end of file diff --git a/interfaces/innerkits/eventhandler_native/libappexecfwk.json b/interfaces/innerkits/eventhandler_native/libappexecfwk.json new file mode 100644 index 000000000..07d9d6425 --- /dev/null +++ b/interfaces/innerkits/eventhandler_native/libappexecfwk.json @@ -0,0 +1,21 @@ +[ + { + "first_introduced": "1", + "name": "GetEventRunnerNativeObjForThread" + }, + { + "name": "CreateEventRunnerNativeObj" + }, + { + "name": "EventRunnerRun" + }, + { + "name": "EventRunnerStop" + }, + { + "name": "EventRunnerAddFileDescriptorListener" + }, + { + "name": "EventRunnerRemoveFileDescriptorListener" + } +] diff --git a/interfaces/innerkits/libeventhandler/BUILD.gn b/interfaces/innerkits/libeventhandler/BUILD.gn new file mode 100644 index 000000000..f956eb308 --- /dev/null +++ b/interfaces/innerkits/libeventhandler/BUILD.gn @@ -0,0 +1,38 @@ +# 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") +import( + "//foundation/appexecfwk/standard/libs/libeventhandler/lib_event_handler_sources.gni") + +config("public_libeventhandler_config") { + include_dirs = [ + "include", + "//base/hiviewdfx/interfaces/innerkits/libhilog/include", + "//base/hiviewdfx/interfaces/innerkits/libhitrace/include", + ] +} + +ohos_shared_library("libeventhandler") { + sources = lib_event_handler_sources + defines = event_handler_log_domain_defines + + configs = [ "${libs_path}/libeventhandler:libeventhandler_config" ] + + public_configs = [ ":public_libeventhandler_config" ] + + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + subsystem_name = "appexecfwk" + part_name = "appexecfwk_standard" +} diff --git a/interfaces/innerkits/libeventhandler/include/dumper.h b/interfaces/innerkits/libeventhandler/include/dumper.h new file mode 100644 index 000000000..59d5d476d --- /dev/null +++ b/interfaces/innerkits/libeventhandler/include/dumper.h @@ -0,0 +1,39 @@ +/* + * 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_LIBEVENTHANDLER_INCLUDE_DUMPER_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_LIBEVENTHANDLER_INCLUDE_DUMPER_H + +namespace OHOS { +namespace AppExecFwk { +class Dumper { +public: + /** + * Processes the content of a specified string. + * @param message the content of a specified string. + */ + virtual void Dump(const std::string &message) = 0; + + /** + * Obtains the tag information. + * which is a prefix added to each string before the string content is processed. + * @return the tag information. + */ + virtual std::string GetTag() = 0; +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_LIBEVENTHANDLER_INCLUDE_DUMPER_H \ No newline at end of file diff --git a/interfaces/innerkits/libeventhandler/include/event_handler.h b/interfaces/innerkits/libeventhandler/include/event_handler.h new file mode 100644 index 000000000..013c5067e --- /dev/null +++ b/interfaces/innerkits/libeventhandler/include/event_handler.h @@ -0,0 +1,900 @@ +/* + * 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_LIBEVENTHANDLER_INCLUDE_EVENT_HANDLER_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_LIBEVENTHANDLER_INCLUDE_EVENT_HANDLER_H + +#include "event_runner.h" +#include "dumper.h" + +namespace OHOS { +namespace AppExecFwk { +enum class EventType { + SYNC_EVENT = 0, + DELAY_EVENT = 1, + TIMING_EVENT = 2, +}; + +template +class ThreadLocalData; + +class EventHandler : public std::enable_shared_from_this { +public: + using Callback = InnerEvent::Callback; + using Priority = EventQueue::Priority; + + /** + * Constructor, set 'EventRunner' automatically. + * + * @param runner The 'EventRunner'. + */ + explicit EventHandler(const std::shared_ptr &runner = nullptr); + virtual ~EventHandler(); + DISALLOW_COPY_AND_MOVE(EventHandler); + + /** + * Get event handler that running on current thread. + * + * @return Returns shared pointer of the current 'EventHandler'. + */ + static std::shared_ptr Current(); + + /** + * Send an event. + * + * @param event Event which should be handled. + * @param delayTime Process the event after 'delayTime' milliseconds. + * @param priority Priority of the event queue for this event. + * @return Returns true if event has been sent successfully. If returns false, event should be released manually. + */ + bool SendEvent(InnerEvent::Pointer &event, int64_t delayTime = 0, Priority priority = Priority::LOW); + + /** + * Send an event. + * + * @param event Event which should be handled. + * @param taskTime Process the event at taskTime. + * @param priority Priority of the event queue for this event. + * @return Returns true if event has been sent successfully. If returns false, event should be released manually. + */ + bool SendTimingEvent(InnerEvent::Pointer &event, int64_t taskTime, Priority priority = Priority::LOW); + + /** + * Send an event. + * + * @param event Event which should be handled. + * @param priority Priority of the event queue for this event. + * @return Returns true if event has been sent successfully. If returns false, event should be released manually. + */ + inline bool SendEvent(InnerEvent::Pointer &event, Priority priority) + { + return SendEvent(event, 0, priority); + } + + /** + * Send an event. + * + * @param event Event which should be handled. + * @param delayTime Process the event after 'delayTime' milliseconds. + * @param priority Priority of the event queue for this event. + * @return Returns true if event has been sent successfully. + */ + inline bool SendEvent(InnerEvent::Pointer &&event, int64_t delayTime = 0, Priority priority = Priority::LOW) + { + return SendEvent(event, delayTime, priority); + } + + /** + * Send an event. + * + * @param innerEventId The id of the event. + * @param param Basic parameter of the event, default is 0. + * @param delayTime Process the event after 'delayTime' milliseconds. + * @return Returns true if event has been sent successfully. + */ + inline bool SendEvent(uint32_t innerEventId, int64_t param, int64_t delayTime) + { + return SendEvent(InnerEvent::Get(innerEventId, param), delayTime); + } + + /** + * Send an event. + * + * @param innerEventId The id of the event. + * @param delayTime Process the event after 'delayTime' milliseconds. + * @param priority Priority of the event queue for this event. + * @return Returns true if event has been sent successfully. + */ + inline bool SendEvent(uint32_t innerEventId, int64_t delayTime = 0, Priority priority = Priority::LOW) + { + return SendEvent(InnerEvent::Get(innerEventId, 0), delayTime, priority); + } + + /** + * Send an event. + * + * @param innerEventId The id of the event. + * @param delayTime Process the event after 'delayTime' milliseconds. + * @return Returns true if event has been sent successfully. + */ + inline bool SendEvent(uint32_t innerEventId, int64_t delayTime) + { + return SendEvent(InnerEvent::Get(innerEventId, 0), delayTime, Priority::LOW); + } + + /** + * Send an event. + * + * @param innerEventId The id of the event. + * @param priority Priority of the event queue for this event. + * @return Returns true if event has been sent successfully. + */ + inline bool SendEvent(uint32_t innerEventId, Priority priority) + { + return SendEvent(InnerEvent::Get(innerEventId, 0), 0, priority); + } + + /** + * Send an event. + * + * @param innerEventId The id of the event. + * @param object Shared pointer of object. + * @param delayTime Process the event after 'delayTime' milliseconds. + * @return Returns true if event has been sent successfully. + */ + template + inline bool SendEvent(uint32_t innerEventId, const std::shared_ptr &object, int64_t delayTime = 0) + { + return SendEvent(InnerEvent::Get(innerEventId, object), delayTime); + } + + /** + * Send an event. + * + * @param innerEventId The id of the event. + * @param object Weak pointer of object. + * @param delayTime Process the event after 'delayTime' milliseconds. + * @return Returns true if event has been sent successfully. + */ + template + inline bool SendEvent(uint32_t innerEventId, const std::weak_ptr &object, int64_t delayTime = 0) + { + return SendEvent(InnerEvent::Get(innerEventId, object), delayTime); + } + + /** + * Send an event. + * + * @param innerEventId The id of the event. + * @param object Unique pointer of object. + * @param delayTime Process the event after 'delayTime' milliseconds. + * @return Returns true if event has been sent successfully. + */ + template + inline bool SendEvent(uint32_t innerEventId, std::unique_ptr &object, int64_t delayTime = 0) + { + return SendEvent(InnerEvent::Get(innerEventId, object), delayTime); + } + + /** + * Send an event. + * + * @param innerEventId The id of the event. + * @param object Unique pointer of object. + * @param delayTime Process the event after 'delayTime' milliseconds. + * @return Returns true if event has been sent successfully. + */ + template + inline bool SendEvent(uint32_t innerEventId, std::unique_ptr &&object, int64_t delayTime = 0) + { + return SendEvent(InnerEvent::Get(innerEventId, object), delayTime); + } + + /** + * Send an immediate event. + * + * @param event Event which should be handled. + * @return Returns true if event has been sent successfully. + */ + inline bool SendImmediateEvent(InnerEvent::Pointer &event) + { + return SendEvent(event, 0, Priority::IMMEDIATE); + } + + /** + * Send an immediate event. + * + * @param event Event which should be handled. + * @return Returns true if event has been sent successfully. + */ + inline bool SendImmediateEvent(InnerEvent::Pointer &&event) + { + return SendImmediateEvent(event); + } + + /** + * Send an immediate event. + * + * @param innerEventId The id of the event. + * @param param Basic parameter of the event, default is 0. + * @return Returns true if event has been sent successfully. + */ + inline bool SendImmediateEvent(uint32_t innerEventId, int64_t param = 0) + { + return SendImmediateEvent(InnerEvent::Get(innerEventId, param)); + } + + /** + * Send an immediate event. + * + * @param innerEventId The id of the event. + * @param object Shared pointer of object. + * @return Returns true if event has been sent successfully. + */ + template + inline bool SendImmediateEvent(uint32_t innerEventId, const std::shared_ptr &object) + { + return SendImmediateEvent(InnerEvent::Get(innerEventId, object)); + } + + /** + * Send an immediate event. + * + * @param innerEventId The id of the event. + * @param object Weak pointer of object. + * @return Returns true if event has been sent successfully. + */ + template + inline bool SendImmediateEvent(uint32_t innerEventId, const std::weak_ptr &object) + { + return SendImmediateEvent(InnerEvent::Get(innerEventId, object)); + } + + /** + * Send an immediate event. + * + * @param innerEventId The id of the event. + * @param object Unique pointer of object. + * @return Returns true if event has been sent successfully. + */ + template + inline bool SendImmediateEvent(uint32_t innerEventId, std::unique_ptr &object) + { + return SendImmediateEvent(InnerEvent::Get(innerEventId, object)); + } + + /** + * Send an immediate event. + * + * @param innerEventId The id of the event. + * @param object Unique pointer of object. + * @return Returns true if event has been sent successfully. + */ + template + inline bool SendImmediateEvent(uint32_t innerEventId, std::unique_ptr &&object) + { + return SendImmediateEvent(InnerEvent::Get(innerEventId, object)); + } + + /** + * Send an high priority event. + * + * @param event Event which should be handled. + * @param delayTime Process the event after 'delayTime' milliseconds. + * @return Returns true if event has been sent successfully. + */ + inline bool SendHighPriorityEvent(InnerEvent::Pointer &event, int64_t delayTime = 0) + { + return SendEvent(event, delayTime, Priority::HIGH); + } + + /** + * Send an high priority event. + * + * @param event Event which should be handled. + * @param delayTime Process the event after 'delayTime' milliseconds. + * @return Returns true if event has been sent successfully. + */ + inline bool SendHighPriorityEvent(InnerEvent::Pointer &&event, int64_t delayTime = 0) + { + return SendHighPriorityEvent(event, delayTime); + } + + /** + * Send an high priority event. + * + * @param innerEventId The id of the event. + * @param param Basic parameter of the event, default is 0. + * @param delayTime Process the event after 'delayTime' milliseconds. + * @return Returns true if event has been sent successfully. + */ + inline bool SendHighPriorityEvent(uint32_t innerEventId, int64_t param = 0, int64_t delayTime = 0) + { + return SendHighPriorityEvent(InnerEvent::Get(innerEventId, param), delayTime); + } + + /** + * Send an high priority event. + * + * @param innerEventId The id of the event. + * @param object Shared pointer of object. + * @param delayTime Process the event after 'delayTime' milliseconds. + * @return Returns true if event has been sent successfully. + */ + template + inline bool SendHighPriorityEvent(uint32_t innerEventId, const std::shared_ptr &object, int64_t delayTime = 0) + { + return SendHighPriorityEvent(InnerEvent::Get(innerEventId, object), delayTime); + } + + /** + * Send an high priority event. + * + * @param innerEventId The id of the event. + * @param object Weak pointer of object. + * @param delayTime Process the event after 'delayTime' milliseconds. + * @return Returns true if event has been sent successfully. + */ + template + inline bool SendHighPriorityEvent(uint32_t innerEventId, const std::weak_ptr &object, int64_t delayTime = 0) + { + return SendHighPriorityEvent(InnerEvent::Get(innerEventId, object), delayTime); + } + + /** + * Send an high priority event. + * + * @param innerEventId The id of the event. + * @param object Unique pointer of object. + * @param delayTime Process the event after 'delayTime' milliseconds. + * @return Returns true if event has been sent successfully. + */ + template + inline bool SendHighPriorityEvent(uint32_t innerEventId, std::unique_ptr &object, int64_t delayTime = 0) + { + return SendHighPriorityEvent(InnerEvent::Get(innerEventId, object), delayTime); + } + + /** + * Send an high priority event. + * + * @param innerEventId The id of the event. + * @param object Unique pointer of object. + * @param delayTime Process the event after 'delayTime' milliseconds. + * @return Returns true if event has been sent successfully. + */ + template + inline bool SendHighPriorityEvent(uint32_t innerEventId, std::unique_ptr &&object, int64_t delayTime = 0) + { + return SendHighPriorityEvent(InnerEvent::Get(innerEventId, object), delayTime); + } + + /** + * Post a task. + * + * @param callback Task callback. + * @param name Name of the task. + * @param delayTime Process the event after 'delayTime' milliseconds. + * @param priority Priority of the event queue for this event. + * @return Returns true if task has been sent successfully. + */ + inline bool PostTask(const Callback &callback, const std::string &name = std::string(), int64_t delayTime = 0, + Priority priority = Priority::LOW) + { + return SendEvent(InnerEvent::Get(callback, name), delayTime, priority); + } + + /** + * Post a task. + * + * @param callback Task callback. + * @param priority Priority of the event queue for this event. + * @return Returns true if task has been sent successfully. + */ + inline bool PostTask(const Callback &callback, Priority priority) + { + return PostTask(callback, std::string(), 0, priority); + } + + /** + * Post a task. + * + * @param callback Task callback. + * @param delayTime Process the event after 'delayTime' milliseconds. + * @param priority Priority of the event queue for this event. + * @return Returns true if task has been sent successfully. + */ + inline bool PostTask(const Callback &callback, int64_t delayTime, Priority priority = Priority::LOW) + { + return PostTask(callback, std::string(), delayTime, priority); + } + + /** + * Post an immediate task. + * + * @param callback Task callback. + * @param name Remove events by name of the task. + * @return Returns true if task has been sent successfully. + */ + inline bool PostImmediateTask(const Callback &callback, const std::string &name = std::string()) + { + return SendEvent(InnerEvent::Get(callback, name), 0, Priority::IMMEDIATE); + } + + /** + * Post a high priority task. + * + * @param callback Task callback. + * @param name Name of the task. + * @param delayTime Process the event after 'delayTime' milliseconds. + * @return Returns true if task has been sent successfully. + */ + inline bool PostHighPriorityTask( + const Callback &callback, const std::string &name = std::string(), int64_t delayTime = 0) + { + return PostTask(callback, name, delayTime, Priority::HIGH); + } + + /** + * Post a high priority task. + * + * @param callback Task callback. + * @param delayTime Process the event after 'delayTime' milliseconds. + * @return Returns true if task has been sent successfully. + */ + inline bool PostHighPriorityTask(const Callback &callback, int64_t delayTime) + { + return PostHighPriorityTask(callback, std::string(), delayTime); + } + + /** + * Post a idle task. + * + * @param callback task callback. + * @param name Name of the task. + * @param delayTime Process the event after 'delayTime' milliseconds. + * @return Returns true if task has been sent successfully. + */ + inline bool PostIdleTask(const Callback &callback, const std::string &name = std::string(), int64_t delayTime = 0) + { + return PostTask(callback, name, delayTime, Priority::IDLE); + } + + /** + * Post a idle task. + * + * @param callback Task callback. + * @param delayTime Process the event after 'delayTime' milliseconds. + * @return Returns true if task has been sent successfully. + */ + inline bool PostIdleTask(const Callback &callback, int64_t delayTime) + { + return PostIdleTask(callback, std::string(), delayTime); + } + + /** + * Send an event, and wait until this event has been handled. + * + * @param event Event which should be handled. + * @param priority Priority of the event queue for this event, IDLE is not permitted for sync event. + * @return Returns true if event has been sent successfully. If returns false, event should be released manually. + */ + bool SendSyncEvent(InnerEvent::Pointer &event, Priority priority = Priority::LOW); + + /** + * Send an event. + * + * @param event Event which should be handled. + * @param priority Priority of the event queue for this event. + * @param priority Priority of the event queue for this event, IDLE is not permitted for sync event. + * @return Returns true if event has been sent successfully. + */ + inline bool SendSyncEvent(InnerEvent::Pointer &&event, Priority priority = Priority::LOW) + { + return SendSyncEvent(event, priority); + } + + /** + * Send an event, and wait until this event has been handled. + * + * @param innerEventId The id of the event. + * @param param Basic parameter of the event, default is 0. + * @param priority Priority of the event queue for this event, IDLE is not permitted for sync event. + * @return Returns true if event has been sent successfully. + */ + inline bool SendSyncEvent(uint32_t innerEventId, int64_t param = 0, Priority priority = Priority::LOW) + { + return SendSyncEvent(InnerEvent::Get(innerEventId, param), priority); + } + + /** + * Send an event, and wait until this event has been handled. + * + * @param innerEventId The id of the event. + * @param priority Priority of the event queue for this event, IDLE is not permitted for sync event. + * @return Returns true if event has been sent successfully. + */ + inline bool SendSyncEvent(uint32_t innerEventId, Priority priority) + { + return SendSyncEvent(InnerEvent::Get(innerEventId, 0), priority); + } + + /** + * Send an event, and wait until this event has been handled. + * + * @param innerEventId The id of the event. + * @param object Shared pointer of object. + * @param priority Priority of the event queue for this event, IDLE is not permitted for sync event. + * @return Returns true if event has been sent successfully. + */ + template + inline bool SendSyncEvent( + uint32_t innerEventId, const std::shared_ptr &object, Priority priority = Priority::LOW) + { + return SendSyncEvent(InnerEvent::Get(innerEventId, object), priority); + } + + /** + * Send an event, and wait until this event has been handled. + * + * @param innerEventId The id of the event. + * @param object Weak pointer of object. + * @param priority Priority of the event queue for this event, IDLE is not permitted for sync event. + * @return Returns true if event has been sent successfully. + */ + template + inline bool SendSyncEvent(uint32_t innerEventId, const std::weak_ptr &object, Priority priority = Priority::LOW) + { + return SendSyncEvent(InnerEvent::Get(innerEventId, object), priority); + } + + /** + * Send an event, and wait until this event has been handled. + * + * @param innerEventId The id of the event. + * @param object Unique pointer of object. + * @param priority Priority of the event queue for this event, IDLE is not permitted for sync event. + * @return Returns true if event has been sent successfully. + */ + template + inline bool SendSyncEvent(uint32_t innerEventId, std::unique_ptr &object, Priority priority = Priority::LOW) + { + return SendSyncEvent(InnerEvent::Get(innerEventId, object), priority); + } + + /** + * Send an event, and wait until this event has been handled. + * + * @param innerEventId The id of the event. + * @param object Unique pointer of object. + * @param priority Priority of the event queue for this event, IDLE is not permitted for sync event. + * @return Returns true if event has been sent successfully. + */ + template + inline bool SendSyncEvent(uint32_t innerEventId, std::unique_ptr &&object, Priority priority = Priority::LOW) + { + return SendSyncEvent(InnerEvent::Get(innerEventId, object), priority); + } + + /** + * Post a task, and wait until this task has been handled. + * + * @param callback Task callback. + * @param name Name of the task. + * @param priority Priority of the event queue for this event, IDLE is not permitted for sync event. + * @return Returns true if task has been sent successfully. + */ + inline bool PostSyncTask(const Callback &callback, const std::string &name, Priority priority = Priority::LOW) + { + return SendSyncEvent(InnerEvent::Get(callback, name), priority); + } + + /** + * Post a task, and wait until this task has been handled. + * + * @param callback Task callback. + * @param priority Priority of the event queue for this event, IDLE is not permitted for sync event. + * @return Returns true if task has been sent successfully. + */ + inline bool PostSyncTask(const Callback &callback, Priority priority = Priority::LOW) + { + return PostSyncTask(callback, std::string(), priority); + } + + /** + * Send a timing event. + * + * @param event Event which should be handled. + * @param taskTime Process the event at taskTime. + * @param priority Priority of the event queue for this event. + * @return Returns true if event has been sent successfully. + */ + inline bool SendTimingEvent(InnerEvent::Pointer &&event, int64_t taskTime, Priority priority) + { + return SendTimingEvent(event, taskTime, priority); + } + + /** + * Send a timing event. + * + * @param event Event which should be handled. + * @param taskTime Process the event at taskTime. + * @return Returns true if event has been sent successfully. + */ + inline bool SendTimingEvent(InnerEvent::Pointer &&event, int64_t taskTime) + { + return SendTimingEvent(event, taskTime, Priority::LOW); + } + + /** + * Send a timing event. + * + * @param innerEventId The id of the event. + * @param taskTime Process the event at taskTime. + * @param param Basic parameter of the event. + * @return Returns true if event has been sent successfully. + */ + inline bool SendTimingEvent(uint32_t innerEventId, int64_t taskTime, int64_t param) + { + return SendTimingEvent(InnerEvent::Get(innerEventId, param), taskTime); + } + + /** + * Send a timing event. + * + * @param innerEventId The id of the event. + * @param taskTime Process the event at taskTime. + * @param priority Priority of the event queue for this event. + * @return Returns true if event has been sent successfully. + */ + inline bool SendTimingEvent(uint32_t innerEventId, int64_t taskTime, Priority priority) + { + return SendTimingEvent(InnerEvent::Get(innerEventId, 0), taskTime, priority); + } + + /** + * Send a timing event. + * + * @param innerEventId The id of the event. + * @param taskTime Process the event at taskTime. + * @param priority Priority of the event queue for this event. + * @return Returns true if event has been sent successfully. + */ + inline bool SendTimingEvent(uint32_t innerEventId, int64_t taskTime) + { + return SendTimingEvent(InnerEvent::Get(innerEventId, 0), taskTime, Priority::LOW); + } + + /** + * Send a timing event. + * + * @param innerEventId The id of the event. + * @param object Shared pointer of object. + * @param taskTime Process the event at taskTime. + * @param priority Priority of the event queue for this event + * @return Returns true if event has been sent successfully. + */ + template + inline bool SendTimingEvent( + uint32_t innerEventId, const std::shared_ptr &object, int64_t taskTime, Priority priority = Priority::LOW) + { + return SendTimingEvent(InnerEvent::Get(innerEventId, object), taskTime, priority); + } + + /** + * Send a timing event. + * + * @param innerEventId The id of the event. + * @param object Weak pointer of object. + * @param taskTime Process the event at taskTime. + * @param priority Priority of the event queue for this event + * @return Returns true if event has been sent successfully. + */ + template + inline bool SendTimingEvent( + uint32_t innerEventId, const std::weak_ptr &object, int64_t taskTime, Priority priority = Priority::LOW) + { + return SendTimingEvent(InnerEvent::Get(innerEventId, object), taskTime, priority); + } + + /** + * Send a timing event. + * + * @param innerEventId The id of the event. + * @param object Unique pointer of object. + * @param taskTime Process the event at taskTime. + * @param priority Priority of the event queue for this event + * @return Returns true if event has been sent successfully. + */ + template + inline bool SendTimingEvent( + uint32_t innerEventId, std::unique_ptr &object, int64_t taskTime, Priority priority = Priority::LOW) + { + return SendTimingEvent(InnerEvent::Get(innerEventId, object), taskTime, priority); + } + + /** + * Send a timing event. + * + * @param innerEventId The id of the event. + * @param object Unique pointer of object. + * @param taskTime Process the event at taskTime. + * @param priority Priority of the event queue for this event + * @return Returns true if event has been sent successfully. + */ + template + inline bool SendTimingEvent( + uint32_t innerEventId, std::unique_ptr &&object, int64_t taskTime, Priority priority = Priority::LOW) + { + return SendTimingEvent(InnerEvent::Get(innerEventId, object), taskTime, priority); + } + + /** + * Post a timing task. + * + * @param callback Task callback. + * @param taskTime Process the event at taskTime. + * @param name Name of the task. + * @param priority Priority of the event queue for this event. + * @return Returns true if task has been sent successfully. + */ + inline bool PostTimingTask(const Callback &callback, int64_t taskTime, const std::string &name = std::string(), + Priority priority = Priority::LOW) + { + return SendTimingEvent(InnerEvent::Get(callback, name), taskTime, priority); + } + + /** + * Post a timing task. + * + * @param callback Task callback. + * @param taskTime Process the event at taskTime. + * @param priority Priority of the event queue for this event. + * @return Returns true if task has been sent successfully. + */ + inline bool PostTimingTask(const Callback &callback, int64_t taskTime, Priority priority = Priority::LOW) + { + return PostTimingTask(callback, taskTime, std::string(), priority); + } + + /** + * Remove all sent events. + */ + void RemoveAllEvents(); + + /** + * Remove sent events. + * + * @param innerEventId The id of the event. + */ + void RemoveEvent(uint32_t innerEventId); + + /** + * Remove sent events. + * + * @param innerEventId The id of the event. + * @param param Basic parameter of the event. + */ + void RemoveEvent(uint32_t innerEventId, int64_t param); + + /** + * Remove a task. + * + * @param name Name of the task. + */ + void RemoveTask(const std::string &name); + + /** + * Add file descriptor listener for a file descriptor. + * + * @param fileDescriptor File descriptor. + * @param events Events from file descriptor, such as input, output, error + * @param listener Listener callback. + * @return Return 'ERR_OK' on success. + */ + ErrCode AddFileDescriptorListener( + int32_t fileDescriptor, uint32_t events, const std::shared_ptr &listener); + + /** + * Remove all file descriptor listeners. + */ + void RemoveAllFileDescriptorListeners(); + + /** + * Remove file descriptor listener for a file descriptor. + * + * @param fileDescriptor File descriptor. + */ + void RemoveFileDescriptorListener(int32_t fileDescriptor); + + /** + * Set the 'EventRunner' to the 'EventHandler'. + * + * @param runner The 'EventRunner'. + */ + void SetEventRunner(const std::shared_ptr &runner); + + /** + * Get the 'EventRunner' of the 'EventHandler'. + * + * @return Return the 'EventRunner'. + */ + inline const std::shared_ptr &GetEventRunner() const + { + return eventRunner_; + } + + /** + * Distribute the event. + * + * @param event The event should be distributed. + */ + void DistributeEvent(const InnerEvent::Pointer &event); + + /** + * Print out the internal information about an object in the specified format, + * helping you diagnose internal errors of the object. + * + * @param dumpr The Dumper object you have implemented to process the output internal information. + */ + void Dump(Dumper &dumper); + + /** + * Check whether an event with the given ID can be found among the events that have been sent but not processed. + * + * @param innerEventId The id of the event. + */ + bool HasInnerEvent(uint32_t innerEventId); + + /** + * Check whether an event carrying the given param can be found among the events that have been sent but not + * processed. + * + * @param param Basic parameter of the event. + */ + bool HasInnerEvent(int64_t param); + + /** + * Check whether an event carrying the given param can be found among the events that have been sent but not + * processed. + * + * @param event InnerEvent whose name is to be obtained. + * @return Returns the task name if the given event contains a specific task; returns the event ID otherwise. + */ + std::string GetEventName(const InnerEvent::Pointer &event); + + /** + * Checks whether the current event handler is idle + * @return Returns true if current event handler is idle otherwise return false. + */ + bool IsIdle(); + +protected: + /** + * Process the event. Developers should override this method. + * + * @param event The event should be processed. + */ + virtual void ProcessEvent(const InnerEvent::Pointer &event); + +private: + std::shared_ptr eventRunner_; + + static ThreadLocalData> currentEventHandler; +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // #ifndef FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_LIBEVENTHANDLER_INCLUDE_EVENT_HANDLER_H diff --git a/interfaces/innerkits/libeventhandler/include/event_handler_errors.h b/interfaces/innerkits/libeventhandler/include/event_handler_errors.h new file mode 100644 index 000000000..f8aadc7ac --- /dev/null +++ b/interfaces/innerkits/libeventhandler/include/event_handler_errors.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_INTERFACES_INNERKITS_LIBEVENTHANDLER_INCLUDE_EVENT_HANDLER_ERRORS_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_LIBEVENTHANDLER_INCLUDE_EVENT_HANDLER_ERRORS_H + +#include "errors.h" + +namespace OHOS { +namespace AppExecFwk { +// Module id of event handler is assigned in "appexecfwk_errors.h" +const uint32_t APPEXECFWK_MODULE_EVENT_HANDLER = 0x10; +constexpr ErrCode EVENT_HANDLER_ERR_OFFSET = ErrCodeOffset(SUBSYS_APPEXECFWK, APPEXECFWK_MODULE_EVENT_HANDLER); + +enum { + // Invalid parameters. + EVENT_HANDLER_ERR_INVALID_PARAM = EVENT_HANDLER_ERR_OFFSET, + // Have not set event runner yet. + EVENT_HANDLER_ERR_NO_EVENT_RUNNER, + // Not support to listen file descriptors. + EVENT_HANDLER_ERR_FD_NOT_SUPPORT, + // File descriptor is already in listening. + EVENT_HANDLER_ERR_FD_ALREADY, + // Failed to listen file descriptor. + EVENT_HANDLER_ERR_FD_FAILED, + // No permit to start or stop deposited event runner. + EVENT_HANDLER_ERR_RUNNER_NO_PERMIT, + // Event runner is already running. + EVENT_HANDLER_ERR_RUNNER_ALREADY, +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_LIBEVENTHANDLER_INCLUDE_EVENT_HANDLER_ERRORS_H diff --git a/interfaces/innerkits/libeventhandler/include/event_queue.h b/interfaces/innerkits/libeventhandler/include/event_queue.h new file mode 100644 index 000000000..0315975a1 --- /dev/null +++ b/interfaces/innerkits/libeventhandler/include/event_queue.h @@ -0,0 +1,253 @@ +/* + * 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_LIBEVENTHANDLER_INCLUDE_EVENT_QUEUE_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_LIBEVENTHANDLER_INCLUDE_EVENT_QUEUE_H + +#include +#include +#include +#include + +#include "inner_event.h" +#include "event_handler_errors.h" +#include "file_descriptor_listener.h" +#include "dumper.h" +#include "logger.h" + +namespace OHOS { +namespace AppExecFwk { +class IoWaiter; + +class EventQueue final { +public: + // Priority for the events + enum class Priority : uint32_t { + // Event that should be distributed at once if possible. + IMMEDIATE = 0, + // High priority event, sorted by handle time, should be distributed before low priority event. + HIGH, + // Normal event, sorted by handle time. + LOW, + // Event that should be distributed only if no other event right now. + IDLE, + }; + + EventQueue(); + explicit EventQueue(const std::shared_ptr &ioWaiter); + ~EventQueue() = default; + DISALLOW_COPY_AND_MOVE(EventQueue); + + /** + * Insert an event into event queue with different priority. + * The events will be sorted by handle time. + * + * @param event Event instance which should be added into event queue. + * @param Priority Priority of the event + * + * @see #Priority + */ + void Insert(InnerEvent::Pointer &event, Priority priority = Priority::LOW); + + /** + * Remove events if its owner is invalid. + */ + void RemoveOrphan(); + + /** + * Remove events with specified requirements. + * + * @param owner Owner of the event which is point to an instance of 'EventHandler'. + */ + void Remove(const std::shared_ptr &owner); + + /** + * Remove events with specified requirements. + * + * @param owner Owner of the event which is point to an instance of 'EventHandler'. + * @param innerEventId Remove events by event id. + */ + void Remove(const std::shared_ptr &owner, uint32_t innerEventId); + + /** + * Remove events with specified requirements. + * + * @param owner Owner of the event which is point to an instance of 'EventHandler'. + * @param innerEventId Remove events by event id. + * @param param Remove events by value of param. + */ + void Remove(const std::shared_ptr &owner, uint32_t innerEventId, int64_t param); + + /** + * Remove events with specified requirements. + * + * @param owner Owner of the event which is point to an instance of 'EventHandler'. + * @param name Remove events by name of the task. + */ + void Remove(const std::shared_ptr &owner, const std::string &name); + + /** + * Add file descriptor listener for a file descriptor. + * + * @param fileDescriptor File descriptor. + * @param events Events from file descriptor, such as input, output, error + * @param listener Listener callback. + * @return Return 'ERR_OK' on success. + */ + ErrCode AddFileDescriptorListener( + int32_t fileDescriptor, uint32_t events, const std::shared_ptr &listener); + + /** + * Remove all file descriptor listeners for a specified owner. + * + * @param owner Owner of the event which is point to an instance of 'FileDescriptorListener'. + */ + void RemoveFileDescriptorListener(const std::shared_ptr &owner); + + /** + * Remove file descriptor listener for a file descriptor. + * + * @param fileDescriptor File descriptor. + */ + void RemoveFileDescriptorListener(int32_t fileDescriptor); + + /** + * Prepare event queue, before calling {@link #GetEvent}. + * If {@link #Finish} is called, prepare event queue again, before calling {@link #GetEvent}. + */ + void Prepare(); + + /** + * Exit from blocking in {@link #GetEvent}, and mark the event queue finished. + * After calling {@link #Finish}, {@link #GetEvent} never returns any event, until {@link #Prepare} is called. + */ + void Finish(); + + /** + * Get event from event queue one by one. + * Before calling this method, developers should call {@link #Prepare} first. + * If none should be handled right now, the thread will be blocked in this method. + * Call {@link #Finish} to exit from blocking. + * + * @return Returns nullptr if event queue is not prepared yet, or {@link #Finish} is called. + * Otherwise returns event instance. + */ + InnerEvent::Pointer GetEvent(); + + /** + * Get expired event from event queue one by one. + * Before calling this method, developers should call {@link #Prepare} first. + * + * @param nextExpiredTime Output the expired time for the next event. + * @return Returns nullptr if none in event queue is expired. + * Otherwise returns event instance. + */ + InnerEvent::Pointer GetExpiredEvent(InnerEvent::TimePoint &nextExpiredTime); + + /** + * Prints out the internal information about an object in the specified format, + * helping you diagnose internal errors of the object. + * + * @param dumpr The Dumper object you have implemented to process the output internal information. + */ + void Dump(Dumper &dumper); + + /** + * Checks whether the current EventHandler is idle. + * + * @return Returns true if all events have been processed; returns false otherwise. + */ + bool IsIdle(); + + /** + * Check whether this event queue is empty. + * + * @return If queue is empty return true otherwise return false. + */ + bool IsQueueEmpty(); + + /** + * Check whether an event with the given ID can be found among the events that have been sent but not processed. + * + * @param owner Owner of the event which is point to an instance of 'EventHandler'. + * @param innerEventId The id of the event. + */ + bool HasInnerEvent(const std::shared_ptr &owner, uint32_t innerEventId); + + /** + * Check whether an event carrying the given param can be found among the events that have been sent but not + * processed. + * + * @param owner The owner of the event which is point to an instance of 'EventHandler'. + * @param param The basic parameter of the event. + */ + bool HasInnerEvent(const std::shared_ptr &owner, int64_t param); + +private: + using RemoveFilter = std::function; + using HasFilter = std::function; + + /* + * To avoid starvation of lower priority event queue, give a chance to process lower priority events, + * after continuous processing several higher priority events. + */ + static const uint32_t DEFAULT_MAX_HANDLED_EVENT_COUNT = 5; + + // Sub event queues for IMMEDIATE, HIGH and LOW priority. So use value of IDLE as size. + static const uint32_t SUB_EVENT_QUEUE_NUM = static_cast(Priority::IDLE); + + struct SubEventQueue { + std::list queue; + uint32_t handledEventsCount{0}; + uint32_t maxHandledEventsCount{DEFAULT_MAX_HANDLED_EVENT_COUNT}; + }; + + void Remove(const RemoveFilter &filter); + bool HasInnerEvent(const HasFilter &filter); + InnerEvent::Pointer PickEventLocked(const InnerEvent::TimePoint &now, InnerEvent::TimePoint &nextWakeUpTime); + InnerEvent::Pointer GetExpiredEventLocked(InnerEvent::TimePoint &nextExpiredTime); + void WaitUntilLocked(const InnerEvent::TimePoint &when, std::unique_lock &lock); + void HandleFileDescriptorEvent(int32_t fileDescriptor, uint32_t events); + bool EnsureIoWaiterSupportListerningFileDescriptorLocked(); + + std::mutex queueLock_; + + // Sub event queues for different priority. + std::array subEventQueues_; + + // Event queue for IDLE events. + std::list idleEvents_; + + // Next wake up time when block in 'GetEvent'. + InnerEvent::TimePoint wakeUpTime_{InnerEvent::TimePoint::max()}; + + // Mark if in idle mode, and record the start time of idle. + InnerEvent::TimePoint idleTimeStamp_{InnerEvent::Clock::now()}; + + bool isIdle_{true}; + + // Mark if the event queue is finished. + bool finished_{true}; + + // IO waiter used to block if no events while calling 'GetEvent'. + std::shared_ptr ioWaiter_; + + // File descriptor listeners to handle IO events. + std::map> listeners_; +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // #ifndef FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_LIBEVENTHANDLER_INCLUDE_EVENT_QUEUE_H diff --git a/interfaces/innerkits/libeventhandler/include/event_runner.h b/interfaces/innerkits/libeventhandler/include/event_runner.h new file mode 100644 index 000000000..4d648085c --- /dev/null +++ b/interfaces/innerkits/libeventhandler/include/event_runner.h @@ -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. + */ + +#ifndef FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_LIBEVENTHANDLER_INCLUDE_EVENT_RUNNER_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_LIBEVENTHANDLER_INCLUDE_EVENT_RUNNER_H + +#include + +#include "event_queue.h" +#include "dumper.h" +#include "logger.h" + +namespace OHOS { +namespace AppExecFwk { +class EventInnerRunner; + +class EventRunner final { +public: + EventRunner() = delete; + ~EventRunner(); + DISALLOW_COPY_AND_MOVE(EventRunner); + + /** + * Create new 'EventRunner'. + * + * @param inNewThread True if create new thread to start the 'EventRunner' automatically. + * @return Returns shared pointer of the new 'EventRunner'. + */ + static std::shared_ptr Create(bool inNewThread = true); + + /** + * Create new 'EventRunner' and start to run in a new thread. + * + * @param threadName Thread name of the new created thread. + * @return Returns shared pointer of the new 'EventRunner'. + */ + static std::shared_ptr Create(const std::string &threadName); + + /** + * Create new 'EventRunner' and start to run in a new thread. + * Eliminate ambiguity, while calling like 'EventRunner::Create("threadName")'. + * + * @param threadName Thread name of the new created thread. + * @return Returns shared pointer of the new 'EventRunner'. + */ + static inline std::shared_ptr Create(const char *threadName) + { + return Create((threadName != nullptr) ? std::string(threadName) : std::string()); + } + + /** + * Get event runner on current thread. + * + * @return Returns shared pointer of the current 'EventRunner'. + */ + static std::shared_ptr Current(); + + /** + * Start to run the 'EventRunner'. Only used for the 'EventRunner' which is not running in new thread. + * Only running on single thread. + * + * @return Returns 'ERR_OK' on success. + */ + ErrCode Run(); + + /** + * Stop to run the 'EventRunner'. Only used for the 'EventRunner' which is not running in new thread. + * It is a good practice to call {@link #Stop} on the same thread that called {@link #Run}. + * + * @return Returns 'ERR_OK' on success. + */ + ErrCode Stop(); + + /** + * Get event queue from event runner. + * This method only called by 'EventHandler'. + * + * @return Returns event queue. + */ + inline const std::shared_ptr &GetEventQueue() const + { + return queue_; + } + + /** + * Obtain the event queue of the EventRunner associated with the current thread. + * + * @return Return current event queue. + */ + static std::shared_ptr GetCurrentEventQueue(); + + /** + * Print out the internal information about an object in the specified format, + * helping you diagnose internal errors of the object. + * + * @param dumpr The Dumper object you have implemented to process the output internal information. + */ + void Dump(Dumper &dumper); + + /** + * Set the Logger object for logging messages that are processed by this event runner. + * + * @param logger The Logger object you have implemented for logging messages. + */ + void SetLogger(const std::shared_ptr &logger); + + /** + * Obtain the ID of the worker thread associated with this EventRunner. + * + * @return thread id. + */ + uint64_t GetThreadId(); + + /** + * Check whether the current thread is the worker thread of this EventRunner. + * + * @return Returns true if the current thread is the worker thread of this EventRunner; returns false otherwise. + */ + bool IsCurrentRunnerThread(); + + /** + * Obtains the EventRunner for the main thread of the application. + * + * @return Returns the EventRunner for the main thread of the application. + */ + static std::shared_ptr GetMainEventRunner(); + +private: + explicit EventRunner(bool deposit); + + friend class EventHandler; + + /** + * Check whether this event runner is running. + * + * @return if this event runner is running return true otherwise return false + */ + inline bool IsRunning() const + { + // If this runner is deposited, it it always running + return (deposit_) || (running_.load()); + } + + bool deposit_{true}; + std::atomic running_{false}; + std::shared_ptr queue_; + std::shared_ptr innerRunner_; + static std::shared_ptr mainRunner_; +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // #ifndef FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_LIBEVENTHANDLER_INCLUDE_EVENT_RUNNER_H diff --git a/interfaces/innerkits/libeventhandler/include/file_descriptor_listener.h b/interfaces/innerkits/libeventhandler/include/file_descriptor_listener.h new file mode 100644 index 000000000..e299c1603 --- /dev/null +++ b/interfaces/innerkits/libeventhandler/include/file_descriptor_listener.h @@ -0,0 +1,98 @@ +/* + * 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_LIBEVENTHANDLER_INCLUDE_FILE_DESCRIPTOR_LISTENER_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_LIBEVENTHANDLER_INCLUDE_FILE_DESCRIPTOR_LISTENER_H + +#include +#include + +#include "nocopyable.h" + +namespace OHOS { +namespace AppExecFwk { +// Listen input or output events +const uint32_t FILE_DESCRIPTOR_INPUT_EVENT = 1; +const uint32_t FILE_DESCRIPTOR_OUTPUT_EVENT = 2; +// Listen shutdown and exception events automatically, so not necessary to set. +const uint32_t FILE_DESCRIPTOR_SHUTDOWN_EVENT = 4; +const uint32_t FILE_DESCRIPTOR_EXCEPTION_EVENT = 8; +const uint32_t FILE_DESCRIPTOR_EVENTS_MASK = (FILE_DESCRIPTOR_INPUT_EVENT | FILE_DESCRIPTOR_OUTPUT_EVENT); + +class EventHandler; + +class FileDescriptorListener { +public: + DISALLOW_COPY_AND_MOVE(FileDescriptorListener); + + /** + * Called while file descriptor is readable. + * + * @param fileDescriptor File descriptor which is readable. + */ + virtual void OnReadable(int32_t fileDescriptor); + + /** + * Called while file descriptor is writable. + * + * @param fileDescriptor File descriptor which is writable. + */ + virtual void OnWritable(int32_t fileDescriptor); + + /** + * Called while shutting down this file descriptor. + * + * @param fileDescriptor File descriptor which is shutting down. + */ + virtual void OnShutdown(int32_t fileDescriptor); + + /** + * Called while error happened on this file descriptor. + * + * @param fileDescriptor Error happened on this file descriptor. + */ + virtual void OnException(int32_t fileDescriptor); + + /** + * Get owner of the event. + * + * @return Returns owner of the event after it has been sent. + */ + inline std::shared_ptr GetOwner() const + { + return owner_.lock(); + } + + /** + * Set owner of the event. + * + * @param owner Owner for the event. + */ + inline void SetOwner(const std::shared_ptr &owner) + { + owner_ = owner; + } + +protected: + FileDescriptorListener() = default; + virtual ~FileDescriptorListener() = default; + +private: + std::weak_ptr owner_; +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // #ifndef FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_LIBEVENTHANDLER_INCLUDE_FILE_DESCRIPTOR_LISTENER_H diff --git a/interfaces/innerkits/libeventhandler/include/inner_event.h b/interfaces/innerkits/libeventhandler/include/inner_event.h new file mode 100644 index 000000000..ca13bf30a --- /dev/null +++ b/interfaces/innerkits/libeventhandler/include/inner_event.h @@ -0,0 +1,506 @@ +/* + * 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_LIBEVENTHANDLER_INCLUDE_INNER_EVENT_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_LIBEVENTHANDLER_INCLUDE_INNER_EVENT_H + +#include +#include +#include +#include +#include +#include + +#include "nocopyable.h" + +namespace OHOS { +namespace AppExecFwk { +class EventHandler; + +const std::string LINE_SEPARATOR = "\n"; + +class InnerEvent final { +public: + using Clock = std::chrono::steady_clock; + using TimePoint = std::chrono::time_point; + using Callback = std::function; + using Pointer = std::unique_ptr; + + class Waiter { + public: + Waiter() = default; + virtual ~Waiter() = default; + DISALLOW_COPY_AND_MOVE(Waiter); + + virtual void Wait() = 0; + virtual void Notify() = 0; + }; + + DISALLOW_COPY_AND_MOVE(InnerEvent); + + /** + * Get InnerEvent instance from pool. + * + * @param innerEventId The id of the event. + * @param param Basic parameter of the event, default is 0. + * @return Returns the pointer of InnerEvent instance. + */ + static Pointer Get(uint32_t innerEventId, int64_t param = 0); + + /** + * Get InnerEvent instance from pool. + * + * @param innerEventId The id of the event. + * @param object Shared pointer of the object. + * @param param Basic parameter of the event, default is 0. + * @return Returns the pointer of InnerEvent instance. + */ + template + static inline Pointer Get(uint32_t innerEventId, const std::shared_ptr &object, int64_t param = 0) + { + auto event = Get(innerEventId, param); + event->SaveSharedPtr(object); + return event; + } + + /** + * Get InnerEvent instance from pool. + * + * @param innerEventId The id of the event. + * @param object Weak pointer of the object. + * @param param Basic parameter of the event, default is 0. + * @return Returns the pointer of InnerEvent instance. + */ + template + static inline Pointer Get(uint32_t innerEventId, const std::weak_ptr &object, int64_t param = 0) + { + auto event = Get(innerEventId, param); + event->SaveSharedPtr(object); + return event; + } + + /** + * Get InnerEvent instance from pool. + * + * @param innerEventId The id of the event. + * @param object Unique pointer of the object. + * @param param Basic parameter of the event, default is 0. + * @return Returns the pointer of InnerEvent instance. + */ + template + static inline Pointer Get(uint32_t innerEventId, std::unique_ptr &&object, int64_t param = 0) + { + auto event = Get(innerEventId, param); + event->SaveUniquePtr(object); + return event; + } + + /** + * Get InnerEvent instance from pool. + * + * @param innerEventId The id of the event. + * @param object Unique pointer of the object. + * @param param Basic parameter of the event, default is 0. + * @return Returns the pointer of InnerEvent instance. + */ + template + static inline Pointer Get(uint32_t innerEventId, std::unique_ptr &object, int64_t param = 0) + { + auto event = Get(innerEventId, param); + event->SaveUniquePtr(object); + return event; + } + + /** + * Get InnerEvent instance from pool. + * + * @param innerEventId The id of the event. + * @param param Basic parameter of the event. + * @param object Shared pointer of the object. + * @return Returns the pointer of InnerEvent instance. + */ + template + static inline Pointer Get(uint32_t innerEventId, int64_t param, const std::shared_ptr &object) + { + auto event = Get(innerEventId, param); + event->SaveSharedPtr(object); + return event; + } + + /** + * Get InnerEvent instance from pool. + * + * @param innerEventId The id of the event. + * @param param Basic parameter of the event. + * @param object Weak pointer of the object. + * @return Returns the pointer of InnerEvent instance. + */ + template + static inline Pointer Get(uint32_t innerEventId, int64_t param, const std::weak_ptr &object) + { + auto event = Get(innerEventId, param); + event->SaveSharedPtr(object); + return event; + } + + /** + * Get InnerEvent instance from pool. + * + * @param innerEventId The id of the event. + * @param param Basic parameter of the event. + * @param object Unique pointer of the object. + * @return Returns the pointer of InnerEvent instance. + */ + template + static inline Pointer Get(uint32_t innerEventId, int64_t param, std::unique_ptr &&object) + { + auto event = Get(innerEventId, param); + event->SaveUniquePtr(object); + return event; + } + + /** + * Get InnerEvent instance from pool. + * + * @param innerEventId The id of the event. + * @param param Basic parameter of the event. + * @param object Unique pointer of the object. + * @return Returns the pointer of InnerEvent instance. + */ + template + static inline Pointer Get(uint32_t innerEventId, int64_t param, std::unique_ptr &object) + { + auto event = Get(innerEventId, param); + event->SaveUniquePtr(object); + return event; + } + + /** + * Get InnerEvent instance from pool. + * + * @param callback Callback for task. + * @param name Name of task. + * @return Returns the pointer of InnerEvent instance, if callback is invalid, returns nullptr object. + */ + static Pointer Get(const Callback &callback, const std::string &name = std::string()); + + /** + * Get InnerEvent instance from pool. + * + * @return Returns the pointer of InnerEvent instance + */ + static Pointer Get(); + + /** + * Get owner of the event. + * + * @return Returns owner of the event after it has been sent. + */ + inline std::shared_ptr GetOwner() const + { + return owner_.lock(); + } + + /** + * Set owner of the event. + * + * @param owner Owner for the event. + */ + inline void SetOwner(const std::shared_ptr &owner) + { + owner_ = owner; + } + + /** + * Get handle time of the event. + * + * @return Returns handle time of the event after it has been sent. + */ + inline const TimePoint &GetHandleTime() const + { + return handleTime_; + } + + /** + * Set handle time of the event. + * + * @param handleTime Handle time of the event. + */ + inline void SetHandleTime(const TimePoint &handleTime) + { + handleTime_ = handleTime; + } + + /** + * Get send time of the event. + * + * @return Returns send time of the event after it has been sent. + */ + inline const TimePoint &GetSendTime() const + { + return sendTime_; + } + + /** + * Set send time of the event. + * + * @param sendTime Send time of the event. + */ + inline void SetSendTime(const TimePoint &sendTime) + { + sendTime_ = sendTime; + } + + /** + * Get id of the event. + * Make sure {@link #hasTask} returns false. + * + * @return Returns id of the event after it has been sent. + */ + inline uint32_t GetInnerEventId() const + { + return innerEventId_; + } + + /** + * Get basic param of the event. + * Make sure {@link #hasTask} returns false. + * + * @return Returns basic param of the event after it has been sent. + */ + inline int64_t GetParam() const + { + return param_; + } + + /** + * Get saved object. + * + * @return Returns shared pointer of saved object. + */ + template + std::shared_ptr GetSharedObject() const + { + const std::shared_ptr &sharedObject = *reinterpret_cast *>(smartPtr_); + if (CalculateSmartPtrTypeId(sharedObject) == smartPtrTypeId_) { + return sharedObject; + } + + const std::weak_ptr &weakObject = *reinterpret_cast *>(smartPtr_); + if (CalculateSmartPtrTypeId(weakObject) == smartPtrTypeId_) { + return weakObject.lock(); + } + + WarnSmartPtrCastMismatch(); + return nullptr; + } + + /** + * Get saved object. + * + * @return Returns unique pointer of saved object. + */ + template + std::unique_ptr GetUniqueObject() const + { + std::unique_ptr &object = *reinterpret_cast *>(smartPtr_); + if (CalculateSmartPtrTypeId(object) == smartPtrTypeId_) { + return std::move(object); + } + + WarnSmartPtrCastMismatch(); + return nullptr; + } + + /** + * Get saved object. + * + * @return Returns unique pointer of saved object. + */ + template + std::unique_ptr GetUniqueObject() const + { + std::unique_ptr &object = *reinterpret_cast *>(smartPtr_); + if (CalculateSmartPtrTypeId(object) == smartPtrTypeId_) { + return std::move(object); + } + + WarnSmartPtrCastMismatch(); + return std::unique_ptr(nullptr, nullptr); + } + + /** + * Get task name. + * Make sure {@link #hasTask} returns true. + * + * @return Returns the task name. + */ + inline const std::string &GetTaskName() const + { + return taskName_; + } + + /** + * Get task callback. + * Make sure {@link #hasTask} returns true. + * + * @return Returns the callback of the task. + */ + inline const Callback &GetTaskCallback() const + { + return taskCallback_; + } + + /** + * Obtains the Runnable task that will be executed when this InnerEvent is handled. + * + * @return Returns the callback of the task. + */ + inline const Callback &GetTask() const + { + return GetTaskCallback(); + } + + /** + * Check whether it takes a task callback in event. + * + * @return Returns true if it takes a task callback. + */ + inline bool HasTask() const + { + return static_cast(taskCallback_); + } + + /** + * Prints out the internal information about an object in the specified format, + * helping you diagnose internal errors of the object. + * + * @param return The content of the event. + */ + std::string Dump(); + +private: + using SmartPtrDestructor = void (*)(void *); + + InnerEvent() = default; + ~InnerEvent() = default; + + void ClearEvent(); + + static void WarnSmartPtrCastMismatch(); + + template + static void ReleaseSmartPtr(void *smartPtr) + { + if (smartPtr != nullptr) { + delete reinterpret_cast(smartPtr); + } + } + + template + inline void SaveSharedPtr(const T &object) + { + smartPtr_ = new T(object); + smartPtrDtor_ = ReleaseSmartPtr; + smartPtrTypeId_ = CalculateSmartPtrTypeId(object); + } + + template + inline void SaveUniquePtr(T &object) + { + smartPtr_ = new T(std::move(object)); + smartPtrDtor_ = ReleaseSmartPtr; + smartPtrTypeId_ = CalculateSmartPtrTypeId(object); + } + + /* + * Calculate the type id for different smart pointers. + */ +#ifdef __GXX_RTTI + // If RTTI(Run-Time Type Info) is enabled, use hash code of type info. + template + static inline size_t CalculateSmartPtrTypeId(const T &) + { + return typeid(T).hash_code(); + } +#else // #ifdef __GXX_RTTI + // Otherwise, generate type id using smart pointer type and the size of the elements they contain. + static const size_t SHARED_PTR_TYPE = 0x10000000; + static const size_t WEAK_PTR_TYPE = 0x20000000; + static const size_t UNIQUE_PTR_TYPE = 0x30000000; + static const size_t UNIQUE_PTR_ARRAY_TYPE = 0x40000000; + + template + static inline size_t CalculateSmartPtrTypeId(const std::shared_ptr &) + { + return (sizeof(T) | SHARED_PTR_TYPE); + } + + template + static inline size_t CalculateSmartPtrTypeId(const std::weak_ptr &) + { + return (sizeof(T) | WEAK_PTR_TYPE); + } + + template + static inline size_t CalculateSmartPtrTypeId(const std::unique_ptr &) + { + return (sizeof(T) | (sizeof(D) - 1) | UNIQUE_PTR_TYPE); + } + + template + static inline size_t CalculateSmartPtrTypeId(const std::unique_ptr &) + { + return (sizeof(T) | (sizeof(D) - 1) | UNIQUE_PTR_ARRAY_TYPE); + } +#endif // #ifdef __GXX_RTTI + + // Used by event handler to create waiter. + const std::shared_ptr &CreateWaiter(); + + // Used by event handler to tell whether event has waiter. + bool HasWaiter() const; + + // Let event pool to create instance of events. + friend class InnerEventPool; + // Let event handler to access private interface. + friend class EventHandler; + + std::weak_ptr owner_; + TimePoint handleTime_; + TimePoint sendTime_; + + // Event id of the event, if it is not a task object + uint32_t innerEventId_{0}; + + // Simple parameter for the event. + int64_t param_{0}; + + // Using to save smart pointer + size_t smartPtrTypeId_{0}; + void *smartPtr_{nullptr}; + SmartPtrDestructor smartPtrDtor_{nullptr}; + + // Task callback and its name. + Callback taskCallback_; + std::string taskName_; + + // Used for synchronized event. + std::shared_ptr waiter_; +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // #ifndef FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_LIBEVENTHANDLER_INCLUDE_INNER_EVENT_H diff --git a/interfaces/innerkits/libeventhandler/include/logger.h b/interfaces/innerkits/libeventhandler/include/logger.h new file mode 100644 index 000000000..e5b10bf64 --- /dev/null +++ b/interfaces/innerkits/libeventhandler/include/logger.h @@ -0,0 +1,32 @@ +/* + * 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_LIBEVENTHANDLER_INCLUDE_LOGGER_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_LIBEVENTHANDLER_INCLUDE_LOGGER_H + +namespace OHOS { +namespace AppExecFwk { +class Logger { +public: + /** + * Processes the content of a specified string. + * @param message the content of a specified string. + */ + virtual void Log(const std::string &line) = 0; +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_LIBEVENTHANDLER_INCLUDE_LOGGER_H \ No newline at end of file diff --git a/interfaces/innerkits/libeventhandler/include/native_implement_eventhandler.h b/interfaces/innerkits/libeventhandler/include/native_implement_eventhandler.h new file mode 100644 index 000000000..f10044707 --- /dev/null +++ b/interfaces/innerkits/libeventhandler/include/native_implement_eventhandler.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 AAFWK_APPEXECFWK_NATIVE_IMPLEMENT_EVENTHANDLER_H +#define AAFWK_APPEXECFWK_NATIVE_IMPLEMENT_EVENTHANDLER_H + +#include "event_runner.h" + +using OHOS::ErrCode; +using OHOS::AppExecFwk::EventHandler; +using OHOS::AppExecFwk::EventRunner; + +typedef void (*FileFDCallback)(int32_t filedescriptor); + +struct FileDescriptorCallbacks; +struct EventRunnerNativeImplement { +public: + EventRunnerNativeImplement(bool current); + ~EventRunnerNativeImplement(); + + /** + * Get current thread 'EventRunnerNativeImplement'. + * + * @return Returns pointer of the new 'EventRunnerNativeImplement'. + */ + static const EventRunnerNativeImplement *GetEventRunnerNativeObj(); + + /** + * Create new 'EventRunnerNativeImplement'. + * + * @return Returns pointer of the new 'EventRunnerNativeImplement'. + */ + static const EventRunnerNativeImplement *CreateEventRunnerNativeObj(); + + /** + * Start to run the 'EventRunnerNativeImplement'. Only running on single thread. + * + * @return Returns 'ERR_OK' on success. + */ + ErrCode RunEventRunnerNativeObj() const; + + /** + * Stop to run the 'EventRunnerNativeImplement'. + * + * @return Returns 'ERR_OK' on success. + */ + ErrCode StopEventRunnerNativeObj() const; + + /** + * Add file descriptor listener for a file descriptor. + * + * @param fileDescriptor File descriptor. + * @param events Events from file descriptor, such as input, output, error + * @param onReadableCallback Called while file descriptor is readable. + * @param onWritableCallback Called while file descriptor is writable. + * @param onShutdownCallback Called while shutting down this file descriptor. + * @param onExceptionCallback Called while error happened on this file descriptor. + * @return Return 'ERR_OK' on success. + */ + ErrCode AddFileDescriptorListener( + int32_t fileDescriptor, uint32_t events, const FileDescriptorCallbacks *fdCallbacks) const; + + /** + * Remove file descriptor listener for a file descriptor. + * + * @param fileDescriptor File descriptor. + */ + void RemoveFileDescriptorListener(int32_t fileDescriptor) const; + +private: + std::shared_ptr eventRunner_ = nullptr; +}; + +#endif // AAFWK_APPEXECFWK_NATIVE_IMPLEMENT_EVENTHANDLER_H diff --git a/interfaces/innerkits/libeventhandler/lib_event_handler_headers.gni b/interfaces/innerkits/libeventhandler/lib_event_handler_headers.gni new file mode 100644 index 000000000..a880dbe5f --- /dev/null +++ b/interfaces/innerkits/libeventhandler/lib_event_handler_headers.gni @@ -0,0 +1,26 @@ +# 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. + +lib_event_handler_headers = { + 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", + ] + + header_base = "interfaces/innerkits/libeventhandler/include" +} diff --git a/kits/BUILD.gn b/kits/BUILD.gn new file mode 100755 index 000000000..0c030a8b8 --- /dev/null +++ b/kits/BUILD.gn @@ -0,0 +1,137 @@ +# 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("appkit_config") { + defines = [ + "APP_LOG_TAG = \"AppkitNative\"", + "LOG_DOMAIN = 0xD001150", + ] + + include_dirs = [ + "//foundation/aafwk/standard/interfaces/innerkits/intent/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/bundlemgr", + "//foundation/aafwk/standard/interfaces/innerkits/want/include", + "//utils/system/safwk/native/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/appmgr", + "//foundation/aafwk/standard/frameworks/kits/ability/native/include", + "//foundation/aafwk/standard/interfaces/innerkits/want/include/ohos/aafwk/content", + "//base/global/resmgr_standard/interfaces/innerkits/include", + ] +} + +config("appkit_public_config") { + visibility = [ ":*" ] + include_dirs = + [ "//base/global/resmgr_standard/interfaces/innerkits/include" ] +} + +#build bin +ohos_executable("appexec") { + include_dirs = [ + "$SUBSYSTEM_DIR/common/log/include", + "$SUBSYSTEM_DIR/interfaces/innerkits/appexecfwk_core/include/appmgr", + "$SUBSYSTEM_DIR/interfaces/innerkits/appexecfwk_base/include", + "$SUBSYSTEM_DIR/interfaces/innerkits/libeventhandler/include", + "//foundation/aafwk/standard/frameworks/kits/ability/native/include", + "//foundation/aafwk/standard/interfaces/innerkits/base/include", + "//foundation/aafwk/standard/interfaces/innerkits/ability_manager/include", + "//foundation/aafwk/standard/services/abilitymgr/include", + "//foundation/appexecfwk/standard/kits/appkit/native/app/include", + "//utils/native/base/include", + "//foundation/distributedschedule/dmsfwk/services/dtbschedmgr/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + ] + + configs = [ ":appkit_config" ] + + sources = [ "$SUBSYSTEM_DIR/kits/appkit/native/app/src/main.cpp" ] + + deps = [ + "$SUBSYSTEM_DIR/kits:appkit_native", + "//foundation/aafwk/standard/frameworks/kits/ability/native:abilitykit_native", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] + + install_enable = true + part_name = "appexecfwk_standard" +} + +# build so +ohos_shared_library("appkit_native") { + include_dirs = [ + "$SUBSYSTEM_DIR/common/log/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "$SUBSYSTEM_DIR/interfaces/innerkits/appexecfwk_base/include", + "$SUBSYSTEM_DIR/interfaces/innerkits/appexecfwk_core/include/appmgr", + "$SUBSYSTEM_DIR/interfaces/innerkits/libeventhandler/include", + "$SUBSYSTEM_DIR/kits/appkit/native/app/include", + "//foundation/aafwk/standard/frameworks/kits/ability/native/include", + "//foundation/aafwk/standard/interfaces/innerkits/ability_manager/include", + "//foundation/aafwk/standard/services/abilitymgr/include", + "//utils/native/base/include", + "//foundation/distributedschedule/dmsfwk/services/dtbschedmgr/include", + "//foundation/aafwk/standard/interfaces/innerkits/want/include/ohos/aafwk_L2/content", + ] + + configs = [ ":appkit_config" ] + + public_configs = [ ":appkit_public_config" ] + + 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", + "$SUBSYSTEM_DIR/kits/appkit/native/app/src/application_env_impl.cpp", + "$SUBSYSTEM_DIR/kits/appkit/native/app/src/application_impl.cpp", + "$SUBSYSTEM_DIR/kits/appkit/native/app/src/context_container.cpp", + + #"$SUBSYSTEM_DIR/kits/appkit/native/app/main.cpp", + "$SUBSYSTEM_DIR/kits/appkit/native/app/src/context_deal.cpp", + "$SUBSYSTEM_DIR/kits/appkit/native/app/src/main_thread.cpp", + "$SUBSYSTEM_DIR/kits/appkit/native/app/src/ohos_application.cpp", + "$SUBSYSTEM_DIR/kits/appkit/native/app/src/sys_mgr_client.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", + "//base/global/resmgr_standard/frameworks/resmgr:global_resmgr", + "//foundation/aafwk/standard/frameworks/kits/ability/native:abilitykit_native", + "//foundation/aafwk/standard/interfaces/innerkits/ability_manager:ability_manager", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler:libeventhandler", + "//foundation/distributedschedule/dmsfwk/interfaces/innerkits/uri:zuri", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] + + part_name = "appexecfwk_standard" +} diff --git a/kits/appkit/napi/BUILD.gn b/kits/appkit/napi/BUILD.gn new file mode 100644 index 000000000..e41cd5d51 --- /dev/null +++ b/kits/appkit/napi/BUILD.gn @@ -0,0 +1,21 @@ +# 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") + +group("napi_packages") { + deps = [ + "//foundation/appexecfwk/standard/kits/appkit/napi/appMgr:napi_app_mgr", + "//foundation/appexecfwk/standard/kits/appkit/napi/bundlemgr:bundle_mgr", + ] +} diff --git a/kits/appkit/napi/appMgr/BUILD.gn b/kits/appkit/napi/appMgr/BUILD.gn new file mode 100644 index 000000000..eb05000f7 --- /dev/null +++ b/kits/appkit/napi/appMgr/BUILD.gn @@ -0,0 +1,52 @@ +# 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") + +ohos_shared_library("napi_app_mgr") { + include_dirs = [ + "//foundation/ace/napi/interfaces/kits", + "//third_party/node/src", + "//foundation/aafwk/standard/services/common/include", + "//utils/system/safwk/native/include", + "./", + ] + + sources = [ + "app_mgr.cpp", + "native_module.cpp", + ] + + deps = [ + "//foundation/aafwk/standard/interfaces/innerkits/ability_manager:ability_manager", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/ace/napi:ace_napi", + "//foundation/appexecfwk/standard/common:libappexecfwk_common", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "//foundation/appexecfwk/standard/libs/libeventhandler:libeventhandler_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", + ] + + relative_install_dir = "module" + subsystem_name = "appexecfwk" + part_name = "appexecfwk_standard" +} diff --git a/kits/appkit/napi/appMgr/app_mgr.cpp b/kits/appkit/napi/appMgr/app_mgr.cpp new file mode 100755 index 000000000..c0a84af84 --- /dev/null +++ b/kits/appkit/napi/appMgr/app_mgr.cpp @@ -0,0 +1,154 @@ +/* + * 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_mgr.h" + +#include +#include +#include +#include + +#include "ipc_skeleton.h" +#include "system_ability_definition.h" +#include "if_system_ability_manager.h" +#include "iservice_registry.h" + +using namespace OHOS; +using namespace OHOS::AAFwk; +using namespace OHOS::AppExecFwk; + +static napi_value ParseBundleName(napi_env env, std::string &bundleName, napi_value args) +{ + napi_status status; + napi_valuetype valuetype; + NAPI_CALL(env, napi_typeof(env, args, &valuetype)); + NAPI_ASSERT(env, valuetype == napi_string, "Wrong argument type. String expected."); + char buf[BUFFER_LENGTH_MAX] = {0}; + size_t len = 0; + napi_get_value_string_utf8(env, args, buf, BUFFER_LENGTH_MAX, &len); + HILOG_INFO("bundleName= [%{public}s].", buf); + bundleName = std::string{buf}; + // create result code + napi_value result; + status = napi_create_int32(env, 1, &result); + NAPI_ASSERT(env, status == napi_ok, "napi_create_int32 error!"); + return result; +} + +static int32_t AbilityMgrKillProcess(const std::string &bundleName) +{ + OHOS::sptr systemAbilityManager = + OHOS::SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + OHOS::sptr abilityObject = + systemAbilityManager->GetSystemAbility(OHOS::ABILITY_MGR_SERVICE_ID); + OHOS::sptr abilityManager = + OHOS::iface_cast(abilityObject); + + return abilityManager->KillProcess(bundleName); +} + +napi_value NAPI_KillProcessesByBundleName(napi_env env, napi_callback_info info) +{ + HILOG_INFO("NAPI_KillProcessesByBundleName called..."); + size_t argc = 2; + napi_value argv[argc]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); + HILOG_INFO("argc = [%{public}zu]", argc); + + if (argc >= 2) { + napi_valuetype valuetype; + NAPI_CALL(env, napi_typeof(env, argv[1], &valuetype)); + NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); + } + + AsyncCallbackInfo *async_callback_info = + new AsyncCallbackInfo{.env = env, .asyncWork = nullptr, .deferred = nullptr}; + std::string bundleName; + ParseBundleName(env, bundleName, argv[0]); + + if (argc >= 2) { + async_callback_info->bundleName = bundleName; + napi_create_reference(env, argv[1], 1, &async_callback_info->callback[0]); + + napi_value resourceName; + napi_create_string_latin1(env, "NAPI_KillProcessesByBundleNameCallBack", NAPI_AUTO_LENGTH, &resourceName); + + napi_create_async_work(env, + nullptr, + resourceName, + [](napi_env env, void *data) { + HILOG_INFO("killProcessesByBundleName called(CallBack Mode)..."); + AsyncCallbackInfo *async_callback_info = (AsyncCallbackInfo *)data; + async_callback_info->result = AbilityMgrKillProcess(async_callback_info->bundleName); + }, + [](napi_env env, napi_status status, void *data) { + HILOG_INFO("killProcessesByBundleName compeleted(CallBack Mode)..."); + AsyncCallbackInfo *async_callback_info = (AsyncCallbackInfo *)data; + + napi_value result; + napi_value callback; + napi_value undefined; + + napi_create_int32(async_callback_info->env, async_callback_info->result, &result); + napi_get_undefined(env, &undefined); + + napi_get_reference_value(env, async_callback_info->callback[0], &callback); + napi_call_function(env, undefined, callback, 1, &result, nullptr); + + if (async_callback_info->callback[0] != nullptr) { + napi_delete_reference(env, async_callback_info->callback[0]); + } + + napi_delete_async_work(env, async_callback_info->asyncWork); + delete async_callback_info; + }, + (void *)async_callback_info, + &async_callback_info->asyncWork); + + NAPI_CALL(env, napi_queue_async_work(env, async_callback_info->asyncWork)); + return NULL; + } else { + napi_value resourceName; + napi_create_string_latin1(env, "NAPI_KillProcessesByBundleNamePromise", NAPI_AUTO_LENGTH, &resourceName); + + napi_deferred deferred; + napi_value promise; + NAPI_CALL(env, napi_create_promise(env, &deferred, &promise)); + async_callback_info->deferred = deferred; + async_callback_info->bundleName = bundleName; + + napi_create_async_work(env, + nullptr, + resourceName, + [](napi_env env, void *data) { + HILOG_INFO("killProcessesByBundleName called(Promise Mode)..."); + AsyncCallbackInfo *async_callback_info = (AsyncCallbackInfo *)data; + async_callback_info->result = AbilityMgrKillProcess(async_callback_info->bundleName); + }, + [](napi_env env, napi_status status, void *data) { + HILOG_INFO("killProcessesByBundleName compeleted(Promise Mode)..."); + AsyncCallbackInfo *async_callback_info = (AsyncCallbackInfo *)data; + napi_value result; + napi_create_int32(async_callback_info->env, async_callback_info->result, &result); + napi_resolve_deferred(async_callback_info->env, async_callback_info->deferred, result); + napi_delete_async_work(env, async_callback_info->asyncWork); + delete async_callback_info; + }, + (void *)async_callback_info, + &async_callback_info->asyncWork); + napi_queue_async_work(env, async_callback_info->asyncWork); + return promise; + } +} \ No newline at end of file diff --git a/kits/appkit/napi/appMgr/app_mgr.h b/kits/appkit/napi/appMgr/app_mgr.h new file mode 100644 index 000000000..e8f462e21 --- /dev/null +++ b/kits/appkit/napi/appMgr/app_mgr.h @@ -0,0 +1,39 @@ +/* + * 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 APP_MGR_H +#define APP_MGR_H + +#include "napi/native_common.h" +#include +#include "napi/native_node_api.h" + +#include "hilog_wrapper.h" +#include "ability_manager_interface.h" + +struct AsyncCallbackInfo { + napi_env env; + napi_async_work asyncWork; + napi_deferred deferred; + napi_ref callback[2] = {0}; + std::string bundleName; + int32_t result; +}; + +#define BUFFER_LENGTH_MAX (128) + +napi_value NAPI_KillProcessesByBundleName(napi_env env, napi_callback_info); + +#endif // APP_MGR_H diff --git a/kits/appkit/napi/appMgr/native_module.cpp b/kits/appkit/napi/appMgr/native_module.cpp new file mode 100644 index 000000000..0e4c22c52 --- /dev/null +++ b/kits/appkit/napi/appMgr/native_module.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 +#include +#include +#include + +#include "app_mgr.h" +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +EXTERN_C_START +/* + * function for module exports + */ +static napi_value Init(napi_env env, napi_value exports) +{ + HILOG_INFO("native_module Init start..."); + /* + * Propertise define + */ + napi_property_descriptor desc[] = { + DECLARE_NAPI_FUNCTION("killProcessesByBundleName", NAPI_KillProcessesByBundleName)}; + + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); + HILOG_INFO("native_module Init end..."); + return exports; +} +EXTERN_C_END + +/* + * Module define + */ +static napi_module _module = {.nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = Init, + .nm_modname = "napi_app_mgr", + .nm_priv = ((void *)0), + .reserved = {0}}; +/* + * Module register function + */ +extern "C" __attribute__((constructor)) void RegisterModule(void) +{ + napi_module_register(&_module); +} \ No newline at end of file diff --git a/kits/appkit/napi/bundlemgr/BUILD.gn b/kits/appkit/napi/bundlemgr/BUILD.gn new file mode 100644 index 000000000..09415a952 --- /dev/null +++ b/kits/appkit/napi/bundlemgr/BUILD.gn @@ -0,0 +1,52 @@ +# 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") + +ohos_shared_library("bundle_mgr") { + include_dirs = [ + "//foundation/ace/napi/interfaces/kits", + "//third_party/node/src", + "//foundation/aafwk/standard/services/common/include", + "//utils/system/safwk/native/include", + "./", + ] + + sources = [ + "bundle_mgr.cpp", + "installer_callback.cpp", + "native_module.cpp", + ] + + deps = [ + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/ace/napi:ace_napi", + "//foundation/appexecfwk/standard/common:libappexecfwk_common", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "//foundation/appexecfwk/standard/libs/libeventhandler:libeventhandler_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", + ] + + relative_install_dir = "module" + subsystem_name = "appexecfwk" + part_name = "appexecfwk_standard" +} diff --git a/kits/appkit/napi/bundlemgr/bundle_mgr.cpp b/kits/appkit/napi/bundlemgr/bundle_mgr.cpp new file mode 100644 index 000000000..dc6ad9419 --- /dev/null +++ b/kits/appkit/napi/bundlemgr/bundle_mgr.cpp @@ -0,0 +1,1669 @@ +/* + * 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_mgr.h" + +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "securec.h" +#include "system_ability_definition.h" +#include "if_system_ability_manager.h" +#include "iservice_registry.h" +#include "installer_callback.h" + +using namespace OHOS; +using namespace OHOS::AAFwk; +using namespace OHOS::AppExecFwk; + +namespace { +constexpr int ARGC_SIZE = 4; +constexpr size_t BUF_SIZE = 1024; +constexpr size_t ARGS_SIZE_TWO = 2; +} // namespace + +static OHOS::sptr 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); +} + +static void ConvertApplicationInfo(napi_env env, napi_value objAppInfo, const ApplicationInfo &appInfo) +{ + napi_value nName; + NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, appInfo.name.c_str(), NAPI_AUTO_LENGTH, &nName)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAppInfo, "name", nName)); + HILOG_INFO("ConvertApplicationInfo name=%{public}s.", appInfo.name.c_str()); + + napi_value nBundleName; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, appInfo.bundleName.c_str(), NAPI_AUTO_LENGTH, &nBundleName)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAppInfo, "bundleName", nBundleName)); + HILOG_INFO("ConvertApplicationInfo bundleName=%{public}s.", appInfo.bundleName.c_str()); + + napi_value nDescription; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, appInfo.description.c_str(), NAPI_AUTO_LENGTH, &nDescription)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAppInfo, "description", nDescription)); + + napi_value nDescriptionId; + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, appInfo.descriptionId, &nDescriptionId)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAppInfo, "descriptionId", nDescriptionId)); + + napi_value nIconPath; + NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, appInfo.iconPath.c_str(), NAPI_AUTO_LENGTH, &nIconPath)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAppInfo, "iconPath", nIconPath)); + + napi_value nIconId; + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, appInfo.iconId, &nIconId)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAppInfo, "iconId", nIconId)); + + napi_value nLabel; + NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, appInfo.label.c_str(), NAPI_AUTO_LENGTH, &nLabel)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAppInfo, "label", nLabel)); + + napi_value nLabelId; + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, appInfo.labelId, &nLabelId)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAppInfo, "labelId", nLabelId)); + + napi_value nDeviceId; + NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, appInfo.deviceId.c_str(), NAPI_AUTO_LENGTH, &nDeviceId)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAppInfo, "deviceId", nDeviceId)); + + napi_value nSignatureKey; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, appInfo.signatureKey.c_str(), NAPI_AUTO_LENGTH, &nSignatureKey)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAppInfo, "signatureKey", nSignatureKey)); + + napi_value nIsSystemApp; + NAPI_CALL_RETURN_VOID(env, napi_get_boolean(env, appInfo.isSystemApp, &nIsSystemApp)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAppInfo, "isSystemApp", nIsSystemApp)); + + napi_value nIsLauncherApp; + NAPI_CALL_RETURN_VOID(env, napi_get_boolean(env, appInfo.isLauncherApp, &nIsLauncherApp)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAppInfo, "isLauncherApp", nIsLauncherApp)); + + napi_value nSupportedModes; + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, appInfo.supportedModes, &nSupportedModes)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAppInfo, "supportedModes", nSupportedModes)); + + napi_value nProcess; + 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)); + + napi_value nCodePath; + NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, appInfo.codePath.c_str(), NAPI_AUTO_LENGTH, &nCodePath)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAppInfo, "codePath", nCodePath)); + + napi_value nDataDir; + NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, appInfo.dataDir.c_str(), NAPI_AUTO_LENGTH, &nDataDir)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAppInfo, "dataDir", nDataDir)); + + napi_value nDataBaseDir; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, appInfo.dataBaseDir.c_str(), NAPI_AUTO_LENGTH, &nDataBaseDir)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAppInfo, "dataBaseDir", nDataBaseDir)); + + napi_value nCacheDir; + NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, appInfo.cacheDir.c_str(), NAPI_AUTO_LENGTH, &nCacheDir)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAppInfo, "cacheDir", nCacheDir)); + + napi_value nPermissions; + NAPI_CALL_RETURN_VOID(env, napi_create_array(env, &nPermissions)); + for (size_t idx = 0; idx < appInfo.permissions.size(); idx++) { + napi_value nPermission; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, appInfo.permissions[idx].c_str(), NAPI_AUTO_LENGTH, &nPermission)); + NAPI_CALL_RETURN_VOID(env, napi_set_element(env, nPermissions, idx, nPermission)); + } + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAppInfo, "permissions", nPermissions)); + + napi_value nModuleSourceDirs; + NAPI_CALL_RETURN_VOID(env, napi_create_array(env, &nModuleSourceDirs)); + for (size_t idx = 0; idx < appInfo.moduleSourceDirs.size(); idx++) { + napi_value nModuleSourceDir; + NAPI_CALL_RETURN_VOID(env, + napi_create_string_utf8(env, appInfo.moduleSourceDirs[idx].c_str(), NAPI_AUTO_LENGTH, &nModuleSourceDir)); + NAPI_CALL_RETURN_VOID(env, napi_set_element(env, nModuleSourceDirs, idx, nModuleSourceDir)); + } + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAppInfo, "moduleSourceDirs", nModuleSourceDirs)); + + napi_value nModuleInfos; + NAPI_CALL_RETURN_VOID(env, napi_create_array(env, &nModuleInfos)); + for (size_t idx = 0; idx < appInfo.moduleInfos.size(); idx++) { + napi_value objModuleInfos; + NAPI_CALL_RETURN_VOID(env, napi_create_object(env, &objModuleInfos)); + + napi_value nModuleName; + NAPI_CALL_RETURN_VOID(env, + napi_create_string_utf8(env, appInfo.moduleInfos[idx].moduleName.c_str(), NAPI_AUTO_LENGTH, &nModuleName)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objModuleInfos, "moduleName", nModuleName)); + + napi_value nModuleSourceDir; + NAPI_CALL_RETURN_VOID(env, + napi_create_string_utf8( + env, appInfo.moduleInfos[idx].moduleSourceDir.c_str(), NAPI_AUTO_LENGTH, &nModuleSourceDir)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objModuleInfos, "moduleSourceDir", nModuleSourceDir)); + + NAPI_CALL_RETURN_VOID(env, napi_set_element(env, nModuleInfos, idx, objModuleInfos)); + } + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAppInfo, "moduleInfos", nModuleInfos)); + HILOG_INFO("ConvertApplicationInfo cacheDir=%{public}s.", appInfo.cacheDir.c_str()); +} + +static void ConvertAbilityInfo(napi_env env, napi_value objAbilityInfo, const AbilityInfo &abilityInfo) +{ + napi_value nName; + NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, abilityInfo.name.c_str(), NAPI_AUTO_LENGTH, &nName)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAbilityInfo, "name", nName)); + HILOG_INFO("ConvertAbilityInfo name=%{public}s.", abilityInfo.name.c_str()); + + napi_value nLabel; + NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, abilityInfo.label.c_str(), NAPI_AUTO_LENGTH, &nLabel)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAbilityInfo, "label", nLabel)); + HILOG_INFO("ConvertAbilityInfo label=%{public}s.", abilityInfo.label.c_str()); + + napi_value nDescription; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, abilityInfo.description.c_str(), NAPI_AUTO_LENGTH, &nDescription)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAbilityInfo, "description", nDescription)); + + napi_value nIconPath; + NAPI_CALL_RETURN_VOID( + 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, "iconPath", nIconPath)); + + 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, "visible", nVisible)); + + napi_value nKind; + NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, abilityInfo.kind.c_str(), NAPI_AUTO_LENGTH, &nKind)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAbilityInfo, "kind", nKind)); + + napi_value nPermissions; + NAPI_CALL_RETURN_VOID(env, napi_create_array(env, &nPermissions)); + for (size_t idx = 0; idx < abilityInfo.permissions.size(); idx++) { + napi_value nPermission; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, abilityInfo.permissions[idx].c_str(), NAPI_AUTO_LENGTH, &nPermission)); + NAPI_CALL_RETURN_VOID(env, napi_set_element(env, nPermissions, idx, nPermission)); + } + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAbilityInfo, "permissions", nPermissions)); + + napi_value nDeviceCapabilities; + NAPI_CALL_RETURN_VOID(env, napi_create_array(env, &nDeviceCapabilities)); + for (size_t idx = 0; idx < abilityInfo.deviceCapabilities.size(); idx++) { + napi_value nDeviceCapability; + NAPI_CALL_RETURN_VOID(env, + napi_create_string_utf8( + env, abilityInfo.deviceCapabilities[idx].c_str(), NAPI_AUTO_LENGTH, &nDeviceCapability)); + NAPI_CALL_RETURN_VOID(env, napi_set_element(env, nDeviceCapabilities, idx, nDeviceCapability)); + } + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAbilityInfo, "deviceCapabilities", nDeviceCapabilities)); + + napi_value nDeviceTypes; + NAPI_CALL_RETURN_VOID(env, napi_create_array(env, &nDeviceTypes)); + for (size_t idx = 0; idx < abilityInfo.deviceTypes.size(); idx++) { + napi_value nDeviceType; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, abilityInfo.deviceTypes[idx].c_str(), NAPI_AUTO_LENGTH, &nDeviceType)); + NAPI_CALL_RETURN_VOID(env, napi_set_element(env, nDeviceTypes, idx, nDeviceType)); + } + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAbilityInfo, "deviceTypes", nDeviceTypes)); + + napi_value nProcess; + NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, abilityInfo.process.c_str(), NAPI_AUTO_LENGTH, &nProcess)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAbilityInfo, "process", nProcess)); + + napi_value nUri; + NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, abilityInfo.uri.c_str(), NAPI_AUTO_LENGTH, &nUri)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAbilityInfo, "uri", nUri)); + HILOG_INFO("ConvertAbilityInfo uri=%{public}s.", abilityInfo.uri.c_str()); + + napi_value nBundleName; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, abilityInfo.bundleName.c_str(), NAPI_AUTO_LENGTH, &nBundleName)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAbilityInfo, "bundleName", nBundleName)); + HILOG_INFO("ConvertAbilityInfo bundleName=%{public}s.", abilityInfo.bundleName.c_str()); + + napi_value nPackage; + NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, abilityInfo.package.c_str(), NAPI_AUTO_LENGTH, &nPackage)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAbilityInfo, "package", nPackage)); + HILOG_INFO("ConvertAbilityInfo package=%{public}s.", abilityInfo.package.c_str()); + + napi_value nModuleName; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, abilityInfo.moduleName.c_str(), NAPI_AUTO_LENGTH, &nModuleName)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAbilityInfo, "moduleName", nModuleName)); + + napi_value nApplicationName; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, abilityInfo.applicationName.c_str(), NAPI_AUTO_LENGTH, &nApplicationName)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAbilityInfo, "applicationName", nApplicationName)); + + napi_value nDeviceId; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, abilityInfo.deviceId.c_str(), NAPI_AUTO_LENGTH, &nDeviceId)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAbilityInfo, "deviceId", nDeviceId)); + + napi_value nCodePath; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, abilityInfo.codePath.c_str(), NAPI_AUTO_LENGTH, &nCodePath)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAbilityInfo, "codePath", nCodePath)); + + napi_value nResourcePath; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, abilityInfo.resourcePath.c_str(), NAPI_AUTO_LENGTH, &nResourcePath)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAbilityInfo, "resourcePath", nResourcePath)); + + napi_value nLibPath; + NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, abilityInfo.libPath.c_str(), NAPI_AUTO_LENGTH, &nLibPath)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAbilityInfo, "libPath", nLibPath)); + + napi_value nAppInfo; + NAPI_CALL_RETURN_VOID(env, napi_create_object(env, &nAppInfo)); + ConvertApplicationInfo(env, nAppInfo, abilityInfo.applicationInfo); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAbilityInfo, "applicationInfo", nAppInfo)); + + napi_value nType; + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, static_cast(abilityInfo.type), &nType)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAbilityInfo, "type", nType)); + + napi_value nOrientation; + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, static_cast(abilityInfo.orientation), &nOrientation)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAbilityInfo, "orientation", nOrientation)); + + napi_value nLaunchMode; + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, static_cast(abilityInfo.launchMode), &nLaunchMode)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objAbilityInfo, "launchMode", nLaunchMode)); +} + +static void ConvertBundleInfo(napi_env env, napi_value objBundleInfo, const BundleInfo &bundleInfo) +{ + napi_value nName; + NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, bundleInfo.name.c_str(), NAPI_AUTO_LENGTH, &nName)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "name", nName)); + + napi_value nLabel; + NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, bundleInfo.label.c_str(), NAPI_AUTO_LENGTH, &nLabel)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "label", nLabel)); + + napi_value nDescription; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, bundleInfo.description.c_str(), NAPI_AUTO_LENGTH, &nDescription)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "description", nDescription)); + + napi_value nVendor; + NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, bundleInfo.vendor.c_str(), NAPI_AUTO_LENGTH, &nVendor)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "vendor", nVendor)); + + napi_value nVersionCode; + NAPI_CALL_RETURN_VOID(env, napi_create_uint32(env, bundleInfo.versionCode, &nVersionCode)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "versionCode", nVersionCode)); + + napi_value nVersionName; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, bundleInfo.versionName.c_str(), NAPI_AUTO_LENGTH, &nVersionName)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "versionName", nVersionName)); + + napi_value nJointUserId; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, bundleInfo.jointUserId.c_str(), NAPI_AUTO_LENGTH, &nJointUserId)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "jointUserId", nJointUserId)); + + napi_value nIsKeepAlive; + NAPI_CALL_RETURN_VOID(env, napi_get_boolean(env, bundleInfo.isKeepAlive, &nIsKeepAlive)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "isKeepAlive", nIsKeepAlive)); + + napi_value nIsNativeApp; + NAPI_CALL_RETURN_VOID(env, napi_get_boolean(env, bundleInfo.isNativeApp, &nIsNativeApp)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "isNativeApp", nIsNativeApp)); + + napi_value nMinSdkVersion; + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, bundleInfo.minSdkVersion, &nMinSdkVersion)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "minSdkVersion", nMinSdkVersion)); + + napi_value nMaxSdkVersion; + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, bundleInfo.maxSdkVersion, &nMaxSdkVersion)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "maxSdkVersion", nMaxSdkVersion)); + + napi_value nMainEntry; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, bundleInfo.mainEntry.c_str(), NAPI_AUTO_LENGTH, &nMainEntry)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "mainEntry", nMainEntry)); + + napi_value nCpuAbi; + NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, bundleInfo.cpuAbi.c_str(), NAPI_AUTO_LENGTH, &nCpuAbi)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "cpuAbi", nCpuAbi)); + + napi_value nAppId; + NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, bundleInfo.appId.c_str(), NAPI_AUTO_LENGTH, &nAppId)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "appId", nAppId)); + + napi_value nReleaseType; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, bundleInfo.releaseType.c_str(), NAPI_AUTO_LENGTH, &nReleaseType)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "releaseType", nReleaseType)); + + napi_value nSeInfo; + NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, bundleInfo.seInfo.c_str(), NAPI_AUTO_LENGTH, &nSeInfo)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "seInfo", nSeInfo)); + + napi_value nEntryModuleName; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, bundleInfo.entryModuleName.c_str(), NAPI_AUTO_LENGTH, &nEntryModuleName)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "entryModuleName", nEntryModuleName)); + + napi_value nCompatibleVersion; + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, bundleInfo.compatibleVersion, &nCompatibleVersion)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "compatibleVersion", nCompatibleVersion)); + + napi_value nTargetVersion; + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, bundleInfo.targetVersion, &nTargetVersion)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "targetVersion", nTargetVersion)); + + napi_value nUid; + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, bundleInfo.uid, &nUid)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "uid", nUid)); + + napi_value nGid; + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, bundleInfo.gid, &nGid)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "gid", nGid)); + + napi_value nInstallTime; + NAPI_CALL_RETURN_VOID(env, napi_create_int64(env, bundleInfo.installTime, &nInstallTime)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "installTime", nInstallTime)); + + napi_value nUpdateTime; + NAPI_CALL_RETURN_VOID(env, napi_create_int64(env, bundleInfo.updateTime, &nUpdateTime)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "updateTime", nUpdateTime)); + + napi_value nAppInfo; + NAPI_CALL_RETURN_VOID(env, napi_create_object(env, &nAppInfo)); + ConvertApplicationInfo(env, nAppInfo, bundleInfo.applicationInfo); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "applicationInfo", nAppInfo)); + + napi_value nAbilityInfos; + NAPI_CALL_RETURN_VOID(env, napi_create_array(env, &nAbilityInfos)); + for (size_t idx = 0; idx < bundleInfo.abilityInfos.size(); idx++) { + napi_value objAbilityInfo; + NAPI_CALL_RETURN_VOID(env, napi_create_object(env, &objAbilityInfo)); + ConvertAbilityInfo(env, objAbilityInfo, bundleInfo.abilityInfos[idx]); + NAPI_CALL_RETURN_VOID(env, napi_set_element(env, nAbilityInfos, idx, objAbilityInfo)); + } + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "abilityInfos", nAbilityInfos)); + + napi_value nReqPermissions; + NAPI_CALL_RETURN_VOID(env, napi_create_array(env, &nReqPermissions)); + for (size_t idx = 0; idx < bundleInfo.reqPermissions.size(); idx++) { + napi_value nReqPermission; + NAPI_CALL_RETURN_VOID(env, + napi_create_string_utf8(env, bundleInfo.reqPermissions[idx].c_str(), NAPI_AUTO_LENGTH, &nReqPermission)); + NAPI_CALL_RETURN_VOID(env, napi_set_element(env, nReqPermissions, idx, nReqPermission)); + } + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "reqPermissions", nReqPermissions)); + + napi_value nDefPermissions; + NAPI_CALL_RETURN_VOID(env, napi_create_array(env, &nDefPermissions)); + for (size_t idx = 0; idx < bundleInfo.defPermissions.size(); idx++) { + napi_value nDefPermission; + NAPI_CALL_RETURN_VOID(env, + napi_create_string_utf8(env, bundleInfo.defPermissions[idx].c_str(), NAPI_AUTO_LENGTH, &nDefPermission)); + NAPI_CALL_RETURN_VOID(env, napi_set_element(env, nDefPermissions, idx, nDefPermission)); + } + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "defPermissions", nDefPermissions)); + + napi_value nHapModuleNames; + NAPI_CALL_RETURN_VOID(env, napi_create_array(env, &nHapModuleNames)); + for (size_t idx = 0; idx < bundleInfo.hapModuleNames.size(); idx++) { + napi_value nHapModuleName; + NAPI_CALL_RETURN_VOID(env, + napi_create_string_utf8(env, bundleInfo.hapModuleNames[idx].c_str(), NAPI_AUTO_LENGTH, &nHapModuleName)); + NAPI_CALL_RETURN_VOID(env, napi_set_element(env, nHapModuleNames, idx, nHapModuleName)); + } + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "hapModuleNames", nHapModuleNames)); + + napi_value nModuleNames; + NAPI_CALL_RETURN_VOID(env, napi_create_array(env, &nModuleNames)); + for (size_t idx = 0; idx < bundleInfo.moduleNames.size(); idx++) { + napi_value nModuleName; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, bundleInfo.moduleNames[idx].c_str(), NAPI_AUTO_LENGTH, &nModuleName)); + NAPI_CALL_RETURN_VOID(env, napi_set_element(env, nModuleNames, idx, nModuleName)); + } + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "moduleNames", nModuleNames)); + + napi_value nModulePublicDirs; + NAPI_CALL_RETURN_VOID(env, napi_create_array(env, &nModulePublicDirs)); + for (size_t idx = 0; idx < bundleInfo.modulePublicDirs.size(); idx++) { + napi_value nModulePublicDir; + NAPI_CALL_RETURN_VOID(env, + napi_create_string_utf8( + env, bundleInfo.modulePublicDirs[idx].c_str(), NAPI_AUTO_LENGTH, &nModulePublicDir)); + NAPI_CALL_RETURN_VOID(env, napi_set_element(env, nModulePublicDirs, idx, nModulePublicDir)); + } + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "modulePublicDirs", nModulePublicDirs)); + + napi_value nModuleDirs; + NAPI_CALL_RETURN_VOID(env, napi_create_array(env, &nModuleDirs)); + for (size_t idx = 0; idx < bundleInfo.moduleDirs.size(); idx++) { + napi_value nModuleDir; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, bundleInfo.moduleDirs[idx].c_str(), NAPI_AUTO_LENGTH, &nModuleDir)); + NAPI_CALL_RETURN_VOID(env, napi_set_element(env, nModuleDirs, idx, nModuleDir)); + } + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "moduleDirs", nModuleDirs)); + + napi_value nModuleResPaths; + NAPI_CALL_RETURN_VOID(env, napi_create_array(env, &nModuleResPaths)); + for (size_t idx = 0; idx < bundleInfo.moduleResPaths.size(); idx++) { + napi_value nModuleResPath; + NAPI_CALL_RETURN_VOID(env, + napi_create_string_utf8(env, bundleInfo.moduleResPaths[idx].c_str(), NAPI_AUTO_LENGTH, &nModuleResPath)); + NAPI_CALL_RETURN_VOID(env, napi_set_element(env, nModuleResPaths, idx, nModuleResPath)); + } + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objBundleInfo, "moduleResPaths", nModuleResPaths)); +} + +static void InnerGetApplicationInfos(napi_env env, std::vector &appInfos) +{ + auto iBundleMgr = GetBundleMgr(); + if (!iBundleMgr) { + HILOG_ERROR("can not get iBundleMgr"); + return; + } + iBundleMgr->GetApplicationInfos(ApplicationFlag::GET_APPLICATION_INFO_WITH_PERMS, 0, appInfos); +} + +static void ProcessApplicationInfos( + napi_env env, napi_value result, const std::vector &appInfos) +{ + if (appInfos.size() > 0) { + HILOG_INFO("-----appInfos is not null-----"); + size_t index = 0; + for (const auto &item : appInfos) { + HILOG_INFO("name{%s} ", item.name.c_str()); + HILOG_INFO("bundleName{%s} ", item.bundleName.c_str()); + for (const auto &moduleInfo : item.moduleInfos) { + HILOG_INFO("moduleName{%s} ", moduleInfo.moduleName.c_str()); + HILOG_INFO("bundleName{%s} ", moduleInfo.moduleSourceDir.c_str()); + } + napi_value objAppInfo; + NAPI_CALL_RETURN_VOID(env, napi_create_object(env, &objAppInfo)); + ConvertApplicationInfo(env, objAppInfo, item); + NAPI_CALL_RETURN_VOID(env, napi_set_element(env, result, index, objAppInfo)); + index++; + } + } else { + HILOG_INFO("-----appInfos is null-----"); + } +} +/** + * Promise and async callback + */ +napi_value GetApplicationInfos(napi_env env, napi_callback_info info) +{ + size_t argc = ARGS_SIZE_TWO; + napi_value args[ARGC_SIZE] = {nullptr}; + napi_value thisArg; + void *data = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thisArg, &data)); + + AsyncApplicationInfosCallbackInfo *asyncCallbackInfo = new AsyncApplicationInfosCallbackInfo{ + .env = env, + .asyncWork = nullptr, + .deferred = nullptr, + }; + if (argc > 0) { + HILOG_INFO("GetApplicationInfos asyncCallback."); + napi_value resourceName; + NAPI_CALL(env, napi_create_string_latin1(env, "GetApplicationInfos", NAPI_AUTO_LENGTH, &resourceName)); + for (size_t i = 0; i < argc; i++) { + napi_valuetype valuetype; + NAPI_CALL(env, napi_typeof(env, args[i], &valuetype)); + NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); + NAPI_CALL(env, napi_create_reference(env, args[i], 1, &asyncCallbackInfo->callback[i])); + } + napi_create_async_work( + env, + nullptr, + resourceName, + [](napi_env env, void *data) { + AsyncApplicationInfosCallbackInfo *asyncCallbackInfo = (AsyncApplicationInfosCallbackInfo *)data; + InnerGetApplicationInfos(env, asyncCallbackInfo->appInfos); + }, + [](napi_env env, napi_status status, void *data) { + AsyncApplicationInfosCallbackInfo *asyncCallbackInfo = (AsyncApplicationInfosCallbackInfo *)data; + napi_value result; + napi_create_array(env, &result); + ProcessApplicationInfos(env, result, asyncCallbackInfo->appInfos); + napi_value callback; + napi_value undefined; + napi_get_undefined(env, &undefined); + napi_get_reference_value(env, asyncCallbackInfo->callback[0], &callback); + napi_value callResult; + napi_call_function(env, undefined, callback, 1, &result, &callResult); + + if (asyncCallbackInfo->callback[0] != nullptr) { + napi_delete_reference(env, asyncCallbackInfo->callback[0]); + } + if (asyncCallbackInfo->callback[1] != nullptr) { + napi_delete_reference(env, asyncCallbackInfo->callback[1]); + } + 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 { + HILOG_INFO("GetApplicationInfos 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, "GetApplicationInfos", NAPI_AUTO_LENGTH, &resourceName); + napi_create_async_work( + env, + nullptr, + resourceName, + [](napi_env env, void *data) { + AsyncApplicationInfosCallbackInfo *asyncCallbackInfo = (AsyncApplicationInfosCallbackInfo *)data; + InnerGetApplicationInfos(env, asyncCallbackInfo->appInfos); + }, + [](napi_env env, napi_status status, void *data) { + HILOG_INFO("=================load================="); + AsyncApplicationInfosCallbackInfo *asyncCallbackInfo = (AsyncApplicationInfosCallbackInfo *)data; + napi_value result; + napi_create_array(env, &result); + ProcessApplicationInfos(env, result, asyncCallbackInfo->appInfos); + 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); + return promise; + } +} + +// QueryAbilityInfo(want) +static void InnerQueryAbilityInfo(napi_env env, const Want &want, AbilityInfo &abilityInfo) +{ + auto iBundleMgr = GetBundleMgr(); + if (!iBundleMgr) { + HILOG_ERROR("can not get iBundleMgr"); + return; + } + iBundleMgr->QueryAbilityInfo(want, abilityInfo); +} + +static napi_value ParseWant(napi_env env, Want &want, napi_value args) +{ + napi_status status; + char buf[BUF_SIZE] = {0}; + size_t len = 0; + napi_valuetype valueType; + NAPI_CALL(env, napi_typeof(env, args, &valueType)); + NAPI_ASSERT(env, valueType == napi_object, "param type mismatch!"); + HILOG_INFO("-----ParseWant type1-----"); + napi_value wantProp = nullptr; + status = napi_get_named_property(env, args, "want", &wantProp); + NAPI_ASSERT(env, status == napi_ok, "property name incorrect!"); + napi_typeof(env, wantProp, &valueType); + NAPI_ASSERT(env, valueType == napi_object, "property type mismatch!"); + HILOG_INFO("-----ParseWant want-----"); + // get want action property + napi_value property = nullptr; + status = napi_get_named_property(env, wantProp, "action", &property); + NAPI_ASSERT(env, status == napi_ok, "property name incorrect!"); + napi_typeof(env, property, &valueType); + NAPI_ASSERT(env, valueType == napi_string, "property type mismatch!"); + (void)memset_s(buf, BUF_SIZE, 0, BUF_SIZE); + napi_get_value_string_utf8(env, property, buf, BUF_SIZE, &len); + want.SetAction(std::string(buf)); + HILOG_INFO("ParseWantSetAction=%{public}s.", want.GetAction().c_str()); + // get want entities property + property = nullptr; + status = napi_get_named_property(env, wantProp, "entities", &property); + NAPI_ASSERT(env, status == napi_ok, "property name incorrect!"); + napi_typeof(env, property, &valueType); + NAPI_ASSERT(env, valueType == napi_object, "property type mismatch!"); + { + std::string deviceId; + std::string bundleName; + std::string abilityName; + + status = napi_get_named_property(env, wantProp, "elementName", &property); + NAPI_ASSERT(env, status == napi_ok, "property name incorrect!"); + napi_typeof(env, property, &valueType); + NAPI_ASSERT(env, valueType == napi_object, "property type mismatch!"); + + // get elementName:deviceId_ property + napi_value prop = nullptr; + status = napi_get_named_property(env, property, "deviceId", &prop); + NAPI_ASSERT(env, status == napi_ok, "property name incorrect!"); + napi_typeof(env, prop, &valueType); + NAPI_ASSERT(env, valueType == napi_string, "property type mismatch!"); + (void)memset_s(buf, BUF_SIZE, 0, BUF_SIZE); + NAPI_CALL(env, napi_get_value_string_utf8(env, prop, buf, BUF_SIZE, &len)); + deviceId = std::string(buf); + + // get elementName:bundleName_ property + prop = nullptr; + status = napi_get_named_property(env, property, "bundleName", &prop); + NAPI_ASSERT(env, status == napi_ok, "property name incorrect!"); + napi_typeof(env, prop, &valueType); + NAPI_ASSERT(env, valueType == napi_string, "property type mismatch!"); + (void)memset_s(buf, BUF_SIZE, 0, BUF_SIZE); + napi_get_value_string_utf8(env, prop, buf, BUF_SIZE, &len); + bundleName = std::string(buf); + HILOG_INFO("ParseWant bundleName=%{public}s.", bundleName.c_str()); + + // get elementName:abilityName_ property + prop = nullptr; + status = napi_get_named_property(env, property, "abilityName", &prop); + NAPI_ASSERT(env, status == napi_ok, "property name incorrect!"); + napi_typeof(env, prop, &valueType); + NAPI_ASSERT(env, valueType == napi_string, "property type mismatch!"); + (void)memset_s(buf, BUF_SIZE, 0, BUF_SIZE); + napi_get_value_string_utf8(env, prop, buf, BUF_SIZE, &len); + abilityName = std::string(buf); + HILOG_INFO("ParseWant abilityName=%{public}s.", abilityName.c_str()); + want.SetElementName(deviceId, bundleName, abilityName); + } + // create result code + napi_value result; + status = napi_create_int32(env, 1, &result); + NAPI_ASSERT(env, status == napi_ok, "napi_create_int32 error!"); + return result; +} +/** + * Promise and async callback + */ +napi_value QueryAbilityInfo(napi_env env, napi_callback_info info) +{ + + HILOG_INFO("QueryAbilityInfo called"); + size_t argc = ARGS_SIZE_TWO; + napi_value argv[ARGC_SIZE] = {nullptr}; + 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[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()); + AsyncAbilityInfoCallbackInfo *asyncCallbackInfo = + new AsyncAbilityInfoCallbackInfo{.env = env, .asyncWork = nullptr, .deferred = nullptr, .want = want}; + + if (argc >= ARGS_SIZE_TWO) { + HILOG_INFO("QueryAbilityInfo asyncCallback."); + napi_valuetype valuetype; + NAPI_CALL(env, napi_typeof(env, argv[1], &valuetype)); + NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); + napi_create_reference(env, argv[1], 1, &asyncCallbackInfo->callback[0]); + + napi_value resourceName; + napi_create_string_latin1(env, "QueryAbilityInfo", NAPI_AUTO_LENGTH, &resourceName); + napi_create_async_work( + env, + nullptr, + resourceName, + [](napi_env env, void *data) { + AsyncAbilityInfoCallbackInfo *asyncCallbackInfo = (AsyncAbilityInfoCallbackInfo *)data; + InnerQueryAbilityInfo(env, asyncCallbackInfo->want, asyncCallbackInfo->abilityInfo); + }, + [](napi_env env, napi_status status, void *data) { + AsyncAbilityInfoCallbackInfo *asyncCallbackInfo = (AsyncAbilityInfoCallbackInfo *)data; + napi_value result; + napi_create_object(env, &result); + ConvertAbilityInfo(env, result, asyncCallbackInfo->abilityInfo); + napi_value callback; + napi_value undefined; + napi_get_undefined(env, &undefined); + napi_get_reference_value(env, asyncCallbackInfo->callback[0], &callback); + napi_value callResult; + napi_call_function(env, undefined, callback, 1, &result, &callResult); + + if (asyncCallbackInfo->callback[0] != nullptr) { + napi_delete_reference(env, asyncCallbackInfo->callback[0]); + } + if (asyncCallbackInfo->callback[1] != nullptr) { + napi_delete_reference(env, asyncCallbackInfo->callback[1]); + } + 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 { + HILOG_INFO("QueryAbilityInfo 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, "QueryAbilityInfo", NAPI_AUTO_LENGTH, &resourceName); + napi_create_async_work( + env, + nullptr, + resourceName, + [](napi_env env, void *data) { + AsyncAbilityInfoCallbackInfo *asyncCallbackInfo = (AsyncAbilityInfoCallbackInfo *)data; + InnerQueryAbilityInfo(env, asyncCallbackInfo->want, asyncCallbackInfo->abilityInfo); + }, + [](napi_env env, napi_status status, void *data) { + HILOG_INFO("=================load================="); + AsyncAbilityInfoCallbackInfo *asyncCallbackInfo = (AsyncAbilityInfoCallbackInfo *)data; + napi_value result; + napi_create_object(env, &result); + ConvertAbilityInfo(env, result, asyncCallbackInfo->abilityInfo); + 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); + return promise; + } +} + +static void InnerGetApplicationInfo(napi_env env, const std::string &bundleName, ApplicationInfo &appInfo) +{ + auto iBundleMgr = GetBundleMgr(); + if (!iBundleMgr) { + HILOG_ERROR("can not get iBundleMgr"); + return; + } + iBundleMgr->GetApplicationInfo(bundleName, ApplicationFlag::GET_APPLICATION_INFO_WITH_PERMS, 0, appInfo); +} + +static napi_value ParseString(napi_env env, std::string ¶m, napi_value args) +{ + napi_status status; + napi_valuetype valuetype; + NAPI_CALL(env, napi_typeof(env, args, &valuetype)); + NAPI_ASSERT(env, valuetype == napi_string, "Wrong argument type. String expected."); + char buf[BUF_SIZE] = {0}; + size_t len = 0; + napi_get_value_string_utf8(env, args, buf, BUF_SIZE, &len); + HILOG_INFO("param=%{public}s.", buf); + param = std::string{buf}; + // create result code + napi_value result; + status = napi_create_int32(env, 1, &result); + NAPI_ASSERT(env, status == napi_ok, "napi_create_int32 error!"); + return result; +} +/** + * Promise and async callback + */ +napi_value GetApplicationInfo(napi_env env, napi_callback_info info) +{ + HILOG_INFO("NAPI_GetApplicationInfo called"); + size_t argc = ARGS_SIZE_TWO; + napi_value argv[ARGC_SIZE] = {nullptr}; + 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[0]); + AsyncApplicationInfoCallbackInfo *asyncCallbackInfo = new AsyncApplicationInfoCallbackInfo{ + .env = env, .asyncWork = nullptr, .deferred = nullptr, .bundleName = bundleName}; + + if (argc >= ARGS_SIZE_TWO) { + HILOG_INFO("GetApplicationInfo asyncCallback."); + napi_valuetype valuetype; + NAPI_CALL(env, napi_typeof(env, argv[1], &valuetype)); + NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); + napi_create_reference(env, argv[1], 1, &asyncCallbackInfo->callback[0]); + + napi_value resourceName; + napi_create_string_latin1(env, "NAPI_GetApplicationInfoCallBack", NAPI_AUTO_LENGTH, &resourceName); + napi_create_async_work( + env, + nullptr, + resourceName, + [](napi_env env, void *data) { + AsyncApplicationInfoCallbackInfo *asyncCallbackInfo = (AsyncApplicationInfoCallbackInfo *)data; + InnerGetApplicationInfo(env, asyncCallbackInfo->bundleName, asyncCallbackInfo->appInfo); + }, + [](napi_env env, napi_status status, void *data) { + AsyncApplicationInfoCallbackInfo *asyncCallbackInfo = (AsyncApplicationInfoCallbackInfo *)data; + napi_value result; + napi_create_object(env, &result); + HILOG_INFO("appInfo.name=%{public}s.", asyncCallbackInfo->appInfo.name.c_str()); + HILOG_INFO("appInfo.bundleName=%{public}s.", asyncCallbackInfo->appInfo.bundleName.c_str()); + HILOG_INFO("appInfo.description=%{public}s.", asyncCallbackInfo->appInfo.description.c_str()); + HILOG_INFO("appInfo.descriptionId=%{public}d.", asyncCallbackInfo->appInfo.descriptionId); + ConvertApplicationInfo(env, result, asyncCallbackInfo->appInfo); + napi_value callback; + napi_value undefined; + napi_get_undefined(env, &undefined); + napi_get_reference_value(env, asyncCallbackInfo->callback[0], &callback); + napi_value callResult; + napi_call_function(env, undefined, callback, 1, &result, &callResult); + + if (asyncCallbackInfo->callback[0] != nullptr) { + napi_delete_reference(env, asyncCallbackInfo->callback[0]); + } + if (asyncCallbackInfo->callback[1] != nullptr) { + napi_delete_reference(env, asyncCallbackInfo->callback[1]); + } + 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 { + HILOG_INFO("GetApplicationInfo 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, "GetApplicationInfo", NAPI_AUTO_LENGTH, &resourceName); + napi_create_async_work( + env, + nullptr, + resourceName, + [](napi_env env, void *data) { + AsyncApplicationInfoCallbackInfo *asyncCallbackInfo = (AsyncApplicationInfoCallbackInfo *)data; + InnerGetApplicationInfo(env, asyncCallbackInfo->bundleName, asyncCallbackInfo->appInfo); + }, + [](napi_env env, napi_status status, void *data) { + HILOG_INFO("=================load================="); + AsyncApplicationInfoCallbackInfo *asyncCallbackInfo = (AsyncApplicationInfoCallbackInfo *)data; + napi_value result; + napi_create_object(env, &result); + HILOG_INFO("appInfo.name=%{public}s.", asyncCallbackInfo->appInfo.name.c_str()); + HILOG_INFO("appInfo.bundleName=%{public}s.", asyncCallbackInfo->appInfo.bundleName.c_str()); + HILOG_INFO("appInfo.description=%{public}s.", asyncCallbackInfo->appInfo.description.c_str()); + HILOG_INFO("appInfo.descriptionId=%{public}d.", asyncCallbackInfo->appInfo.descriptionId); + ConvertApplicationInfo(env, result, asyncCallbackInfo->appInfo); + 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); + return promise; + } +} + +static void InnerGetBundleInfos(napi_env env, std::vector &bundleInfos) +{ + auto iBundleMgr = GetBundleMgr(); + if (!iBundleMgr) { + HILOG_ERROR("can not get iBundleMgr"); + return; + } + iBundleMgr->GetBundleInfos(BundleFlag::GET_BUNDLE_WITH_ABILITIES, bundleInfos); +} + +static void ProcessBundleInfos( + napi_env env, napi_value result, const std::vector &bundleInfos) +{ + if (bundleInfos.size() > 0) { + HILOG_INFO("-----bundleInfos is not null-----"); + size_t index = 0; + for (const auto &item : bundleInfos) { + HILOG_INFO("name{%s} ", item.name.c_str()); + HILOG_INFO("bundleName{%s} ", item.applicationInfo.bundleName.c_str()); + for (const auto &moduleInfo : item.applicationInfo.moduleInfos) { + HILOG_INFO("moduleName{%s} ", moduleInfo.moduleName.c_str()); + HILOG_INFO("moduleSourceDir{%s} ", moduleInfo.moduleSourceDir.c_str()); + } + napi_value objBundleInfo = nullptr; + napi_create_object(env, &objBundleInfo); + ConvertBundleInfo(env, objBundleInfo, item); + napi_set_element(env, result, index, objBundleInfo); + index++; + } + } else { + HILOG_INFO("-----bundleInfos is null-----"); + } +} +/** + * Promise and async callback + */ +napi_value GetBundleInfos(napi_env env, napi_callback_info info) +{ + size_t argc = ARGS_SIZE_TWO; + napi_value args[ARGC_SIZE] = {0}; + napi_value thisArg = nullptr; + void *data = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thisArg, &data)); + AsyncBundleInfosCallbackInfo *asyncCallbackInfo = new AsyncBundleInfosCallbackInfo{ + .env = env, + .asyncWork = nullptr, + .deferred = nullptr, + }; + if (argc > 0) { + HILOG_INFO("GetBundleInfo asyncCallback."); + napi_value resourceName; + napi_create_string_latin1(env, "GetBundleInfos", NAPI_AUTO_LENGTH, &resourceName); + for (size_t i = 0; i < argc; i++) { + napi_valuetype valuetype; + NAPI_CALL(env, napi_typeof(env, args[i], &valuetype)); + NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); + NAPI_CALL(env, napi_create_reference(env, args[i], 1, &asyncCallbackInfo->callback[i])); + } + + napi_create_async_work( + env, + nullptr, + resourceName, + [](napi_env env, void *data) { + AsyncBundleInfosCallbackInfo *asyncCallbackInfo = (AsyncBundleInfosCallbackInfo *)data; + InnerGetBundleInfos(env, asyncCallbackInfo->bundleInfos); + }, + [](napi_env env, napi_status status, void *data) { + AsyncBundleInfosCallbackInfo *asyncCallbackInfo = (AsyncBundleInfosCallbackInfo *)data; + napi_value result; + napi_create_array(env, &result); + ProcessBundleInfos(env, result, asyncCallbackInfo->bundleInfos); + napi_value callback; + napi_value undefined; + napi_get_undefined(env, &undefined); + napi_get_reference_value(env, asyncCallbackInfo->callback[0], &callback); + napi_value callResult; + napi_call_function(env, undefined, callback, 1, &result, &callResult); + + if (asyncCallbackInfo->callback[0] != nullptr) { + napi_delete_reference(env, asyncCallbackInfo->callback[0]); + } + if (asyncCallbackInfo->callback[1] != nullptr) { + napi_delete_reference(env, asyncCallbackInfo->callback[1]); + } + 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 { + HILOG_INFO("BundleMgr::GetBundleInfos 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, "GetBundleInfos", NAPI_AUTO_LENGTH, &resourceName); + napi_create_async_work( + env, + nullptr, + resourceName, + [](napi_env env, void *data) { + AsyncBundleInfosCallbackInfo *asyncCallbackInfo = (AsyncBundleInfosCallbackInfo *)data; + InnerGetBundleInfos(env, asyncCallbackInfo->bundleInfos); + }, + [](napi_env env, napi_status status, void *data) { + HILOG_INFO("=================load================="); + AsyncBundleInfosCallbackInfo *asyncCallbackInfo = (AsyncBundleInfosCallbackInfo *)data; + napi_value result; + napi_create_array(env, &result); + ProcessBundleInfos(env, result, asyncCallbackInfo->bundleInfos); + 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); + return promise; + } +} +static void InnerGetBundleInfo(napi_env env, const std::string &bundleName, BundleInfo &bundleInfo) +{ + auto iBundleMgr = GetBundleMgr(); + if (!iBundleMgr) { + HILOG_ERROR("can not get iBundleMgr"); + return; + } + bool ret = iBundleMgr->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_WITH_ABILITIES, bundleInfo); + if (!ret) { + HILOG_INFO("-----bundleInfo is not find-----"); + } +} +/** + * Promise and async callback + */ +napi_value GetBundleInfo(napi_env env, napi_callback_info info) +{ + HILOG_INFO("NAPI_InnerGetBundleInfo called"); + size_t argc = ARGS_SIZE_TWO; + napi_value argv[ARGC_SIZE] = {nullptr}; + 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[0]); + AsyncBundleInfoCallbackInfo *asyncCallbackInfo = + new AsyncBundleInfoCallbackInfo{.env = env, .asyncWork = nullptr, .deferred = nullptr, .param = bundleName}; + + if (argc >= ARGS_SIZE_TWO) { + HILOG_INFO("InnerGetBundleInfo asyncCallback."); + napi_valuetype valuetype; + NAPI_CALL(env, napi_typeof(env, argv[1], &valuetype)); + NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); + napi_create_reference(env, argv[1], 1, &asyncCallbackInfo->callback[0]); + + napi_value resourceName; + napi_create_string_latin1(env, "NAPI_InnerGetBundleInfo", NAPI_AUTO_LENGTH, &resourceName); + napi_create_async_work( + env, + nullptr, + resourceName, + [](napi_env env, void *data) { + AsyncBundleInfoCallbackInfo *asyncCallbackInfo = (AsyncBundleInfoCallbackInfo *)data; + InnerGetBundleInfo(env, asyncCallbackInfo->param, asyncCallbackInfo->bundleInfo); + }, + [](napi_env env, napi_status status, void *data) { + AsyncBundleInfoCallbackInfo *asyncCallbackInfo = (AsyncBundleInfoCallbackInfo *)data; + napi_value result; + napi_create_object(env, &result); + ConvertBundleInfo(env, result, asyncCallbackInfo->bundleInfo); + napi_value callback; + napi_value undefined; + napi_get_undefined(env, &undefined); + napi_get_reference_value(env, asyncCallbackInfo->callback[0], &callback); + napi_value callResult; + napi_call_function(env, undefined, callback, 1, &result, &callResult); + + if (asyncCallbackInfo->callback[0] != nullptr) { + napi_delete_reference(env, asyncCallbackInfo->callback[0]); + } + if (asyncCallbackInfo->callback[1] != nullptr) { + napi_delete_reference(env, asyncCallbackInfo->callback[1]); + } + 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 { + HILOG_INFO("GetBundleinfo 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, "GetBundleInfo", NAPI_AUTO_LENGTH, &resourceName); + napi_create_async_work( + env, + nullptr, + resourceName, + [](napi_env env, void *data) { + AsyncBundleInfoCallbackInfo *asyncCallbackInfo = (AsyncBundleInfoCallbackInfo *)data; + InnerGetBundleInfo(env, asyncCallbackInfo->param, asyncCallbackInfo->bundleInfo); + }, + [](napi_env env, napi_status status, void *data) { + HILOG_INFO("=================load================="); + AsyncBundleInfoCallbackInfo *asyncCallbackInfo = (AsyncBundleInfoCallbackInfo *)data; + napi_value result; + napi_create_object(env, &result); + ConvertBundleInfo(env, result, asyncCallbackInfo->bundleInfo); + 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); + return promise; + } +} + +static void InnerGetArchiveInfo(napi_env env, const std::string &hapFilePath, BundleInfo &bundleInfo) +{ + auto iBundleMgr = GetBundleMgr(); + if (!iBundleMgr) { + HILOG_ERROR("can not get iBundleMgr"); + return; + }; + bool ret = iBundleMgr->GetBundleArchiveInfo(hapFilePath, BundleFlag::GET_BUNDLE_WITH_ABILITIES, bundleInfo); + if (!ret) { + HILOG_INFO("-----bundleInfo is not find-----"); + } +} +/** + * Promise and async callback + */ +napi_value GetBundleArchiveInfo(napi_env env, napi_callback_info info) +{ + HILOG_INFO("NAPI_GetBundleArchiveInfo called"); + size_t argc = ARGS_SIZE_TWO; + napi_value argv[ARGC_SIZE] = {nullptr}; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); + HILOG_INFO("argc = [%{public}zu]", argc); + std::string hapFilePath; + ParseString(env, hapFilePath, argv[0]); + AsyncBundleInfoCallbackInfo *asyncCallbackInfo = + new AsyncBundleInfoCallbackInfo{.env = env, .asyncWork = nullptr, .deferred = nullptr, .param = hapFilePath}; + + if (argc >= ARGS_SIZE_TWO) { + HILOG_INFO("GetBundleArchiveInfo asyncCallback."); + napi_valuetype valuetype; + NAPI_CALL(env, napi_typeof(env, argv[1], &valuetype)); + NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); + napi_create_reference(env, argv[1], 1, &asyncCallbackInfo->callback[0]); + + napi_value resourceName; + napi_create_string_latin1(env, "NAPI_GetBundleArchiveInfo", NAPI_AUTO_LENGTH, &resourceName); + napi_create_async_work( + env, + nullptr, + resourceName, + [](napi_env env, void *data) { + AsyncBundleInfoCallbackInfo *asyncCallbackInfo = (AsyncBundleInfoCallbackInfo *)data; + InnerGetArchiveInfo(env, asyncCallbackInfo->param, asyncCallbackInfo->bundleInfo); + }, + [](napi_env env, napi_status status, void *data) { + AsyncBundleInfoCallbackInfo *asyncCallbackInfo = (AsyncBundleInfoCallbackInfo *)data; + napi_value result; + napi_create_object(env, &result); + ConvertBundleInfo(env, result, asyncCallbackInfo->bundleInfo); + napi_value callback; + napi_value undefined; + napi_get_undefined(env, &undefined); + napi_get_reference_value(env, asyncCallbackInfo->callback[0], &callback); + napi_value callResult; + napi_call_function(env, undefined, callback, 1, &result, &callResult); + + if (asyncCallbackInfo->callback[0] != nullptr) { + napi_delete_reference(env, asyncCallbackInfo->callback[0]); + } + if (asyncCallbackInfo->callback[1] != nullptr) { + napi_delete_reference(env, asyncCallbackInfo->callback[1]); + } + 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 { + HILOG_INFO("GetBundleArchiveInfo 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, "GetBundleArchiveInfo", NAPI_AUTO_LENGTH, &resourceName); + napi_create_async_work( + env, + nullptr, + resourceName, + [](napi_env env, void *data) { + AsyncBundleInfoCallbackInfo *asyncCallbackInfo = (AsyncBundleInfoCallbackInfo *)data; + InnerGetArchiveInfo(env, asyncCallbackInfo->param, asyncCallbackInfo->bundleInfo); + }, + [](napi_env env, napi_status status, void *data) { + HILOG_INFO("=================load================="); + AsyncBundleInfoCallbackInfo *asyncCallbackInfo = (AsyncBundleInfoCallbackInfo *)data; + napi_value result; + napi_create_object(env, &result); + ConvertBundleInfo(env, result, asyncCallbackInfo->bundleInfo); + 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); + return promise; + } +} + +static void ConvertPermissionDef(napi_env env, napi_value result, const PermissionDef &permissionDef) +{ + napi_value nPermissionName; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, permissionDef.permissionName.c_str(), NAPI_AUTO_LENGTH, &nPermissionName)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, result, "permissionName", nPermissionName)); + HILOG_INFO("InnerGetPermissionDef name=%{public}s.", permissionDef.permissionName.c_str()); + + napi_value nBundleName; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, permissionDef.bundleName.c_str(), NAPI_AUTO_LENGTH, &nBundleName)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, result, "bundleName", nBundleName)); + HILOG_INFO("InnerGetPermissionDef bundleName=%{public}s.", permissionDef.bundleName.c_str()); + + napi_value nGrantMode; + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, permissionDef.grantMode, &nGrantMode)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, result, "grantMode", nGrantMode)); + + napi_value nAvailableScope; + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, permissionDef.availableScope, &nAvailableScope)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, result, "availableScope", nAvailableScope)); + + napi_value nLabel; + NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, permissionDef.label.c_str(), NAPI_AUTO_LENGTH, &nLabel)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, result, "label", nLabel)); + + napi_value nLabelId; + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, permissionDef.labelId, &nLabelId)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, result, "labelId", nLabelId)); + + napi_value nDescription; + NAPI_CALL_RETURN_VOID( + env, napi_create_string_utf8(env, permissionDef.description.c_str(), NAPI_AUTO_LENGTH, &nDescription)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, result, "description", nDescription)); + + napi_value nDescriptionId; + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, permissionDef.descriptionId, &nDescriptionId)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, result, "descriptionId", nDescriptionId)); +} + +static void InnerGetPermissionDef(napi_env env, const std::string &permissionName, PermissionDef &permissionDef) +{ + auto iBundleMgr = GetBundleMgr(); + if (!iBundleMgr) { + HILOG_ERROR("can not get iBundleMgr"); + return; + }; + bool ret = iBundleMgr->GetPermissionDef(permissionName, permissionDef); + if (ret) { + HILOG_INFO("-----permissionName is not find-----"); + } +} +/** + * Promise and async callback + */ +napi_value GetPermissionDef(napi_env env, napi_callback_info info) +{ + HILOG_INFO("GetPermissionDef called"); + size_t argc = ARGS_SIZE_TWO; + napi_value argv[ARGC_SIZE] = {nullptr}; + 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[0]); + AsyncPermissionDefCallbackInfo *asyncCallbackInfo = new AsyncPermissionDefCallbackInfo{ + .env = env, .asyncWork = nullptr, .deferred = nullptr, .permissionName = permissionName}; + + if (argc >= ARGS_SIZE_TWO) { + HILOG_INFO("GetPermissionDef asyncCallback."); + napi_valuetype valuetype; + NAPI_CALL(env, napi_typeof(env, argv[1], &valuetype)); + NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); + napi_create_reference(env, argv[1], 1, &asyncCallbackInfo->callback[0]); + + napi_value resourceName; + napi_create_string_latin1(env, "GetPermissionDef", NAPI_AUTO_LENGTH, &resourceName); + napi_create_async_work( + env, + nullptr, + resourceName, + [](napi_env env, void *data) { + AsyncPermissionDefCallbackInfo *asyncCallbackInfo = (AsyncPermissionDefCallbackInfo *)data; + HILOG_INFO("asyncCallbackInfo->permissionName=%{public}s.", asyncCallbackInfo->permissionName.c_str()); + InnerGetPermissionDef(env, asyncCallbackInfo->permissionName, asyncCallbackInfo->permissionDef); + }, + [](napi_env env, napi_status status, void *data) { + AsyncPermissionDefCallbackInfo *asyncCallbackInfo = (AsyncPermissionDefCallbackInfo *)data; + napi_value result; + napi_create_object(env, &result); + ConvertPermissionDef(env, result, asyncCallbackInfo->permissionDef); + napi_value callback; + napi_value undefined; + napi_get_undefined(env, &undefined); + napi_get_reference_value(env, asyncCallbackInfo->callback[0], &callback); + napi_value callResult; + napi_call_function(env, undefined, callback, 1, &result, &callResult); + + if (asyncCallbackInfo->callback[0] != nullptr) { + napi_delete_reference(env, asyncCallbackInfo->callback[0]); + } + if (asyncCallbackInfo->callback[1] != nullptr) { + napi_delete_reference(env, asyncCallbackInfo->callback[1]); + } + 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 { + 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, "GetBundleInfo", NAPI_AUTO_LENGTH, &resourceName); + napi_create_async_work( + env, + nullptr, + resourceName, + [](napi_env env, void *data) { + AsyncPermissionDefCallbackInfo *asyncCallbackInfo = (AsyncPermissionDefCallbackInfo *)data; + InnerGetPermissionDef(env, asyncCallbackInfo->permissionName, asyncCallbackInfo->permissionDef); + }, + [](napi_env env, napi_status status, void *data) { + HILOG_INFO("=================load================="); + AsyncPermissionDefCallbackInfo *asyncCallbackInfo = (AsyncPermissionDefCallbackInfo *)data; + napi_value result; + napi_create_object(env, &result); + ConvertPermissionDef(env, result, asyncCallbackInfo->permissionDef); + 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); + return promise; + } +} + +static void InnerInstall(napi_env env, const std::string &bundleFilePath, std::string &resultMsg) +{ + auto iBundleMgr = GetBundleMgr(); + if (!iBundleMgr) { + HILOG_ERROR("can not get iBundleMgr"); + return; + } + auto iBundleInstaller = iBundleMgr->GetBundleInstaller(); + if (!iBundleInstaller) { + HILOG_ERROR("can not get iBundleInstaller"); + return; + } + InstallParam installParam; + installParam.installFlag = InstallFlag::REPLACE_EXISTING; + OHOS::sptr callback = new InstallerCallback(); + if (!callback) { + HILOG_ERROR("callback nullptr"); + return; + } + iBundleInstaller->Install(bundleFilePath, installParam, callback); + resultMsg = callback->GetResultMsg(); +} +/** + * Promise and async callback + */ +napi_value Install(napi_env env, napi_callback_info info) +{ + HILOG_INFO("Install called"); + size_t argc = ARGS_SIZE_TWO; + napi_value argv[ARGC_SIZE] = {nullptr}; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); + HILOG_INFO("argc = [%{public}zu]", argc); + std::string bundleFilePath; + ParseString(env, bundleFilePath, argv[0]); + AsyncInstallCallbackInfo *asyncCallbackInfo = + new AsyncInstallCallbackInfo{.env = env, .asyncWork = nullptr, .deferred = nullptr, .param = bundleFilePath}; + + if (argc >= ARGS_SIZE_TWO) { + HILOG_INFO("Install asyncCallback."); + napi_valuetype valuetype; + NAPI_CALL(env, napi_typeof(env, argv[1], &valuetype)); + NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); + napi_create_reference(env, argv[1], 1, &asyncCallbackInfo->callback[0]); + + napi_value resourceName; + napi_create_string_latin1(env, "Install", NAPI_AUTO_LENGTH, &resourceName); + napi_create_async_work( + env, + nullptr, + resourceName, + [](napi_env env, void *data) { + AsyncInstallCallbackInfo *asyncCallbackInfo = (AsyncInstallCallbackInfo *)data; + InnerInstall(env, asyncCallbackInfo->param, asyncCallbackInfo->resultMsg); + }, + [](napi_env env, napi_status status, void *data) { + AsyncInstallCallbackInfo *asyncCallbackInfo = (AsyncInstallCallbackInfo *)data; + napi_value result; + napi_create_object(env, &result); + napi_value nResultMsg; + napi_create_string_utf8(env, asyncCallbackInfo->resultMsg.c_str(), NAPI_AUTO_LENGTH, &nResultMsg); + napi_set_named_property(env, result, "installResultMsg", nResultMsg); + napi_value callback; + napi_value undefined; + napi_get_undefined(env, &undefined); + napi_get_reference_value(env, asyncCallbackInfo->callback[0], &callback); + napi_value callResult; + napi_call_function(env, undefined, callback, 1, &result, &callResult); + + if (asyncCallbackInfo->callback[0] != nullptr) { + napi_delete_reference(env, asyncCallbackInfo->callback[0]); + } + if (asyncCallbackInfo->callback[1] != nullptr) { + napi_delete_reference(env, asyncCallbackInfo->callback[1]); + } + 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 { + 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, "Install", NAPI_AUTO_LENGTH, &resourceName); + napi_create_async_work( + env, + nullptr, + resourceName, + [](napi_env env, void *data) { + AsyncInstallCallbackInfo *asyncCallbackInfo = (AsyncInstallCallbackInfo *)data; + InnerInstall(env, asyncCallbackInfo->param, asyncCallbackInfo->resultMsg); + }, + [](napi_env env, napi_status status, void *data) { + HILOG_INFO("=================load================="); + AsyncInstallCallbackInfo *asyncCallbackInfo = (AsyncInstallCallbackInfo *)data; + napi_value result; + napi_create_object(env, &result); + napi_value nResultMsg; + napi_create_string_utf8(env, asyncCallbackInfo->resultMsg.c_str(), NAPI_AUTO_LENGTH, &nResultMsg); + napi_set_named_property(env, result, "installResultMsg", nResultMsg); + 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); + return promise; + } +} + +static void InnerUninstall(napi_env env, const std::string &bundleName, std::string &resultMsg) +{ + auto iBundleMgr = GetBundleMgr(); + if (!iBundleMgr) { + HILOG_ERROR("can not get iBundleMgr"); + return; + } + auto iBundleInstaller = iBundleMgr->GetBundleInstaller(); + if (!iBundleInstaller) { + HILOG_ERROR("can not get iBundleInstaller"); + return; + } + InstallParam installParam; + installParam.installFlag = InstallFlag::NORMAL; + OHOS::sptr callback = new InstallerCallback(); + if (!callback) { + HILOG_ERROR("callback nullptr"); + return; + } + iBundleInstaller->Uninstall(bundleName, installParam, callback); + resultMsg = callback->GetResultMsg(); +} +/** + * Promise and async callback + */ +napi_value Uninstall(napi_env env, napi_callback_info info) +{ + HILOG_INFO("Uninstall called"); + size_t argc = ARGS_SIZE_TWO; + napi_value argv[ARGC_SIZE] = {nullptr}; + 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[0]); + AsyncInstallCallbackInfo *asyncCallbackInfo = + new AsyncInstallCallbackInfo{.env = env, .asyncWork = nullptr, .deferred = nullptr, .param = bundleName}; + + if (argc >= ARGS_SIZE_TWO) { + HILOG_INFO("Uninstall asyncCallback."); + napi_valuetype valuetype; + NAPI_CALL(env, napi_typeof(env, argv[1], &valuetype)); + NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); + napi_create_reference(env, argv[1], 1, &asyncCallbackInfo->callback[0]); + + napi_value resourceName; + napi_create_string_latin1(env, "Uninstall", NAPI_AUTO_LENGTH, &resourceName); + napi_create_async_work( + env, + nullptr, + resourceName, + [](napi_env env, void *data) { + AsyncInstallCallbackInfo *asyncCallbackInfo = (AsyncInstallCallbackInfo *)data; + InnerUninstall(env, asyncCallbackInfo->param, asyncCallbackInfo->resultMsg); + }, + [](napi_env env, napi_status status, void *data) { + AsyncInstallCallbackInfo *asyncCallbackInfo = (AsyncInstallCallbackInfo *)data; + napi_value result; + napi_create_object(env, &result); + napi_value nResultMsg; + napi_create_string_utf8(env, asyncCallbackInfo->resultMsg.c_str(), NAPI_AUTO_LENGTH, &nResultMsg); + napi_set_named_property(env, result, "installResultMsg", nResultMsg); + napi_value callback; + napi_value undefined; + napi_get_undefined(env, &undefined); + napi_get_reference_value(env, asyncCallbackInfo->callback[0], &callback); + napi_value callResult; + napi_call_function(env, undefined, callback, 1, &result, &callResult); + + if (asyncCallbackInfo->callback[0] != nullptr) { + napi_delete_reference(env, asyncCallbackInfo->callback[0]); + } + if (asyncCallbackInfo->callback[1] != nullptr) { + napi_delete_reference(env, asyncCallbackInfo->callback[1]); + } + 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 { + 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, "Install", NAPI_AUTO_LENGTH, &resourceName); + napi_create_async_work( + env, + nullptr, + resourceName, + [](napi_env env, void *data) { + AsyncInstallCallbackInfo *asyncCallbackInfo = (AsyncInstallCallbackInfo *)data; + InnerUninstall(env, asyncCallbackInfo->param, asyncCallbackInfo->resultMsg); + }, + [](napi_env env, napi_status status, void *data) { + HILOG_INFO("=================load================="); + AsyncInstallCallbackInfo *asyncCallbackInfo = (AsyncInstallCallbackInfo *)data; + napi_value result; + napi_create_object(env, &result); + napi_value nResultMsg; + napi_create_string_utf8(env, asyncCallbackInfo->resultMsg.c_str(), NAPI_AUTO_LENGTH, &nResultMsg); + napi_set_named_property(env, result, "installResultMsg", nResultMsg); + 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); + return promise; + } +} \ No newline at end of file diff --git a/kits/appkit/napi/bundlemgr/bundle_mgr.h b/kits/appkit/napi/bundlemgr/bundle_mgr.h new file mode 100644 index 000000000..f34f17d5b --- /dev/null +++ b/kits/appkit/napi/bundlemgr/bundle_mgr.h @@ -0,0 +1,99 @@ +/* + * 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 BUNDLE_MGR_H_ +#define BUNDLE_MGR_H_ +#include + +#include "napi/native_common.h" +#include "napi/native_node_api.h" + +#include "hilog_wrapper.h" +#include "ohos/aafwk/content/want.h" +#include "bundle_mgr_interface.h" +#include "application_info.h" + +struct AsyncAbilityInfoCallbackInfo { + napi_env env; + napi_async_work asyncWork; + napi_deferred deferred; + napi_ref callback[2] = {0}; + OHOS::AAFwk::Want want; + OHOS::AppExecFwk::AbilityInfo abilityInfo; +}; + +struct AsyncBundleInfoCallbackInfo { + napi_env env; + napi_async_work asyncWork; + napi_deferred deferred; + napi_ref callback[2] = {0}; + std::string param; + OHOS::AppExecFwk::BundleInfo bundleInfo; +}; + +struct AsyncApplicationInfoCallbackInfo { + napi_env env; + napi_async_work asyncWork; + napi_deferred deferred; + napi_ref callback[2] = {0}; + std::string bundleName; + OHOS::AppExecFwk::ApplicationInfo appInfo; +}; + +struct AsyncPermissionDefCallbackInfo { + napi_env env; + napi_async_work asyncWork; + napi_deferred deferred; + napi_ref callback[2] = {0}; + std::string permissionName; + OHOS::AppExecFwk::PermissionDef permissionDef; +}; + +struct AsyncBundleInfosCallbackInfo { + napi_env env; + napi_async_work asyncWork; + napi_deferred deferred; + napi_ref callback[2] = {0}; + std::vector bundleInfos; +}; + +struct AsyncApplicationInfosCallbackInfo { + napi_env env; + napi_async_work asyncWork; + napi_deferred deferred; + napi_ref callback[2] = {0}; + std::vector appInfos; +}; + +struct AsyncInstallCallbackInfo { + napi_env env; + napi_async_work asyncWork; + napi_deferred deferred; + napi_ref callback[2] = {0}; + std::string param; + std::string resultMsg; +}; + +napi_value GetApplicationInfos(napi_env env, napi_callback_info); +napi_value GetApplicationInfo(napi_env env, napi_callback_info info); +napi_value QueryAbilityInfo(napi_env env, napi_callback_info info); +napi_value GetBundleInfos(napi_env env, napi_callback_info info); +napi_value GetBundleInfo(napi_env env, napi_callback_info info); +napi_value GetBundleArchiveInfo(napi_env env, napi_callback_info info); +napi_value GetPermissionDef(napi_env env, napi_callback_info info); +napi_value Install(napi_env env, napi_callback_info info); +napi_value Uninstall(napi_env env, napi_callback_info info); + +#endif /* BUNDLE_MGR_H_ */ diff --git a/kits/appkit/napi/bundlemgr/installer_callback.cpp b/kits/appkit/napi/bundlemgr/installer_callback.cpp new file mode 100644 index 000000000..8c6e3f150 --- /dev/null +++ b/kits/appkit/napi/bundlemgr/installer_callback.cpp @@ -0,0 +1,41 @@ +/* + * 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 "installer_callback.h" + +void InstallerCallback::OnFinished(const int32_t resultCode, [[maybe_unused]] const std::string &resultMsg) +{ + resultCodeSignal_.set_value(resultCode); + resultMsgSignal_.set_value(resultMsg); +} + +void InstallerCallback::OnStatusNotify(const int32_t progress) +{ + return; +} + +int32_t InstallerCallback::GetResultCode() +{ + auto future = resultCodeSignal_.get_future(); + future.wait(); + return future.get(); +} + +std::string InstallerCallback::GetResultMsg() +{ + auto future = resultMsgSignal_.get_future(); + future.wait(); + return future.get(); +} diff --git a/kits/appkit/napi/bundlemgr/installer_callback.h b/kits/appkit/napi/bundlemgr/installer_callback.h new file mode 100644 index 000000000..177264f82 --- /dev/null +++ b/kits/appkit/napi/bundlemgr/installer_callback.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 INSTALLER_CALLBACK_H +#define INSTALLER_CALLBACK_H + +#include + +#include "nocopyable.h" +#include "status_receiver_host.h" + +class InstallerCallback : public OHOS::AppExecFwk::StatusReceiverHost { +public: + InstallerCallback() = default; + virtual ~InstallerCallback() override = default; + + virtual void OnStatusNotify(const int32_t progress) override; + virtual void OnFinished(const int32_t resultCode, [[maybe_unused]] const std::string &resultMsg) override; + int32_t GetResultCode(); + std::string GetResultMsg(); + +private: + std::promise resultCodeSignal_; + std::promise resultMsgSignal_; + DISALLOW_COPY_AND_MOVE(InstallerCallback); +}; + +#endif // INSTALLER_CALLBACK_H \ No newline at end of file diff --git a/kits/appkit/napi/bundlemgr/native_module.cpp b/kits/appkit/napi/bundlemgr/native_module.cpp new file mode 100644 index 000000000..d576b9d8f --- /dev/null +++ b/kits/appkit/napi/bundlemgr/native_module.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 +#include +#include +#include + +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "bundle_mgr.h" + +EXTERN_C_START +/* + * function for module exports + */ +static napi_value Init(napi_env env, napi_value exports) +{ + HILOG_INFO("-----Init start------"); + /* + * Propertise define + */ + napi_property_descriptor desc[] = {DECLARE_NAPI_FUNCTION("getApplicationInfos", GetApplicationInfos), + DECLARE_NAPI_FUNCTION("getApplicationInfo", GetApplicationInfo), + DECLARE_NAPI_FUNCTION("getBundleInfos", GetBundleInfos), + DECLARE_NAPI_FUNCTION("getBundleInfo", GetBundleInfo), + DECLARE_NAPI_FUNCTION("getBundleArchiveInfo", GetBundleArchiveInfo), + DECLARE_NAPI_FUNCTION("getPermissionDef", GetPermissionDef), + DECLARE_NAPI_FUNCTION("install", Install), + DECLARE_NAPI_FUNCTION("uninstall", Uninstall), + DECLARE_NAPI_FUNCTION("queryAbilityInfo", QueryAbilityInfo)}; + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); + HILOG_INFO("-----Init end------"); + return exports; +} +EXTERN_C_END + +/* + * Module define + */ +static napi_module _module = {.nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = Init, + .nm_modname = "bundle_mgr", + .nm_priv = ((void *)0), + .reserved = {0}}; +/* + * Module register function + */ +extern "C" __attribute__((constructor)) void RegisterModule(void) +{ + napi_module_register(&_module); +} diff --git a/kits/appkit/native/app/include/ability_manager.h b/kits/appkit/native/app/include/ability_manager.h new file mode 100644 index 000000000..4ae2ac228 --- /dev/null +++ b/kits/appkit/native/app/include/ability_manager.h @@ -0,0 +1,109 @@ +/* + * 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_MANAGER_H +#define ABILITY_MANAGER_H + +#include "ability_manager_client.h" +#include "app_mgr_interface.h" +#include "stack_info.h" + +namespace OHOS { +namespace AppExecFwk { + +using OHOS::AAFwk::AbilityManagerClient; +using OHOS::AAFwk::RECENT_IGNORE_UNAVAILABLE; +using OHOS::AAFwk::RecentMissionInfo; +using OHOS::AAFwk::StackInfo; +using OHOS::AAFwk::Want; +using OHOS::AppExecFwk::RunningProcessInfo; +using RuningMissionInfo = RecentMissionInfo; + +class AbilityManager { +public: + AbilityManager() = default; + virtual ~AbilityManager() = default; + + static AbilityManager &GetInstance(); + + /** + * StartAbility with want, send want to ability manager service. + * + * @param want Ability want. + * @param requestCode Ability request code. + * @return Returns ERR_OK on success, others on failure. + */ + void StartAbility(const Want &want, int requestCode); + + /** + * Ask that the mission associated with a given mission ID be moved to the + * front of the stack, so it is now visible to the user. + * + * @param missionId mission record id + */ + void MoveMissionToTop(int missionId); + + /** + * Get all stack info from ability manager service. + * + * @return Return stack information + */ + StackInfo GetAllStackInfo() const; + + /** + * Query recent Ability Mission info. + * @param numMax The maximum number of entries to return in the list. The + * actual number returned may be smaller, depending on how many tasks the + * user has started and the maximum number the system can remember. + * @param falgs Information about what to return. May be any combination + * of {@link #RECENT_WITH_EXCLUDED} and {@link #RECENT_IGNORE_UNAVAILABLE}. + * + * @returns Returns the RecentMissionInfo. + */ + std::vector QueryRecentAbilityMissionInfo(int numMax, int flags) const; + + /** + * Query running Ability Mission info. + * @param numMax The maximum number of entries to return in the list. The + * actual number returned may be smaller, depending on how many tasks the + * user has started and the maximum number the system can remember. + * + * @returns Returns the RecentMissionInfo. + */ + std::vector QueryRunningAbilityMissionInfo(int numMax) const; + + /** + * Remove the specified mission from the stack by mission id + */ + void RemoveMissions(const std::vector &missionId); + + /** + * Clears user data of the application, which is equivalent to initializing the application. + * + * @param bundleName. + */ + void ClearUpApplicationData(const std::string &bundleName); + + /** + * Obtains information about application processes that are running on the device. + * + * @returns Returns a list of running processes. + */ + RunningProcessInfo GetAllRunningProcesses(); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // ABILITY_MANAGER_H diff --git a/kits/appkit/native/app/include/ability_record_mgr.h b/kits/appkit/native/app/include/ability_record_mgr.h new file mode 100644 index 000000000..74ed2a273 --- /dev/null +++ b/kits/appkit/native/app/include/ability_record_mgr.h @@ -0,0 +1,100 @@ +/* + * 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_ABILITY_RECORD_MGR_H +#define FOUNDATION_APPEXECFWK_OHOS_ABILITY_RECORD_MGR_H + +#include +#include "iremote_object.h" +#include "ability_local_record.h" + +namespace OHOS { +namespace AppExecFwk { +class AbilityLocalRecord; +class AbilityRecordMgr { +public: + AbilityRecordMgr() = default; + ~AbilityRecordMgr() = default; + + /** + * @brief Set the eventRunner of abilitythread to the AbilityRecordMgr. + * + * @param eventRunner The runner of the abilitythread. + * + */ + void SetEventRunner(const std::shared_ptr &eventRunner); + + /** + * @brief Get the token witch is set to the AbilityRecordMgr. + * + * @return Returns the token which is set to the AbilityRecordMgr. + */ + sptr GetToken() const; + + /** + * @brief Set the token witch the app launched. + * + * @param token The token which the is launched by app. + */ + void SetToken(const sptr &token); + + /** + * @brief Save the token and abilityRecord to the AbilityRecordMgr. + * + * @param token The token which the abilityRecord belongs to. + * @param abilityRecord the abilityRecord witch contains the context info belong the the ability. + * + */ + void AddAbilityRecord(const sptr &token, const std::shared_ptr &abilityRecord); + + /** + * @brief Remove the abilityRecord by token. + * + * @param token The token which the abilityRecord belongs to. + * + */ + void RemoveAbilityRecord(const sptr &token); + + /** + * @brief Get the number of abilityRecords which the AbilityRecordMgr saved. + * + * @return Return the number of abilityRecords which the AbilityRecordMgr saved. + * + */ + int GetRecordCount() const; + + /** + * @brief Get the abilityRecord by token. + * + * @param token The token which the abilityRecord belongs to. + * + */ + std::shared_ptr GetAbilityItem(const sptr &token) const; + + /** + * @brief Get the all tokens in the abilityRecordMgr. + * + * @return all tokens in the abilityRecordMgr. + * + */ + std::vector> GetAllTokens(); + +private: + std::map, std::shared_ptr> abilityRecords_; + sptr tokens_; // we use ThreadLocal +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_OHOS_ABILITY_RECORD_MGR_H diff --git a/kits/appkit/native/app/include/ability_start_setting.h b/kits/appkit/native/app/include/ability_start_setting.h new file mode 100644 index 000000000..fa511ec4c --- /dev/null +++ b/kits/appkit/native/app/include/ability_start_setting.h @@ -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. + */ + +#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; + + 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 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 std::shared_ptr 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/app_loader.h b/kits/appkit/native/app/include/app_loader.h new file mode 100644 index 000000000..a1197ca89 --- /dev/null +++ b/kits/appkit/native/app/include/app_loader.h @@ -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. + */ + +#ifndef FOUNDATION_APPEXECFWK_OHOS_APPLICATION_LOADER_H +#define FOUNDATION_APPEXECFWK_OHOS_APPLICATION_LOADER_H + +#include "ohos_application.h" + +#include +#include +#include + +namespace OHOS { +namespace AppExecFwk { +using CreateApplication = std::function; + +class ApplicationLoader { +public: + /** + * @description: Gets the ApplicationLoader object to application register + * @param None + * @return ApplicationLoader + */ + static ApplicationLoader &GetInstance(); + + /** + * @description: Ddefault deconstructor + * @param None + * @return None + */ + ~ApplicationLoader() = default; + + /** + * @description: Gets the ApplicationLoader object to register application + * @param bundleName the bundle name of the application. + * @param createFunc constructor function of application class. + * @return None + */ + void RegisterApplication(const std::string &bundleName, const CreateApplication &createFunc); + + /** + * @description: Gets the {@link OHOSApplication} object + * @param bundleName the bundle name of the application. + * @return Return {@link OHOSApplication} object which is registered by developer. + */ + OHOSApplication *GetApplicationByName(const std::string &bundleName = "OHOSApplication"); + +private: + ApplicationLoader() = default; + ApplicationLoader(const ApplicationLoader &) = delete; + ApplicationLoader &operator=(const ApplicationLoader &) = delete; + ApplicationLoader(ApplicationLoader &&) = delete; + ApplicationLoader &operator=(ApplicationLoader &&) = delete; + + std::unordered_map applications_; +}; + +/** + * @brief Registers the class name of an {@link OHOSApplication} child class. + * + * After implementing your own {@link OHOSApplication} class, you should call this function so that the + * OHOSApplication management framework can create OHOSApplication instances when loading your + * OHOSApplication class. + * + * @param className Indicates the {@link OHOSApplication} class name to register. + */ +#define REGISTER_APPLICATION(bundleName, className) \ + __attribute__((constructor)) void REGISTER_APPLICATION##className() \ + { \ + ApplicationLoader::GetInstance().RegisterApplication( \ + #bundleName, []() -> OHOSApplication * { return new (std::nothrow) className; }); \ + } + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_OHOS_APPLICATION_LOADER_H diff --git a/kits/appkit/native/app/include/application_context.h b/kits/appkit/native/app/include/application_context.h new file mode 100644 index 000000000..7f772a79b --- /dev/null +++ b/kits/appkit/native/app/include/application_context.h @@ -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. + */ + +#ifndef FOUNDATION_APPEXECFWK_OHOS_APPLICATION_CONTEXT_H +#define FOUNDATION_APPEXECFWK_OHOS_APPLICATION_CONTEXT_H + +#include "context_container.h" + +namespace OHOS { +namespace AppExecFwk { + +class ApplicationContext : public ContextContainer, public std::enable_shared_from_this { +public: + ApplicationContext() = default; + virtual ~ApplicationContext() = default; + + /** + * @brief Obtains information about the current ability. + * The returned information includes the class name, bundle name, and other information about the current ability. + * + * @return Returns the AbilityInfo object for the current ability. + */ + const std::shared_ptr GetAbilityInfo() override; + + /** + * @brief Starts a new ability. + * An ability using the AbilityInfo.AbilityType.SERVICE or AbilityInfo.AbilityType.PAGE template uses this method + * to start a specific ability. The system locates the target ability from installed abilities based on the value + * of the want parameter and then starts it. You can specify the ability to start using the want parameter. + * + * @param want Indicates the Want containing information about the target ability to start. + * + * @param requestCode Indicates the request code returned after the ability using the AbilityInfo.AbilityType.PAGE + * template is started. You can define the request code to identify the results returned by abilities. The value + * ranges from 0 to 65535. This parameter takes effect only on abilities using the AbilityInfo.AbilityType.PAGE + * template. + * + */ + void StartAbility(const AAFwk::Want &want, int requestCode) override; + + /** + * @brief Starts a new ability with special ability start setting. + * + * @param want Indicates the Want containing information about the target ability to start. + * @param requestCode Indicates the request code returned after the ability is started. You can define the request + * code to identify the results returned by abilities. The value ranges from 0 to 65535. + * @param abilityStartSetting Indicates the special start setting used in starting ability. + * + */ + void StartAbility(const Want &want, int requestCode, const AbilityStartSetting &abilityStartSetting) override; + + /** + * @brief Destroys another ability you had previously started by calling Ability.startAbilityForResult + * (ohos.aafwk.content.Want, int, ohos.aafwk.ability.startsetting.AbilityStartSetting) with the same requestCode + * passed. + * + * @param requestCode Indicates the request code passed for starting the ability. + * + */ + void TerminateAbility(int requestCode) override; + + /** + * @brief Destroys the current ability. + * + */ + void TerminateAbility() override; + + /** + * @brief Obtains the bundle name of the ability that called the current ability. + * You can use the obtained bundle name to check whether the calling ability is allowed to receive the data you will + * send. If you did not use Ability.startAbilityForResult(ohos.aafwk.content.Want, int, + * ohos.aafwk.ability.startsetting.AbilityStartSetting) to start the calling ability, null is returned. + * + * @return Returns the bundle name of the calling ability; returns null if no calling ability is available. + */ + std::string GetCallingBundle() override; + + /** + * @brief Connects the current ability to an ability using the AbilityInfo.AbilityType.SERVICE template. + * + * @param want Indicates the want containing information about the ability to connect + * + * @param conn Indicates the callback object when the target ability is connected. + * + * @return True means success and false means failure + */ + bool ConnectAbility(const Want &want, const sptr &conn) override; + + /** + * @brief Disconnects the current ability from an ability + * + * @param conn Indicates the IAbilityConnection callback object passed by connectAbility after the connection + * is set up. The IAbilityConnection object uniquely identifies a connection between two abilities. + */ + void DisconnectAbility(const sptr &conn) override; + + /** + * @brief Destroys another ability that uses the AbilityInfo.AbilityType.SERVICE template. + * The current ability using either the AbilityInfo.AbilityType.SERVICE or AbilityInfo.AbilityType.PAGE + * template can call this method to destroy another ability that uses the AbilityInfo.AbilityType.SERVICE + * template. The current ability itself can be destroyed by calling the terminateAbility() method. + * + * @param want Indicates the Want containing information about the ability to destroy. + * + * @return Returns true if the ability is destroyed successfully; returns false otherwise. + */ + bool StopAbility(const AAFwk::Want &want) override; + +protected: + sptr GetToken() override; +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_OHOS_APPLICATION_CONTEXT_H diff --git a/kits/appkit/native/app/include/application_env.h b/kits/appkit/native/app/include/application_env.h new file mode 100644 index 000000000..a2ef64534 --- /dev/null +++ b/kits/appkit/native/app/include/application_env.h @@ -0,0 +1,52 @@ +/* + * 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_APPEXECFWK_APPLICATION_ENV_H +#define OHOS_APPEXECFWK_APPLICATION_ENV_H + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif + +/** + * @brief Obtains the bundle name of the application + * @param - + * @return Returns the pointer to the bundle name if the operation is successful; returns a null pointer otherwise. + */ +const char *GetBundleName(); + +/** + * @brief Obtains the source code path of this application. + * @param - + * @return Returns the pointer to the source code path of this application. + */ +const char *GetSrcPath(); + +/** + * @brief Obtains the data path of this application. + * @param - + * @return Returns the pointer to the data path of this application. + */ +const char *GetDataPath(); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif + +#endif // OHOS_ABILITY_ENV_H \ No newline at end of file diff --git a/kits/appkit/native/app/include/application_env_impl.h b/kits/appkit/native/app/include/application_env_impl.h new file mode 100644 index 000000000..358ef59bf --- /dev/null +++ b/kits/appkit/native/app/include/application_env_impl.h @@ -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. + */ + +#ifndef OHOS_APPLICATION_ENV_IMPL_H +#define OHOS_APPLICATION_ENV_IMPL_H + +#include +#include "nocopyable.h" + +/** + * L1 App_info define + */ +#include +#include + +typedef struct { + std::string bundleName; + std::string srcPath; + std::string dataPath; + bool isNativeApp; + std::list moduleNames; +} AppInfo; + +namespace OHOS { +namespace AppExecFwk { + +struct ApplicationInfo; +class ApplicationEnvImpl : public NoCopyable { + +public: + /** + * @brief Gets an instance of the applicationenvimpl class + * @param - + * @return instance indicates + */ + static ApplicationEnvImpl *GetInstance() + { + static ApplicationEnvImpl instance; + return &instance; + } + /** + * @brief destructor + * @param - + * @return - + */ + ~ApplicationEnvImpl() override = default; + + /** + * @brief Sets L1 information about the runtime environment of the application to which the + * ability belongs, including the bundle name, source code path, and data path. + * @param appInfo + * @return void + */ + void SetAppInfo(const AppInfo &appInfo); + + /** + * @brief Sets information about the runtime environment of the application to which the + * ability belongs, including the bundle name, source code path, and data path. + * @param appInfo + * @return void + */ + void SetAppInfo(const ApplicationInfo &appInfo); + + /** + * @brief Gets the bundlename of the application's runtime environment + * @param - + * @return bundleName + */ + const std::string &GetBundleName() const; + + /** + * @brief Gets the SrcPath of the application's runtime environment + * @param - + * @return SrcPath + */ + const std::string &GetSrcPath() const; + + /** + * @brief Gets the DataPath of the application's runtime environment + * @param - + * @return DataPath + */ + const std::string &GetDataPath() const; + +private: + ApplicationEnvImpl() = default; + + std::string bundleName_; + + std::string srcPath_; + + std::string dataPath_; + + static ApplicationEnvImpl instance_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // OHOS_APPLICATION_ENV_IMPL_H diff --git a/kits/appkit/native/app/include/application_impl.h b/kits/appkit/native/app/include/application_impl.h new file mode 100644 index 000000000..fca3847d2 --- /dev/null +++ b/kits/appkit/native/app/include/application_impl.h @@ -0,0 +1,148 @@ +/* + * 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_APPLICATION_IMPL_H +#define FOUNDATION_APPEXECFWK_OHOS_APPLICATION_IMPL_H + +#include +#include +#include "application_info.h" +#include "profile.h" +#include "iremote_object.h" +#include "ability_local_record.h" + +namespace OHOS { +namespace AppExecFwk { +class OHOSApplication; +class AbilityLocalRecord; +class Configuration; +class ApplicationImpl { +public: + ApplicationImpl(); + virtual ~ApplicationImpl() = default; + + /** + * @brief Set the application to the ApplicationImpl. + * + * @param application The application which the mainthread launched. + * + */ + void SetApplication(const std::shared_ptr &application); + + /** + * @brief Schedule the application to the APP_STATE_READY state. + * + * @return Returns true if performAppReady is scheduled successfully; + * Returns false otherwise. + */ + bool PerformAppReady(); + + /** + * @brief Schedule the application to the APP_STATE_FOREGROUND state. + * + * @return Returns true if PerformForeground is scheduled successfully; + * Returns false otherwise. + */ + bool PerformForeground(); + + /** + * @brief Schedule the application to the APP_STATE_BACKGROUND state. + * + * @return Returns true if PerformBackground is scheduled successfully; + * Returns false otherwise. + */ + bool PerformBackground(); + + /** + * @brief Schedule the application to the APP_STATE_TERMINATED state. + * + * @return Returns true if PerformTerminate is scheduled successfully; + * Returns false otherwise. + */ + bool PerformTerminate(); + + /** + * @brief Schedule the application to the APP_STATE_TERMINATED state. + * + * @return Returns true if PerformTerminate is scheduled successfully; + * Returns false otherwise. + */ + void PerformTerminateStrong(); + + /** + * @brief Set the target state to application. + * + * @param state The target state of application. + * + */ + int SetState(int state); + + /** + * @brief Get the current state of application. + * + * @return Returns the current state of application. + * + */ + int GetState() const; + + /** + * @brief Set the RecordId to application. + * + * @param id recordId. + * + */ + void SetRecordId(int id); + + /** + * @brief Get the recordId of application. + * + * @return Returns the recordId of application. + * + */ + int GetRecordId() const; + + /** + * @brief System determines to trim the memory. + * + * @param level Indicates the memory trim level, which shows the current memory usage status. + * + */ + void PerformMemoryLevel(int level); + + /** + * @brief System determines to send the new config to application. + * + * @param config Indicates the updated configuration information. + * + */ + void PerformConfigurationUpdated(const Configuration &config); + +private: + enum { + APP_STATE_CREATE = 0, + APP_STATE_READY = 1, + APP_STATE_FOREGROUND = 2, + APP_STATE_BACKGROUND = 3, + APP_STATE_TERMINATED = 4 + }; + int curState_; + int recordId_; + std::shared_ptr application_ = nullptr; + + DISALLOW_COPY_AND_MOVE(ApplicationImpl); +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_OHOS_APPLICATION_IMPL_H diff --git a/kits/appkit/native/app/include/context.h b/kits/appkit/native/app/include/context.h new file mode 100755 index 000000000..8d428f05e --- /dev/null +++ b/kits/appkit/native/app/include/context.h @@ -0,0 +1,485 @@ +/* + * 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_CONTEXT_H +#define FOUNDATION_APPEXECFWK_OHOS_CONTEXT_H + +#include + +#include "bundle_mgr_interface.h" +#include "ability_manager_interface.h" +#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" + +namespace OHOS { +namespace AppExecFwk { + +using Want = OHOS::AAFwk::Want; + +#define OHOS_PERMISSIONS_REQUEST_KEY "HAS_CURRENT_PERMISSIONS_REQUEST_KEY" +#define OHOS_PERMISSIONS_REQUEST_RESULT_KEY "HAS_CURRENT_PERMISSIONS_RESULT_KEY" +#define OHOS_PERMISSIONS_REQUEST_BUNDLE_NAME_KEY "HAS_CURRENT_PERMISSIONS_REQUEST_BUNDLE_NAME_KEY" +#define OHOS_PERMISSIONS_REQUEST_USER_ID_KEY "HAS_CURRENT_PERMISSIONS_REQUEST_USER_ID_KEY" + +class DataAbilityHelper; +class IAbilityManager; +class Context { +public: + Context() = default; + virtual ~Context() = default; + + /** + * The value 0 indicates that there is no restriction on creating contexts for applications. + */ + int MODE_PRIVATE = 0x0000; + + /** + * static final int CONTEXT_INCLUDE_CODE + * Indicates the flag used with createBundleContext(java.lang.String,int) for creating a Context + * object that includes the application code. + * + * The value is 0x00000001. + * + * @since 3 + */ + int CONTEXT_INCLUDE_CODE = 0x00000001; + + /** + * static final int CONTEXT_IGNORE_SECURITY + * Indicates the flag used with createBundleContext(java.lang.String,int) for creating a Context + * object that can always be loaded with all security restrictions ignored. + * + * The value is 0x00000002. + * + * @since 3 + */ + int CONTEXT_IGNORE_SECURITY = 0x00000002; + + /** + * static final int CONTEXT_RESTRICTED + * Indicates the flag used with createBundleContext(java.lang.String,int) for creating a Context + * object in which particular features may be disabled. + * + * The value is 0x00000004. + * + * @since 3 + */ + int CONTEXT_RESTRICTED = 0x00000004; + + int CONTEXT_RESOUCE_ONLY = 0x00000008; + + /** + * Called when getting the ProcessInfo + * + * @return ProcessInfo + */ + virtual std::shared_ptr GetProcessInfo() const = 0; + + /** + * @brief Obtains information about the current application. The returned application information includes basic + * information such as the application name and application permissions. + * + * @return Returns the ApplicationInfo for the current application. + */ + virtual std::shared_ptr GetApplicationInfo() const = 0; + + /** + * @brief Obtains the Context object of the application. + * + * @return Returns the Context object of the application. + */ + virtual std::shared_ptr GetApplicationContext() const = 0; + + /** + * @brief Obtains the path of the package containing the current ability. The returned path contains the resources, + * source code, and configuration files of a module. + * + * @return Returns the path of the package file. + */ + virtual std::string GetBundleCodePath() = 0; + + /** + * @brief Obtains information about the current ability. + * The returned information includes the class name, bundle name, and other information about the current ability. + * + * @return Returns the AbilityInfo object for the current ability. + */ + virtual const std::shared_ptr GetAbilityInfo() = 0; + + /** + * @brief Obtains the Context object of the application. + * + * @return Returns the Context object of the application. + */ + virtual std::shared_ptr GetContext() = 0; + + /** + * @brief Obtains an IBundleMgr instance. + * You can use this instance to obtain information about the application bundle. + * + * @return Returns an IBundleMgr instance. + */ + virtual sptr GetBundleManager() const = 0; + + /** + * @brief Obtains a resource manager. + * + * @return Returns a ResourceManager object. + */ + virtual std::shared_ptr GetResourceManager() const = 0; + + /** + * @brief Deletes the specified private file associated with the application. + * + * @param fileName Indicates the name of the file to delete. The file name cannot contain path separators. + * + * @return Returns true if the file is deleted successfully; returns false otherwise. + */ + virtual bool DeleteFile(const std::string &fileName) = 0; + + /** + * @brief Destroys another ability that uses the AbilityInfo.AbilityType.SERVICE template. + * The current ability using either the AbilityInfo.AbilityType.SERVICE or AbilityInfo.AbilityType.PAGE + * template can call this method to destroy another ability that uses the AbilityInfo.AbilityType.SERVICE + * template. The current ability itself can be destroyed by calling the terminateAbility() method. + * + * @param want Indicates the Want containing information about the ability to destroy. + * + * @return Returns true if the ability is destroyed successfully; returns false otherwise. + */ + virtual bool StopAbility(const AAFwk::Want &want) = 0; + + /** + * @brief Obtains the application-specific cache directory on the device's internal storage. The system + * automatically deletes files from the cache directory if disk space is required elsewhere on the device. + * Older files are always deleted first. + * + * @return Returns the application-specific cache directory. + */ + virtual std::string GetCacheDir() = 0; + + /** + * @brief Obtains the application-specific code-cache directory on the device's internal storage. + * The system will delete any files stored in this location both when your specific application is upgraded, + * and when the entire platform is upgraded. + * + * @return Returns the application-specific code-cache directory. + */ + virtual std::string GetCodeCacheDir() = 0; + + /** + * @brief Obtains the local database path. + * If the local database path does not exist, the system creates one and returns the created path. + * + * @return Returns the local database file. + */ + virtual std::string GetDatabaseDir() = 0; + + /** + * @brief Obtains the absolute path where all private data files of this application are stored. + * + * @return Returns the absolute path storing all private data files of this application. + */ + virtual std::string GetDataDir() = 0; + + /** + * @brief Obtains the directory for storing custom data files of the application. + * You can use the returned File object to create and access files in this directory. The files + * can be accessible only by the current application. + * + * @param name Indicates the name of the directory to retrieve. This directory is created as part + * of your application data. + * @param mode Indicates the file operating mode. The value can be 0 or a combination of MODE_PRIVATE. + * + * @return Returns a File object for the requested directory. + */ + virtual std::string GetDir(const std::string &name, int mode) = 0; + + /** + * @brief Obtains the absolute path to the application-specific cache directory + * on the primary external or shared storage device. + * + * @return Returns the absolute path to the application-specific cache directory on the external or + * shared storage device; returns null if the external or shared storage device is temporarily unavailable. + */ + virtual std::string GetExternalCacheDir() = 0; + + /** + * @brief Obtains the absolute path to the directory for storing files for the application on the + * primary external or shared storage device. + * + * @param type Indicates the type of the file directory to return + * + * @return Returns the absolute path to the application file directory on the external or shared storage + * device; returns null if the external or shared storage device is temporarily unavailable. + */ + virtual std::string GetExternalFilesDir(std::string &type) = 0; + + /** + * @brief Obtains the directory for storing files for the application on the device's internal storage. + * + * @return Returns the application file directory. + */ + virtual std::string GetFilesDir() = 0; + + /** + * @brief Obtains the absolute path which app created and will be excluded from automatic backup to remote storage. + * The returned path maybe changed if the application is moved to an adopted storage device. + * + * @return The path of the directory holding application files that will not be automatically backed up to remote + * storage. + */ + virtual std::string GetNoBackupFilesDir() = 0; + + /** + * @brief Checks whether the calling process for inter-process communication has the given permission. + * The calling process is not the current process. + * + * @param permission Indicates the permission to check. This parameter cannot be null. + * + * @return Returns 0 (IBundleManager.PERMISSION_GRANTED) if the calling process has the permission; + * returns -1 (IBundleManager.PERMISSION_DENIED) otherwise. + */ + virtual int VerifyCallingPermission(const std::string &permission) = 0; + + /** + * @brief Checks whether the current process has the given permission. + * You need to call requestPermissionsFromUser(java.lang.std::string[],int) to request a permission only + * if the current process does not have the specific permission. + * + * @param permission Indicates the permission to check. This parameter cannot be null. + * + * @return Returns 0 (IBundleManager.PERMISSION_GRANTED) if the current process has the permission; + * returns -1 (IBundleManager.PERMISSION_DENIED) otherwise. + */ + virtual int VerifySelfPermission(const std::string &permission) = 0; + + /** + * @brief Obtains the bundle name of the current ability. + * + * @return Returns the bundle name of the current ability. + */ + virtual std::string GetBundleName() = 0; + + /** + * @brief Obtains the path of the OHOS Ability Package (HAP} containing this ability. + * + * @return Returns the path of the HAP containing this ability. + */ + virtual std::string GetBundleResourcePath() = 0; + + /** + * @brief Starts a new ability. + * An ability using the AbilityInfo.AbilityType.SERVICE or AbilityInfo.AbilityType.PAGE template uses this method + * to start a specific ability. The system locates the target ability from installed abilities based on the value + * of the want parameter and then starts it. You can specify the ability to start using the want parameter. + * + * @param want Indicates the Want containing information about the target ability to start. + * + * @param requestCode Indicates the request code returned after the ability using the AbilityInfo.AbilityType.PAGE + * template is started. You can define the request code to identify the results returned by abilities. The value + * ranges from 0 to 65535. This parameter takes effect only on abilities using the AbilityInfo.AbilityType.PAGE + * template. + * + */ + virtual void StartAbility(const AAFwk::Want &want, int requestCode) = 0; + + /** + * @brief Remove permissions for all users who have access to specific permissions + * + * @param permission Indicates the permission to unauth. This parameter cannot be null. + * @param uri Indicates the URI to unauth. This parameter cannot be null. + * @param uid Indicates the UID of the unauth to check. + * + */ + virtual void UnauthUriPermission(const std::string &permission, const Uri &uri, int uid) = 0; + + /** + * @brief Obtains an ability manager. + * The ability manager provides information about running processes and memory usage of an application. + * + * @return Returns an IAbilityManager instance. + */ + virtual sptr GetAbilityManager() = 0; + + /** + * @brief Obtains the type of this application. + * + * @return Returns system if this application is a system application; + * returns normal if it is released in OHOS AppGallery; + * returns other if it is released by a third-party vendor; + * returns an empty string if the query fails. + */ + virtual std::string GetAppType() = 0; + + /** + * @brief Destroys another ability you had previously started by calling Ability.startAbilityForResult + * (ohos.aafwk.content.Want, int, ohos.aafwk.ability.startsetting.AbilityStartSetting) with the same requestCode + * passed. + * + * @param requestCode Indicates the request code passed for starting the ability. + * + */ + virtual void TerminateAbility(int requestCode) = 0; + + /** + * @brief Destroys the current ability. + * + */ + virtual void TerminateAbility() = 0; + + /** + * @brief Confirms with the permission management module to check whether a request prompt is required for granting + * a certain permission. You need to call the current method to check whether a prompt is required before calling + * requestPermissionsFromUser(java.lang.String[],int) to request a permission. If a prompt is not required, + * permission request will not be initiated. + * + * @param requestCode Indicates the permission to be queried. This parameter cannot be null. + * + * @return Returns true if the current application does not have the permission and the user does not turn off + * further requests; returns false if the current application already has the permission, the permission is rejected + * by the system, or the permission is denied by the user and the user has turned off further requests. + */ + virtual bool CanRequestPermission(const std::string &permission) = 0; + + /** + * @brief When there is a remote call to check whether the remote has permission, otherwise check whether it has + * permission + * + * @param permissions Indicates the list of permissions to be requested. This parameter cannot be null. + * @return Returns 0 (IBundleManager.PERMISSION_GRANTED) if the current process has the permission; + * returns -1 (IBundleManager.PERMISSION_DENIED) otherwise. + */ + virtual int VerifyCallingOrSelfPermission(const std::string &permission) = 0; + + /** + * @brief Query whether the application of the specified PID and UID has been granted a certain permission + * + * @param permissions Indicates the list of permissions to be requested. This parameter cannot be null. + * @param pid Process id + * @param uid + * @return Returns 0 (IBundleManager.PERMISSION_GRANTED) if the current process has the permission; + * returns -1 (IBundleManager.PERMISSION_DENIED) otherwise. + */ + virtual int VerifyPermission(const std::string &permission, int pid, int uid) = 0; + + /** + * @brief Obtains the distributed file path. + * If the distributed file path does not exist, the system creates one and returns the created path. This method is + * applicable only to the context of an ability rather than that of an application. + * + * @return Returns the distributed file. + */ + virtual std::string GetDistributedDir() = 0; + + /** + * @brief Sets the pattern of this Context based on the specified pattern ID. + * + * @param patternId Indicates the resource ID of the pattern to set. + */ + virtual void SetPattern(int patternId) = 0; + + /** + * @brief Obtains the Context object of this ability. + * + * @return Returns the Context object of this ability. + */ + virtual std::shared_ptr GetAbilityPackageContext() = 0; + + /** + * @brief Obtains the HapModuleInfo object of the application. + * + * @return Returns the HapModuleInfo object of the application. + */ + virtual std::shared_ptr GetHapModuleInfo() = 0; + + /** + * @brief Obtains the name of the current process. + * + * @return Returns the current process name. + */ + virtual std::string GetProcessName() = 0; + + /** + * @brief Obtains the bundle name of the ability that called the current ability. + * You can use the obtained bundle name to check whether the calling ability is allowed to receive the data you will + * send. If you did not use Ability.startAbilityForResult(ohos.aafwk.content.Want, int, + * ohos.aafwk.ability.startsetting.AbilityStartSetting) to start the calling ability, null is returned. + * + * @return Returns the bundle name of the calling ability; returns null if no calling ability is available. + */ + virtual std::string GetCallingBundle() = 0; + + /** + * @brief Requests certain permissions from the system. + * This method is called for permission request. This is an asynchronous method. When it is executed, + * the Ability.onRequestPermissionsFromUserResult(int, String[], int[]) method will be called back. + * + * @param permissions Indicates the list of permissions to be requested. This parameter cannot be null. + * @param requestCode Indicates the request code to be passed to the Ability.onRequestPermissionsFromUserResult(int, + * String[], int[]) callback method. This code cannot be a negative number. + * + */ + virtual void RequestPermissionsFromUser(std::vector &permissions, int requestCode) = 0; + + /** + * @brief Starts a new ability with special ability start setting. + * + * @param want Indicates the Want containing information about the target ability to start. + * @param requestCode Indicates the request code returned after the ability is started. You can define the request + * code to identify the results returned by abilities. The value ranges from 0 to 65535. + * @param abilityStartSetting Indicates the special start setting used in starting ability. + * + */ + virtual void StartAbility(const Want &want, int requestCode, const AbilityStartSetting &abilityStartSetting) = 0; + + /** + * @brief Connects the current ability to an ability using the AbilityInfo.AbilityType.SERVICE template. + * + * @param want Indicates the want containing information about the ability to connect + * + * @param conn Indicates the callback object when the target ability is connected. + * + * @return True means success and false means failure + */ + virtual bool ConnectAbility(const Want &want, const sptr &conn) = 0; + + /** + * @brief Disconnects the current ability from an ability + * + * @param conn Indicates the IAbilityConnection callback object passed by connectAbility after the connection + * is set up. The IAbilityConnection object uniquely identifies a connection between two abilities. + */ + virtual void DisconnectAbility(const sptr &conn) = 0; + + /** + * @brief Obtains information about the caller of this ability. + * + * @return Returns the caller information. + */ + virtual Uri GetCaller() = 0; + + friend DataAbilityHelper; + +protected: + virtual sptr GetToken() = 0; +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_OHOS_CONTEXT_H diff --git a/kits/appkit/native/app/include/context_container.h b/kits/appkit/native/app/include/context_container.h new file mode 100755 index 000000000..3ef1cff6b --- /dev/null +++ b/kits/appkit/native/app/include/context_container.h @@ -0,0 +1,372 @@ +/* + * 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_CONTEXT_CONTAINER_H +#define FOUNDATION_APPEXECFWK_OHOS_CONTEXT_CONTAINER_H + +#include "context_deal.h" + +namespace OHOS { +namespace AppExecFwk { + +class ContextContainer : public Context { +public: + ContextContainer() = default; + virtual ~ContextContainer() = default; + + /** + * Attaches a Context object to the current ability. + * Generally, this method is called after Ability is loaded to provide the application context for the current + * ability. + * + * @param base Indicates a Context object. + */ + void AttachBaseContext(const std::shared_ptr &base); + + /** + * Called when getting the ProcessInfo + * + * @return ProcessInfo + */ + std::shared_ptr GetProcessInfo() const override; + + /** + * @brief Obtains information about the current application. The returned application information includes basic + * information such as the application name and application permissions. + * + * @return Returns the ApplicationInfo for the current application. + */ + std::shared_ptr GetApplicationInfo() const override; + + /** + * @brief Obtains the Context object of the application. + * + * @return Returns the Context object of the application. + */ + std::shared_ptr GetApplicationContext() const override; + + /** + * @brief Obtains the path of the package containing the current ability. The returned path contains the resources, + * source code, and configuration files of a module. + * + * @return Returns the path of the package file. + */ + virtual std::string GetBundleCodePath() override; + + /** + * @brief Obtains information about the current ability. + * The returned information includes the class name, bundle name, and other information about the current ability. + * + * @return Returns the AbilityInfo object for the current ability. + */ + virtual const std::shared_ptr GetAbilityInfo() override; + + /** + * @brief Obtains the Context object of the application. + * + * @return Returns the Context object of the application. + */ + std::shared_ptr GetContext() override; + + /** + * @brief Obtains an IBundleMgr instance. + * You can use this instance to obtain information about the application bundle. + * + * @return Returns an IBundleMgr instance. + */ + sptr GetBundleManager() const override; + + /** + * @brief Obtains a resource manager. + * + * @return Returns a ResourceManager object. + */ + std::shared_ptr GetResourceManager() const override; + + /** + * @brief Deletes the specified private file associated with the application. + * + * @param fileName Indicates the name of the file to delete. The file name cannot contain path separators. + * + * @return Returns true if the file is deleted successfully; returns false otherwise. + */ + bool DeleteFile(const std::string &fileName) override; + + /** + * @brief Obtains the application-specific cache directory on the device's internal storage. The system + * automatically deletes files from the cache directory if disk space is required elsewhere on the device. + * Older files are always deleted first. + * + * @return Returns the application-specific cache directory. + */ + std::string GetCacheDir() override; + + /** + * @brief Obtains the application-specific code-cache directory on the device's internal storage. + * The system will delete any files stored in this location both when your specific application is upgraded, + * and when the entire platform is upgraded. + * + * @return Returns the application-specific code-cache directory. + */ + std::string GetCodeCacheDir() override; + + /** + * @brief Obtains the local database path. + * If the local database path does not exist, the system creates one and returns the created path. + * + * @return Returns the local database file. + */ + std::string GetDatabaseDir() override; + + /** + * @brief Obtains the absolute path where all private data files of this application are stored. + * + * @return Returns the absolute path storing all private data files of this application. + */ + std::string GetDataDir() override; + + /** + * @brief Obtains the directory for storing custom data files of the application. + * You can use the returned File object to create and access files in this directory. The files + * can be accessible only by the current application. + * + * @param name Indicates the name of the directory to retrieve. This directory is created as part + * of your application data. + * @param mode Indicates the file operating mode. The value can be 0 or a combination of MODE_PRIVATE. + * + * @return Returns a File object for the requested directory. + */ + std::string GetDir(const std::string &name, int mode) override; + + /** + * @brief Obtains the absolute path to the application-specific cache directory + * on the primary external or shared storage device. + * + * @return Returns the absolute path to the application-specific cache directory on the external or + * shared storage device; returns null if the external or shared storage device is temporarily unavailable. + */ + std::string GetExternalCacheDir() override; + + /** + * @brief Obtains the absolute path to the directory for storing files for the application on the + * primary external or shared storage device. + * + * @param type Indicates the type of the file directory to return + * + * @return Returns the absolute path to the application file directory on the external or shared storage + * device; returns null if the external or shared storage device is temporarily unavailable. + */ + std::string GetExternalFilesDir(std::string &type) override; + + /** + * @brief Obtains the directory for storing files for the application on the device's internal storage. + * + * @return Returns the application file directory. + */ + std::string GetFilesDir() override; + + /** + * @brief Obtains the absolute path which app created and will be excluded from automatic backup to remote storage. + * The returned path maybe changed if the application is moved to an adopted storage device. + * + * @return The path of the directory holding application files that will not be automatically backed up to remote + * storage. + */ + std::string GetNoBackupFilesDir() override; + + /** + * @brief Checks whether the calling process for inter-process communication has the given permission. + * The calling process is not the current process. + * + * @param permission Indicates the permission to check. This parameter cannot be null. + * + * @return Returns 0 (IBundleManager.PERMISSION_GRANTED) if the calling process has the permission; + * returns -1 (IBundleManager.PERMISSION_DENIED) otherwise. + */ + int VerifyCallingPermission(const std::string &permission) override; + + /** + * @brief Checks whether the current process has the given permission. + * You need to call requestPermissionsFromUser(java.lang.std::string[],int) to request a permission only + * if the current process does not have the specific permission. + * + * @param permission Indicates the permission to check. This parameter cannot be null. + * + * @return Returns 0 (IBundleManager.PERMISSION_GRANTED) if the current process has the permission; + * returns -1 (IBundleManager.PERMISSION_DENIED) otherwise. + */ + int VerifySelfPermission(const std::string &permission) override; + + /** + * @brief Obtains the bundle name of the current ability. + * + * @return Returns the bundle name of the current ability. + */ + std::string GetBundleName() override; + + /** + * @brief Obtains the path of the OHOS Ability Package (HAP} containing this ability. + * + * @return Returns the path of the HAP containing this ability. + */ + std::string GetBundleResourcePath() override; + + /** + * @brief Remove permissions for all users who have access to specific permissions + * + * @param permission Indicates the permission to unauth. This parameter cannot be null. + * @param uri Indicates the URI to unauth. This parameter cannot be null. + * @param uid Indicates the UID of the unauth to check. + * + */ + void UnauthUriPermission(const std::string &permission, const Uri &uri, int uid) override; + + /** + * @brief Obtains an ability manager. + * The ability manager provides information about running processes and memory usage of an application. + * + * @return Returns an IAbilityManager instance. + */ + sptr GetAbilityManager() override; + + /** + * @brief Obtains the type of this application. + * + * @return Returns system if this application is a system application; + * returns normal if it is released in OHOS AppGallery; + * returns other if it is released by a third-party vendor; + * returns an empty string if the query fails. + */ + std::string GetAppType() override; + + /** + * @brief Confirms with the permission management module to check whether a request prompt is required for granting + * a certain permission. You need to call the current method to check whether a prompt is required before calling + * requestPermissionsFromUser(java.lang.String[],int) to request a permission. If a prompt is not required, + * permission request will not be initiated. + * + * @param requestCode Indicates the permission to be queried. This parameter cannot be null. + * + * @return Returns true if the current application does not have the permission and the user does not turn off + * further requests; returns false if the current application already has the permission, the permission is rejected + * by the system, or the permission is denied by the user and the user has turned off further requests. + */ + bool CanRequestPermission(const std::string &permission) override; + + /** + * @brief When there is a remote call to check whether the remote has permission, otherwise check whether it has + * permission + * + * @param permissions Indicates the list of permissions to be requested. This parameter cannot be null. + * @return Returns 0 (IBundleManager.PERMISSION_GRANTED) if the current process has the permission; + * returns -1 (IBundleManager.PERMISSION_DENIED) otherwise. + */ + int VerifyCallingOrSelfPermission(const std::string &permission) override; + + /** + * @brief Query whether the application of the specified PID and UID has been granted a certain permission + * + * @param permissions Indicates the list of permissions to be requested. This parameter cannot be null. + * @param pid Process id + * @param uid + * @return Returns 0 (IBundleManager.PERMISSION_GRANTED) if the current process has the permission; + * returns -1 (IBundleManager.PERMISSION_DENIED) otherwise. + */ + int VerifyPermission(const std::string &permission, int pid, int uid) override; + + /** + * @brief Obtains the distributed file path. + * If the distributed file path does not exist, the system creates one and returns the created path. This method is + * applicable only to the context of an ability rather than that of an application. + * + * @return Returns the distributed file. + */ + std::string GetDistributedDir() override; + + /** + * @brief Sets the pattern of this Context based on the specified pattern ID. + * + * @param patternId Indicates the resource ID of the pattern to set. + */ + void SetPattern(int patternId) override; + + /** + * @brief Obtains the Context object of this ability. + * + * @return Returns the Context object of this ability. + */ + std::shared_ptr GetAbilityPackageContext() override; + + /** + * @brief Obtains the HapModuleInfo object of the application. + * + * @return Returns the HapModuleInfo object of the application. + */ + std::shared_ptr GetHapModuleInfo() override; + + /** + * @brief Obtains the name of the current process. + * + * @return Returns the current process name. + */ + std::string GetProcessName() override; + + /** + * @brief Requests certain permissions from the system. + * This method is called for permission request. This is an asynchronous method. When it is executed, + * the Ability.onRequestPermissionsFromUserResult(int, String[], int[]) method will be called back. + * + * @param permissions Indicates the list of permissions to be requested. This parameter cannot be null. + * @param requestCode Indicates the request code to be passed to the Ability.onRequestPermissionsFromUserResult(int, + * String[], int[]) callback method. This code cannot be a negative number. + * + */ + void RequestPermissionsFromUser(std::vector &permissions, int requestCode) override; + + /** + * @brief Creates a Context object for an application with the given bundle name. + * + * @param bundleName Indicates the bundle name of the application. + * + * @param flag Indicates the flag for creating a Context object. It can be 0, any of + * the following values, or any combination of the following values: CONTEXT_IGNORE_SECURITY, + * CONTEXT_INCLUDE_CODE, and CONTEXT_RESTRICTED. The value 0 indicates that there is no restriction + * on creating contexts for applications. + * + * @return Returns a Context object created for the specified application. + */ + std::shared_ptr CreateBundleContext(std::string bundleName, int flag); + + /** + * @brief Obtains information about the caller of this ability. + * + * @return Returns the caller information. + */ + Uri GetCaller() override; + + /** + * @brief InitResourceManager + * + * @param bundleInfo BundleInfo + */ + void InitResourceManager(BundleInfo &bundleInfo, std::shared_ptr &deal); + +private: + std::shared_ptr baseContext_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_OHOS_CONTEXT_CONTAINER_H diff --git a/kits/appkit/native/app/include/context_deal.h b/kits/appkit/native/app/include/context_deal.h new file mode 100755 index 000000000..ddd133894 --- /dev/null +++ b/kits/appkit/native/app/include/context_deal.h @@ -0,0 +1,507 @@ +/* + * 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_CONTEXT_DEAL_H +#define FOUNDATION_APPEXECFWK_OHOS_CONTEXT_DEAL_H + +#include "context.h" +#include "profile.h" + +namespace OHOS { +namespace AppExecFwk { + +class ContextDeal : public Context, public std::enable_shared_from_this { +public: + ContextDeal() = default; + virtual ~ContextDeal() = default; + + /** + * Called when getting the ProcessInfo + * + * @return ProcessInfo + */ + std::shared_ptr GetProcessInfo() const override; + + /** + * Called when setting the ProcessInfo + * + * @param info ProcessInfo instance + */ + void SetProcessInfo(const std::shared_ptr &info); + + /** + * @brief Obtains information about the current application. The returned application information includes basic + * information such as the application name and application permissions. + * + * @return Returns the ApplicationInfo for the current application. + */ + std::shared_ptr GetApplicationInfo() const override; + + /** + * @brief Set ApplicationInfo + * + * @param info ApplicationInfo instance. + */ + void SetApplicationInfo(const std::shared_ptr &info); + + /** + * @brief Obtains the Context object of the application. + * + * @return Returns the Context object of the application. + */ + std::shared_ptr GetApplicationContext() const override; + + /** + * @brief Set ApplicationContext + * + * @param context ApplicationContext instance. + */ + void SetApplicationContext(const std::shared_ptr &context); + + /** + * @brief Obtains the path of the package containing the current ability. The returned path contains the resources, + * source code, and configuration files of a module. + * + * @return Returns the path of the package file. + */ + std::string GetBundleCodePath() override; + + /** + * @brief SetBundleCodePath + * + * @param Returns string path + */ + void SetBundleCodePath(std::string &path); + + /** + * @brief Obtains information about the current ability. + * The returned information includes the class name, bundle name, and other information about the current ability. + * + * @return Returns the AbilityInfo object for the current ability. + */ + const std::shared_ptr GetAbilityInfo() override; + + /** + * @brief Set AbilityInfo + * + * @param info AbilityInfo instance. + */ + void SetAbilityInfo(const std::shared_ptr &info); + + /** + * @brief Obtains the Context object of the ability. + * + * @return Returns the Context object of the ability. + */ + std::shared_ptr GetContext() override; + + /** + * @brief Set Ability context + * + * @param context Ability object + */ + void SetContext(const std::shared_ptr &context); + + /** + * @brief Obtains an IBundleMgr instance. + * You can use this instance to obtain information about the application bundle. + * + * @return Returns an IBundleMgr instance. + */ + sptr GetBundleManager() const override; + + /** + * @brief Obtains a resource manager. + * + * @return Returns a ResourceManager object. + */ + std::shared_ptr GetResourceManager() const override; + + /** + * @brief Set Profile instance. + * + * @param Profile instance. + */ + void SetProfile(const std::shared_ptr &profile); + + /** + * @brief Obtains an Profile instance. + * + * @return Returns an Profile instance. + */ + std::shared_ptr GetProfile() const; + + /** + * @brief Deletes the specified private file associated with the application. + * + * @param fileName Indicates the name of the file to delete. The file name cannot contain path separators. + * + * @return Returns true if the file is deleted successfully; returns false otherwise. + */ + bool DeleteFile(const std::string &fileName) override; + + /** + * @brief Destroys another ability that uses the AbilityInfo.AbilityType.SERVICE template. + * The current ability using either the AbilityInfo.AbilityType.SERVICE or AbilityInfo.AbilityType.PAGE + * template can call this method to destroy another ability that uses the AbilityInfo.AbilityType.SERVICE + * template. The current ability itself can be destroyed by calling the terminateAbility() method. + * + * @param want Indicates the Want containing information about the ability to destroy. + * + * @return Returns true if the ability is destroyed successfully; returns false otherwise. + */ + bool StopAbility(const AAFwk::Want &want) override; + + /** + * @brief Obtains the application-specific cache directory on the device's internal storage. The system + * automatically deletes files from the cache directory if disk space is required elsewhere on the device. + * Older files are always deleted first. + * + * @return Returns the application-specific cache directory. + */ + std::string GetCacheDir() override; + + /** + * @brief Obtains the application-specific code-cache directory on the device's internal storage. + * The system will delete any files stored in this location both when your specific application is upgraded, + * and when the entire platform is upgraded. + * + * @return Returns the application-specific code-cache directory. + */ + std::string GetCodeCacheDir() override; + + /** + * @brief Obtains the local database path. + * If the local database path does not exist, the system creates one and returns the created path. + * + * @return Returns the local database file. + */ + std::string GetDatabaseDir() override; + + /** + * @brief Obtains the absolute path where all private data files of this application are stored. + * + * @return Returns the absolute path storing all private data files of this application. + */ + std::string GetDataDir() override; + + /** + * @brief Obtains the directory for storing custom data files of the application. + * You can use the returned File object to create and access files in this directory. The files + * can be accessible only by the current application. + * + * @param name Indicates the name of the directory to retrieve. This directory is created as part + * of your application data. + * @param mode Indicates the file operating mode. The value can be 0 or a combination of MODE_PRIVATE. + * + * @return Returns a File object for the requested directory. + */ + std::string GetDir(const std::string &name, int mode) override; + + /** + * @brief Obtains the absolute path to the application-specific cache directory + * on the primary external or shared storage device. + * + * @return Returns the absolute path to the application-specific cache directory on the external or + * shared storage device; returns null if the external or shared storage device is temporarily unavailable. + */ + std::string GetExternalCacheDir() override; + + /** + * @brief Obtains the absolute path to the directory for storing files for the application on the + * primary external or shared storage device. + * + * @param type Indicates the type of the file directory to return + * + * @return Returns the absolute path to the application file directory on the external or shared storage + * device; returns null if the external or shared storage device is temporarily unavailable. + */ + std::string GetExternalFilesDir(std::string &type) override; + + /** + * @brief Obtains the directory for storing files for the application on the device's internal storage. + * + * @return Returns the application file directory. + */ + std::string GetFilesDir() override; + + /** + * @brief Obtains the absolute path which app created and will be excluded from automatic backup to remote storage. + * The returned path maybe changed if the application is moved to an adopted storage device. + * + * @return The path of the directory holding application files that will not be automatically backed up to remote + * storage. + */ + std::string GetNoBackupFilesDir() override; + + /** + * @brief Checks whether the calling process for inter-process communication has the given permission. + * The calling process is not the current process. + * + * @param permission Indicates the permission to check. This parameter cannot be null. + * + * @return Returns 0 (IBundleManager.PERMISSION_GRANTED) if the calling process has the permission; + * returns -1 (IBundleManager.PERMISSION_DENIED) otherwise. + */ + int VerifyCallingPermission(const std::string &permission) override; + + /** + * @brief Checks whether the current process has the given permission. + * You need to call requestPermissionsFromUser(java.lang.std::string[],int) to request a permission only + * if the current process does not have the specific permission. + * + * @param permission Indicates the permission to check. This parameter cannot be null. + * + * @return Returns 0 (IBundleManager.PERMISSION_GRANTED) if the current process has the permission; + * returns -1 (IBundleManager.PERMISSION_DENIED) otherwise. + */ + int VerifySelfPermission(const std::string &permission) override; + + /** + * @brief Obtains the bundle name of the current ability. + * + * @return Returns the bundle name of the current ability. + */ + std::string GetBundleName() override; + + /** + * @brief Obtains the path of the OHOS Ability Package (HAP} containing this ability. + * + * @return Returns the path of the HAP containing this ability. + */ + std::string GetBundleResourcePath() override; + + /** + * @brief Starts a new ability. + * An ability using the AbilityInfo.AbilityType.SERVICE or AbilityInfo.AbilityType.PAGE template uses this method + * to start a specific ability. The system locates the target ability from installed abilities based on the value + * of the want parameter and then starts it. You can specify the ability to start using the want parameter. + * + * @param want Indicates the Want containing information about the target ability to start. + * + * @param requestCode Indicates the request code returned after the ability using the AbilityInfo.AbilityType.PAGE + * template is started. You can define the request code to identify the results returned by abilities. The value + * ranges from 0 to 65535. This parameter takes effect only on abilities using the AbilityInfo.AbilityType.PAGE + * template. + * + */ + void StartAbility(const AAFwk::Want &want, int requestCode) override; + + /** + * @brief Remove permissions for all users who have access to specific permissions + * + * @param permission Indicates the permission to unauth. This parameter cannot be null. + * @param uri Indicates the URI to unauth. This parameter cannot be null. + * @param uid Indicates the UID of the unauth to check. + * + */ + void UnauthUriPermission(const std::string &permission, const Uri &uri, int uid) override; + + /** + * @brief Obtains an ability manager. + * The ability manager provides information about running processes and memory usage of an application. + * + * @return Returns an IAbilityManager instance. + */ + sptr GetAbilityManager() override; + + /** + * @brief Obtains the type of this application. + * + * @return Returns system if this application is a system application; + * returns normal if it is released in OHOS AppGallery; + * returns other if it is released by a third-party vendor; + * returns an empty string if the query fails. + */ + std::string GetAppType() override; + + /** + * @brief Destroys another ability you had previously started by calling Ability.startAbilityForResult + * (ohos.aafwk.content.Want, int, ohos.aafwk.ability.startsetting.AbilityStartSetting) with the same requestCode + * passed. + * + * @param requestCode Indicates the request code passed for starting the ability. + * + */ + void TerminateAbility(int requestCode) override; + + /** + * @brief Confirms with the permission management module to check whether a request prompt is required for granting + * a certain permission. You need to call the current method to check whether a prompt is required before calling + * requestPermissionsFromUser(java.lang.String[],int) to request a permission. If a prompt is not required, + * permission request will not be initiated. + * + * @param requestCode Indicates the permission to be queried. This parameter cannot be null. + * + * @return Returns true if the current application does not have the permission and the user does not turn off + * further requests; returns false if the current application already has the permission, the permission is rejected + * by the system, or the permission is denied by the user and the user has turned off further requests. + */ + bool CanRequestPermission(const std::string &permission) override; + + /** + * @brief When there is a remote call to check whether the remote has permission, otherwise check whether it has + * permission + * + * @param permissions Indicates the list of permissions to be requested. This parameter cannot be null. + * @return Returns 0 (IBundleManager.PERMISSION_GRANTED) if the current process has the permission; + * returns -1 (IBundleManager.PERMISSION_DENIED) otherwise. + */ + virtual int VerifyCallingOrSelfPermission(const std::string &permission) override; + + /** + * @brief Query whether the application of the specified PID and UID has been granted a certain permission + * + * @param permissions Indicates the list of permissions to be requested. This parameter cannot be null. + * @param pid Process id + * @param uid + * @return Returns 0 (IBundleManager.PERMISSION_GRANTED) if the current process has the permission; + * returns -1 (IBundleManager.PERMISSION_DENIED) otherwise. + */ + virtual int VerifyPermission(const std::string &permission, int pid, int uid) override; + + /** + * @brief Obtains the distributed file path. + * If the distributed file path does not exist, the system creates one and returns the created path. This method is + * applicable only to the context of an ability rather than that of an application. + * + * @return Returns the distributed file. + */ + std::string GetDistributedDir() override; + + /** + * @brief Sets the pattern of this Context based on the specified pattern ID. + * + * @param patternId Indicates the resource ID of the pattern to set. + */ + void SetPattern(int patternId) override; + + /** + * @brief Obtains the Context object of this ability. + * + * @return Returns the Context object of this ability. + */ + std::shared_ptr GetAbilityPackageContext() override; + + /** + * @brief Obtains the HapModuleInfo object of the application. + * + * @return Returns the HapModuleInfo object of the application. + */ + std::shared_ptr GetHapModuleInfo() override; + + /** + * @brief Obtains the name of the current process. + * + * @return Returns the current process name. + */ + std::string GetProcessName() override; + + /** + * @brief Obtains the bundle name of the ability that called the current ability. + * You can use the obtained bundle name to check whether the calling ability is allowed to receive the data you will + * send. If you did not use Ability.startAbilityForResult(ohos.aafwk.content.Want, int, + * ohos.aafwk.ability.startsetting.AbilityStartSetting) to start the calling ability, null is returned. + * + * @return Returns the bundle name of the calling ability; returns null if no calling ability is available. + */ + std::string GetCallingBundle() override; + + /** + * @brief Requests certain permissions from the system. + * This method is called for permission request. This is an asynchronous method. When it is executed, + * the Ability.onRequestPermissionsFromUserResult(int, String[], int[]) method will be called back. + * + * @param permissions Indicates the list of permissions to be requested. This parameter cannot be null. + * @param requestCode Indicates the request code to be passed to the Ability.onRequestPermissionsFromUserResult(int, + * String[], int[]) callback method. This code cannot be a negative number. + * + */ + void RequestPermissionsFromUser(std::vector &permissions, int requestCode) override; + + /** + * @brief Starts a new ability with special ability start setting. + * + * @param want Indicates the Want containing information about the target ability to start. + * @param requestCode Indicates the request code returned after the ability is started. You can define the request + * code to identify the results returned by abilities. The value ranges from 0 to 65535. + * @param abilityStartSetting Indicates the special start setting used in starting ability. + * + */ + void StartAbility(const Want &want, int requestCode, const AbilityStartSetting &abilityStartSetting) override; + + /** + * @brief Destroys the current ability. + * + */ + void TerminateAbility() override; + + /** + * @brief Connects the current ability to an ability using the AbilityInfo.AbilityType.SERVICE template. + * + * @param want Indicates the want containing information about the ability to connect + * + * @param conn Indicates the callback object when the target ability is connected. + * + * @return True means success and false means failure + */ + bool ConnectAbility(const Want &want, const sptr &conn) override; + + /** + * @brief Disconnects the current ability from an ability + * + * @param conn Indicates the IAbilityConnection callback object passed by connectAbility after the connection + * is set up. The IAbilityConnection object uniquely identifies a connection between two abilities. + */ + void DisconnectAbility(const sptr &conn) override; + + /** + * @brief init the ResourceManager for ContextDeal. + * + * @param the ResourceManager has been inited. + * + */ + void initResourceManager(const std::shared_ptr &resourceManager); + + /** + * @brief Obtains information about the caller of this ability. + * + * @return Returns the caller information. + */ + Uri GetCaller() override; + + /** + * @brief SerUriString + */ + void SerUriString(const std::string &uri); + +protected: + sptr GetToken() override; + +private: + std::shared_ptr processInfo_ = nullptr; + std::shared_ptr applicationInfo_ = nullptr; + std::shared_ptr abilityInfo_ = nullptr; + std::shared_ptr profile_ = nullptr; + std::shared_ptr appContext_ = nullptr; + std::shared_ptr abilityContext_ = nullptr; + std::shared_ptr resourceManager_ = nullptr; + std::string path_; + std::string uriString_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_OHOS_CONTEXT_DEAL_H diff --git a/kits/appkit/native/app/include/dummy_hap_module_info.h b/kits/appkit/native/app/include/dummy_hap_module_info.h new file mode 100644 index 000000000..baefaf0e1 --- /dev/null +++ b/kits/appkit/native/app/include/dummy_hap_module_info.h @@ -0,0 +1,24 @@ +/* + * 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_HAPMODULEINFO_H +#define FOUNDATION_APPEXECFWK_OHOS_HAPMODULEINFO_H + +namespace OHOS { +namespace AppExecFwk { + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_OHOS_HAPMODULEINFO_H \ No newline at end of file diff --git a/kits/appkit/native/app/include/element_callback.h b/kits/appkit/native/app/include/element_callback.h new file mode 100644 index 000000000..50acc3693 --- /dev/null +++ b/kits/appkit/native/app/include/element_callback.h @@ -0,0 +1,48 @@ +/* + * 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_ELEMENTS_CALLBACK_H +#define FOUNDATION_APPEXECFWK_OHOS_ELEMENTS_CALLBACK_H + +#include "dummy_configuration.h" + +namespace OHOS { +namespace AppExecFwk { + +class ElementsCallback { +public: + ElementsCallback() = default; + virtual ~ElementsCallback() = default; + + /** + * + * Called when the system configuration of the device changes. + * + * @param config Indicates the new Configuration object. + * @param ability Indicates the new Ability object. + */ + virtual void OnConfigurationUpdated(const std::shared_ptr &ability, const Configuration &config) = 0; + + /** + * + * Will be called when the system has determined to trim the memory + * + * @param level Indicates the memory trim level, which shows the current memory usage status. + */ + virtual void OnMemoryLevel(int level) = 0; +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_OHOS_ELEMENTS_CALLBACK_H \ No newline at end of file diff --git a/kits/appkit/native/app/include/main_thread.h b/kits/appkit/native/app/include/main_thread.h new file mode 100644 index 000000000..21f43ad89 --- /dev/null +++ b/kits/appkit/native/app/include/main_thread.h @@ -0,0 +1,441 @@ +/* + * 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_MAIN_THREAD_H +#define FOUNDATION_APPEXECFWK_MAIN_THREAD_H + +#include +#include +#include "event_handler.h" +#include "inner_event.h" +#include "app_scheduler_host.h" +#include "app_mgr_interface.h" +#include "ability_record_mgr.h" +#include "application_impl.h" +#include "ohos/aafwk/base/ipc_singleton.h" +#define ABILITY_LIBRARY_LOADER + +namespace OHOS { +namespace AppExecFwk { +enum class MainThreadState { INIT, ATTACH, READY, RUNNING }; + +class AppMgrDeathRecipient : public IRemoteObject::DeathRecipient { +public: + /** + * + * @brief Notify the AppMgrDeathRecipient that the remote is dead. + * + * @param remote The remote which is dead. + */ + virtual void OnRemoteDied(const wptr &remote) override; + AppMgrDeathRecipient() = default; + ~AppMgrDeathRecipient() override = default; +}; + +class MainThread : public AppSchedulerHost { + DECLARE_DELAYED_IPCSINGLETON(MainThread); + +public: + /** + * + * @brief Get the current MainThreadState. + * + * @return Returns the current MainThreadState. + */ + MainThreadState GetMainThreadState() const; + + /** + * + * @brief Get the runner state of mainthread. + * + * @return Returns the runner state of mainthread. + */ + bool GetRunnerStarted() const; + + /** + * + * @brief Get the newThreadId. + * + * @return Returns the newThreadId. + */ + int GetNewThreadId(); + + /** + * + * @brief Get the application. + * + * @return Returns the application. + */ + std::shared_ptr GetApplication() const; + + /** + * + * @brief Get the applicationInfo. + * + * @return Returns the applicationInfo. + */ + std::shared_ptr GetApplicationInfo() const; + + /** + * + * @brief Get the applicationImpl. + * + * @return Returns the applicationImpl. + */ + std::shared_ptr GetApplicationImpl(); + + /** + * + * @brief Get the eventHandler of mainthread. + * + * @return Returns the eventHandler of mainthread. + */ + std::shared_ptr GetMainHandler() const; + + /** + * + * @brief Schedule the foreground lifecycle of application. + * + */ + void ScheduleForegroundApplication() override; + + /** + * + * @brief Schedule the background lifecycle of application. + * + */ + void ScheduleBackgroundApplication() override; + + /** + * + * @brief Schedule the terminate lifecycle of application. + * + */ + void ScheduleTerminateApplication() override; + + /** + * + * @brief Shrink the memory which used by application. + * + * @param level Indicates the memory trim level, which shows the current memory usage status. + */ + void ScheduleShrinkMemory(const int level) override; + + /** + * + * @brief Low the memory which used by application. + * + */ + void ScheduleLowMemory() override; + + /** + * + * @brief Launch the application. + * + * @param data The launchdata of the application witch launced. + * + */ + void ScheduleLaunchApplication(const AppLaunchData &data) override; + + /** + * + * @brief launch the application. + * + * @param info The launchdata of the application witch launced. + * @param token The launchdata of the application witch launced. + * + */ + void ScheduleLaunchAbility(const AbilityInfo &info, const sptr &token) override; + + /** + * + * @brief clean the ability by token. + * + * @param token The token belong to the ability which want to be cleaned. + * + */ + void ScheduleCleanAbility(const sptr &token) override; + + /** + * + * @brief send the new profile. + * + * @param profile The updated profile. + * + */ + void ScheduleProfileChanged(const Profile &profile) override; + + /** + * + * @brief send the new config to the application. + * + * @param config The updated config. + * + */ + void ScheduleConfigurationUpdated(const Configuration &config) override; + + /** + * + * @brief Starts the mainthread. + * + */ + static void Start(); + + /** + * + * @brief Schedule the application process exit safely. + * + */ + void ScheduleProcessSecurityExit() override; + +private: + /** + * + * @brief Terminate the application but don't notify ams. + * + */ + void HandleTerminateApplicationLocal(); + + /** + * + * @brief Schedule the application process exit safely. + * + */ + void HandleProcessSecurityExit(); + + /** + * + * @brief Clean the ability but don't notify ams. + * + * @param token The token which belongs to the ability launched. + * + */ + void HandleCleanAbilityLocal(const sptr &token); + + /** + * + * @brief Launch the application. + * + * @param appLaunchData The launchdata of the application witch launced. + * + */ + void HandleLaunchApplication(const AppLaunchData &appLaunchData); + + /** + * + * @brief Launch the ability. + * + * @param abilityRecord The abilityRecord which belongs to the ability launched. + * + */ + void HandleLaunchAbility(const std::shared_ptr &abilityRecord); + + /** + * + * @brief Clean the ability. + * + * @param token The token which belongs to the ability launched. + * + */ + void HandleCleanAbility(const sptr &token); + + /** + * + * @brief Foreground the application. + * + */ + void HandleForegroundApplication(); + + /** + * + * @brief Background the application. + * + */ + void HandleBackgroundApplication(); + + /** + * + * @brief Terminate the application. + * + */ + void HandleTerminateApplication(); + + /** + * + * @brief Shrink the memory which used by application. + * + * @param level Indicates the memory trim level, which shows the current memory usage status. + * + */ + void HandleShrinkMemory(const int level); + + /** + * + * @brief send the new config to the application. + * + * @param config The updated config. + * + */ + void HandleConfigurationUpdated(const Configuration &config); + + /** + * + * @brief remove the deathRecipient from appMgr. + * + */ + void RemoveAppMgrDeathRecipient(); + + /** + * + * @brief Attach the mainthread to the AppMgr. + * + */ + void Attach(); + + /** + * + * @brief Set the runner state of mainthread. + * + * @param runnerStart whether the runner is started. + */ + void SetRunnerStarted(bool runnerStart); + + /** + * + * @brief Connect the mainthread to the AppMgr. + * + */ + bool ConnectToAppMgr(); + + /** + * + * @brief Check whether the appLaunchData is legal. + * + * @param appLaunchData The appLaunchData should be checked. + * + * @return if the appLaunchData is legal, return true. else return false. + */ + bool CheckLaunchApplicationParam(const AppLaunchData &appLaunchData) const; + + /** + * + * @brief Check whether the record is legal. + * + * @param record The record should be checked. + * + * @return if the record is legal, return true. else return false. + */ + bool CheckAbilityItem(const std::shared_ptr &record) const; + + /** + * + * @brief Init the mainthread. + * + * @param runner the runner belong to the mainthread. + * + */ + void Init(const std::shared_ptr &runner); + + /** + * + * @brief Check whether the OHOSApplication is ready. + * + * @return if the OHOSApplication is ready, return true. else return false. + * + */ + bool IsApplicationReady() const; + class MainHandler : public EventHandler { + public: + MainHandler(const std::shared_ptr &runner, const sptr &thread); + virtual ~MainHandler() = default; + + /** + * + * @brief Process the event. + * + * @param event the event want to be processed. + * + */ + void ProcessEvent(const OHOS::AppExecFwk::InnerEvent::Pointer &event) override; + + private: + sptr mainThreadObj_ = nullptr; + }; + + bool isRunnerStarted_ = false; + int newThreadId_ = -1; + std::shared_ptr appProfile_ = nullptr; + std::shared_ptr applicationInfo_ = nullptr; + std::shared_ptr processInfo_ = nullptr; + std::shared_ptr application_ = nullptr; + std::shared_ptr applicationImpl_ = nullptr; + std::shared_ptr mainHandler_ = nullptr; + std::shared_ptr abilityRecordMgr_ = nullptr; + MainThreadState mainThreadState_ = MainThreadState::INIT; + sptr appMgr_ = nullptr; // appMgrService Handler + sptr deathRecipient_ = nullptr; + std::string aceApplicationName_ = "AceApplication"; + std::string pathSeparator_ = "/"; + std::string abilityLibraryType_ = ".so"; + +#ifdef ABILITY_LIBRARY_LOADER + /** + * + * @brief Load the ability library. + * + * @param libraryPaths the library paths. + * + */ + void LoadAbilityLibrary(const std::vector &libraryPaths); + + /** + * + * @brief Close the ability library loaded. + * + */ + void CloseAbilityLibrary(); + + /** + * + * @brief Scan the dir ability library loaded. + * + * @param dirPath the the path should be scan. + * + */ + bool ScanDir(const std::string &dirPath); + + /** + * + * @brief Check the fileType. + * + * @param fileName The fileName of the lib. + * @param extensionName The extensionName of the lib. + * + * @return if the FileType is legal, return true. else return false. + * + */ + bool CheckFileType(const std::string &fileName, const std::string &extensionName); + std::vector fileEntries_; + std::vector handleAbilityLib_; // the handler of ACE Library. +#endif // ABILITY_LIBRARY_LOADER +#ifdef APPLICATION_LIBRARY_LOADER + void *handleAppLib_ = nullptr; // the handler of ACE Library. + constexpr static std::string applicationLibraryPath = "/hos/lib/libapplication_native.z.so"; +#endif // APPLICATION_LIBRARY_LOADER + DISALLOW_COPY_AND_MOVE(MainThread); +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_MAIN_THREAD_H diff --git a/kits/appkit/native/app/include/ohos_application.h b/kits/appkit/native/app/include/ohos_application.h new file mode 100644 index 000000000..6c05ec275 --- /dev/null +++ b/kits/appkit/native/app/include/ohos_application.h @@ -0,0 +1,204 @@ +/* + * 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_APPLICATION_H +#define FOUNDATION_APPEXECFWK_OHOS_APPLICATION_H + +#include +#include +#include "application_context.h" +#include "ability_lifecycle_callbacks.h" +#include "element_callback.h" + +namespace OHOS { +namespace AppExecFwk { +class ElementsCallback; +class ApplicationImpl; +class Configuration; +class AbilityRecordMgr; +class OHOSApplication : public ApplicationContext, + public AbilityLifecycleCallbacks, + public std::enable_shared_from_this { +public: + OHOSApplication(); + virtual ~OHOSApplication() = default; + + /** + * @brief dump OHOSApplication info + * + * @param extra dump OHOSApplication info + */ + void DumpApplication(); + + /** + * + * @brief Set the abilityRecordMgr to the OHOSApplication. + * + * @param abilityRecordMgr + */ + void SetAbilityRecordMgr(const std::shared_ptr &abilityRecordMgr); + + /** + * + * @brief Register AbilityLifecycleCallbacks with OHOSApplication + * + * @param callBack callBack When the life cycle of the ability in the application changes, + */ + void RegisterAbilityLifecycleCallbacks(const std::shared_ptr &callBack); + + /** + * + * @brief Unregister AbilityLifecycleCallbacks with OHOSApplication + * + * @param callBack RegisterAbilityLifecycleCallbacks`s callBack + */ + void UnregisterAbilityLifecycleCallbacks(const std::shared_ptr &callBack); + + /** + * + * @brief Will be called when the given ability calls Ability->onStart + * + * @param Ability Indicates the ability object that calls the onStart() method. + */ + void OnAbilityStart(const std::shared_ptr &ability); + + /** + * + * @brief Will be called when the given ability calls Ability->onInactive + * + * @param Ability Indicates the Ability object that calls the onInactive() method. + */ + void OnAbilityInactive(const std::shared_ptr &ability); + + /** + * + * @brief Will be called when the given ability calls Ability->onBackground + * + * @param Ability Indicates the Ability object that calls the onBackground() method. + */ + void OnAbilityBackground(const std::shared_ptr &ability); + + /** + * + * @brief Will be called when the given ability calls Ability->onForeground + * + * @param Ability Indicates the Ability object that calls the onForeground() method. + */ + void OnAbilityForeground(const std::shared_ptr &ability); + + /** + * + * @brief Will be called when the given ability calls Ability->onActive + * + * @param Ability Indicates the Ability object that calls the onActive() method. + */ + void OnAbilityActive(const std::shared_ptr &ability); + + /** + * + * @brief Will be called when the given ability calls Ability->onStop + * + * @param Ability Indicates the Ability object that calls the onStop() method. + */ + void OnAbilityStop(const std::shared_ptr &ability); + + /** + * + * Called when Ability#onSaveAbilityState(PacMap) was called on an ability. + * + * @param outState Indicates the PacMap object passed to Ability#onSaveAbilityState(PacMap) + * for storing user data and states. This parameter cannot be null. + */ + void DispatchAbilitySavedState(const PacMap &outState); + + /** + * + * @brief Called when an ability calls Ability#onSaveAbilityState(PacMap). + * You can implement your own logic in this method. + * @param outState IIndicates the {@link PacMap} object passed to the onSaveAbilityState() callback. + * + */ + void OnAbilitySaveState(const PacMap &outState); + + /** + * + * @brief Register ElementsCallback with OHOSApplication + * + * @param callBack callBack when the system configuration of the device changes. + */ + void RegisterElementsCallbacks(const std::shared_ptr &callback); + + /** + * + * @brief Unregister ElementsCallback with OHOSApplication + * + * @param callback RegisterElementsCallbacks`s callback + */ + void UnregisterElementsCallbacks(const std::shared_ptr &callback); + + /** + * + * @brief Will be Called when the system configuration of the device changes. + * + * @param config Indicates the new Configuration object. + */ + virtual void OnConfigurationUpdated(const Configuration &config); + + /** + * + * @brief Called when the system has determined to trim the memory, for example, + * when the ability is running in the background and there is no enough memory for + * running as many background processes as possible. + * + * @param level Indicates the memory trim level, which shows the current memory usage status. + */ + virtual void OnMemoryLevel(int level); + + /** + * + * @brief Will be called the application foregrounds + * + */ + virtual void OnForeground(); + + /** + * + * @brief Will be called the application backgrounds + * + */ + virtual void OnBackground(); + + /** + * + * @brief Will be called the application starts + * + */ + virtual void OnStart(); + + /** + * + * @brief Will be called the application ends + * + */ + virtual void OnTerminate(); + +private: + std::list> abilityLifecycleCallbacks_; + std::list> elementsCallbacks_; + std::shared_ptr abilityRecordMgr_ = nullptr; +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_OHOS_APPLICATION_H diff --git a/kits/appkit/native/app/include/sys_mgr_client.h b/kits/appkit/native/app/include/sys_mgr_client.h new file mode 100644 index 000000000..a97fc446e --- /dev/null +++ b/kits/appkit/native/app/include/sys_mgr_client.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 OHOS_AAFWK_SYS_MRG_CLIENT_H +#define OHOS_AAFWK_SYS_MRG_CLIENT_H + +#include +#include +#include +#include + +#include "if_system_ability_manager.h" +#include "iremote_object.h" +#include "singleton.h" + +namespace OHOS { +namespace AppExecFwk { + +class SysMrgClient { + DECLARE_DELAYED_SINGLETON(SysMrgClient) +public: + /** + * + * Get the systemAbility by ID. + * + * @param systemAbilityId The ID of systemAbility whitch want to get. + */ + sptr GetSystemAbility(const int32_t systemAbilityId); + + /** + * + * Register the systemAbility by ID. + * + * @param systemAbilityId The ID of systemAbility whitch want to register. + * @param broker The systemAbility whitch want to be registered. + */ + void RegisterSystemAbility(const int32_t systemAbilityId, sptr broker); + + /** + * + * Unregister the systemAbility by ID. + * + * @param systemAbilityId The ID of systemAbility whitch want to unregister. + */ + void UnregisterSystemAbility(const int32_t systemAbilityId); + +private: + OHOS::sptr abilityManager_; + std::mutex saMutex_; + std::unordered_map> servicesMap_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // OHOS_AAFWK_SYS_MRG_CLIENT_H diff --git a/kits/appkit/native/app/src/ability_manager.cpp b/kits/appkit/native/app/src/ability_manager.cpp new file mode 100644 index 000000000..e6ba800f8 --- /dev/null +++ b/kits/appkit/native/app/src/ability_manager.cpp @@ -0,0 +1,127 @@ +/* + * 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.h" +#include "app_log_wrapper.h" +#include "singleton.h" +#include "system_ability_definition.h" +#include "sys_mgr_client.h" + +namespace OHOS { +namespace AppExecFwk { + +AbilityManager &AbilityManager::GetInstance() +{ + static AbilityManager abilityManager; + return abilityManager; +} + +void AbilityManager::StartAbility(const Want &want, int requestCode = -1) +{ + APP_LOGD("%s, %d", __func__, __LINE__); + ErrCode error = AAFwk::AbilityManagerClient::GetInstance()->StartAbility(want, requestCode); + if (error != ERR_OK) { + APP_LOGE("%s failed, error : %d", __func__, error); + } +} + +void AbilityManager::MoveMissionToTop(int missionId) +{ + APP_LOGD("%s, %d", __func__, __LINE__); + ErrCode error = AAFwk::AbilityManagerClient::GetInstance()->MoveMissionToTop(missionId); + if (error != ERR_OK) { + APP_LOGE("%s failed, error : %d", __func__, error); + } +} + +StackInfo AbilityManager::GetAllStackInfo() const +{ + APP_LOGD("%s, %d", __func__, __LINE__); + StackInfo info; + ErrCode error = AAFwk::AbilityManagerClient::GetInstance()->GetAllStackInfo(info); + if (error != ERR_OK) { + APP_LOGE("%s failed, error : %d", __func__, error); + } + + return info; +} + +std::vector AbilityManager::QueryRecentAbilityMissionInfo(int numMax, int flags) const +{ + APP_LOGD("%s, %d", __func__, __LINE__); + std::vector info; + ErrCode error = AAFwk::AbilityManagerClient::GetInstance()->GetRecentMissions(numMax, flags, info); + if (error != ERR_OK) { + APP_LOGE("%s failed, error : %d", __func__, error); + } + + return info; +} + +std::vector AbilityManager::QueryRunningAbilityMissionInfo(int numMax) const +{ + APP_LOGD("%s, %d", __func__, __LINE__); + std::vector info; + ErrCode error = + AAFwk::AbilityManagerClient::GetInstance()->GetRecentMissions(numMax, RECENT_IGNORE_UNAVAILABLE, info); + if (error != ERR_OK) { + APP_LOGE("%s failed, error : %d", __func__, error); + } + + return info; +} + +void AbilityManager::RemoveMissions(const std::vector &missionId) +{ + APP_LOGD("%s, %d", __func__, __LINE__); + ErrCode error = AAFwk::AbilityManagerClient::GetInstance()->RemoveMissions(missionId); + if (error != ERR_OK) { + APP_LOGE("%s failed, error : %d", __func__, error); + } +} + +void AbilityManager::ClearUpApplicationData(const std::string &bundleName) +{ + APP_LOGD("%s, %d", __func__, __LINE__); + auto object = OHOS::DelayedSingleton::GetInstance()->GetSystemAbility(APP_MGR_SERVICE_ID); + sptr appMgr_ = iface_cast(object); + if (appMgr_ == nullptr) { + APP_LOGE("%s, appMgr_ is nullptr", __func__); + return; + } + + appMgr_->ClearUpApplicationData(bundleName); +} + +RunningProcessInfo AbilityManager::GetAllRunningProcesses() +{ + APP_LOGD("%s, %d", __func__, __LINE__); + auto object = OHOS::DelayedSingleton::GetInstance()->GetSystemAbility(APP_MGR_SERVICE_ID); + sptr appMgr_ = iface_cast(object); + RunningProcessInfo info; + std::shared_ptr prpcessInfo = std::make_shared(); + + if (appMgr_ == nullptr || prpcessInfo == nullptr) { + APP_LOGE("%s, appMgr_ is nullptr", __func__); + return info; + } + + appMgr_->GetAllRunningProcesses(prpcessInfo); + info.appProcessInfos = prpcessInfo->appProcessInfos; + return info; +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/kits/appkit/native/app/src/ability_record_mgr.cpp b/kits/appkit/native/app/src/ability_record_mgr.cpp new file mode 100644 index 000000000..c31713667 --- /dev/null +++ b/kits/appkit/native/app/src/ability_record_mgr.cpp @@ -0,0 +1,162 @@ +/* + * 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_record_mgr.h" +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { + +/** + * @brief Get the token witch is set to the AbilityRecordMgr. + * + * @return Returns the token which is set to the AbilityRecordMgr. + */ +sptr AbilityRecordMgr::GetToken() const +{ + return tokens_; +} + +/** + * @brief Set the token witch the app launched. + * + * @param token The token which the is launched by app. + */ +void AbilityRecordMgr::SetToken(const sptr &token) +{ + if (token == nullptr) { + APP_LOGE("AbilityRecordMgr::SetToken failed, application is nullptr"); + return; + } + tokens_ = token; +} + +/** + * @brief Set the eventRunner of abilitythread to the AbilityRecordMgr. + * + * @param eventRunner The runner of the abilitythread. + * + */ +void AbilityRecordMgr::SetEventRunner(const std::shared_ptr &eventRunner) +{ + if (eventRunner == nullptr) { + APP_LOGE("AbilityRecordMgr::SetEventRunner failed, eventRunner is nullptr"); + return; + } + sptr token = GetToken(); + if (token == nullptr) { + APP_LOGE("AbilityRecordMgr::SetEventRunner failed, token is nullptr"); + return; + } + + std::shared_ptr abilityInstance = GetAbilityItem(token); + if (abilityInstance != nullptr) { + abilityInstance->SetEventRunner(eventRunner); + } else { + APP_LOGW("AbilityRecordMgr::setEventRunner failed, ability record is not exists"); + } +} + +/** + * @brief Save the token and abilityRecord to the AbilityRecordMgr. + * + * @param token The token which the abilityRecord belongs to. + * @param abilityRecord the abilityRecord witch contains the context info belong the the ability. + * + */ +void AbilityRecordMgr::AddAbilityRecord( + const sptr &token, const std::shared_ptr &abilityRecord) +{ + if (token == nullptr) { + APP_LOGE("AbilityRecordMgr::AddAbilityRecord failed, token is nullptr"); + return; + } + + if (abilityRecord == nullptr) { + APP_LOGE("AbilityRecordMgr::AddAbilityRecord failed, abilityRecord is nullptr"); + return; + } + + abilityRecords_[token] = abilityRecord; +} + +/** + * @brief Remove the abilityRecord by token. + * + * @param token The token which the abilityRecord belongs to. + * + */ +void AbilityRecordMgr::RemoveAbilityRecord(const sptr &token) +{ + if (token == nullptr) { + APP_LOGE("AbilityRecordMgr::RemoveAbilityRecord failed, token is nullptr"); + return; + } + abilityRecords_.erase(token); +} + +/** + * @brief Get the number of abilityRecords which the AbilityRecordMgr saved. + * + * @return Return the number of abilityRecords which the AbilityRecordMgr saved. + * + */ +int AbilityRecordMgr::GetRecordCount() const +{ + return abilityRecords_.size(); +} + +/** + * @brief Get the abilityRecord by token. + * + * @param token The token which the abilityRecord belongs to. + * + */ +std::shared_ptr AbilityRecordMgr::GetAbilityItem(const sptr &token) const +{ + if (token == nullptr) { + APP_LOGE("AbilityRecordMgr::GetAbilityItem failed, token is nullptr"); + return nullptr; + } + + const auto &iter = abilityRecords_.find(token); + if (iter != abilityRecords_.end()) { + APP_LOGI("AbilityRecordMgr::GetAbilityItem : the ability found"); + return iter->second; + } + APP_LOGI("AbilityRecordMgr::GetAbilityItem : the ability not found"); + return nullptr; +} + +/** + * @brief Get the all tokens in the abilityRecordMgr. + * + * @return all tokens in the abilityRecordMgr. + * + */ +std::vector> AbilityRecordMgr::GetAllTokens() +{ + std::vector> tokens; + for (std::map, std::shared_ptr>::iterator it = abilityRecords_.begin(); + it != abilityRecords_.end(); + ++it) { + sptr token = it->first; + tokens.emplace_back(token); + } + return tokens; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/kits/appkit/native/app/src/ability_start_setting.cpp b/kits/appkit/native/app/src/ability_start_setting.cpp new file mode 100644 index 000000000..3dc34e60e --- /dev/null +++ b/kits/appkit/native/app/src/ability_start_setting.cpp @@ -0,0 +1,149 @@ +/* + * 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 Inner function to create AbilityStartSetting + * + * @return Returns the shared_ptr of AbilityStartSetting object. + */ +std::shared_ptr AbilityStartSettingCreator() +{ + AbilityStartSetting *ptrAbilityStartSetting = new (std::nothrow) AbilityStartSetting(); + if (ptrAbilityStartSetting == nullptr) { + APP_LOGE("AbilityStartSettingCreator failed, create AbilityStartSetting failed"); + return nullptr; + } + + return std::shared_ptr(ptrAbilityStartSetting); +} + +/** + * @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 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 + */ +std::shared_ptr AbilityStartSetting::Unmarshalling(Parcel &parcel) +{ + std::shared_ptr abilityStartSetting = + std::make_shared(AbilityStartSetting()); + + // 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/app_loader.cpp b/kits/appkit/native/app/src/app_loader.cpp new file mode 100644 index 000000000..b313ea91d --- /dev/null +++ b/kits/appkit/native/app/src/app_loader.cpp @@ -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. + */ + +#include "app_loader.h" +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { + +/** + * @description: Gets the ApplicationLoader object to application register + * @param None + * @return ApplicationLoader + */ +ApplicationLoader &ApplicationLoader::GetInstance() +{ + static ApplicationLoader applicationLoader; + return applicationLoader; +} + +/** + * @description: Gets the ApplicationLoader object to register application + * @param bundleName the bundle name of the application. + * @param createFunc constructor function of application class. + * @return None + */ +void ApplicationLoader::RegisterApplication(const std::string &bundleName, const CreateApplication &createFunc) +{ + applications_.emplace(bundleName, createFunc); + APP_LOGD("ApplicationLoader::RegisterApplication:%{public}s", bundleName.c_str()); +} + +/** + * @description: Gets the {@link OHOSApplication} object + * @param applicationName application name. + * @return Return {@link OHOSApplication} object which is registered by developer. + */ +OHOSApplication *ApplicationLoader::GetApplicationByName(const std::string &bundleName) +{ + auto it = applications_.find("OHOSApplication"); + if (it == applications_.end()) { + APP_LOGE("ApplicationLoader::GetApplicationByName failed:%{public}s", bundleName.c_str()); + } else { + return it->second(); + } + return nullptr; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/kits/appkit/native/app/src/application_context.cpp b/kits/appkit/native/app/src/application_context.cpp new file mode 100644 index 000000000..ab50f64d4 --- /dev/null +++ b/kits/appkit/native/app/src/application_context.cpp @@ -0,0 +1,136 @@ +/* + * 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 "application_context.h" +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { + +/** + * @brief Obtains information about the current ability. + * The returned information includes the class name, bundle name, and other information about the current ability. + * + * @return Returns the AbilityInfo object for the current ability. + */ +const std::shared_ptr ApplicationContext::GetAbilityInfo() +{ + return nullptr; +} + +/** + * @brief Starts a new ability. + * An ability using the AbilityInfo.AbilityType.SERVICE or AbilityInfo.AbilityType.PAGE template uses this method + * to start a specific ability. The system locates the target ability from installed abilities based on the value + * of the want parameter and then starts it. You can specify the ability to start using the want parameter. + * + * @param want Indicates the Want containing information about the target ability to start. + * + * @param requestCode Indicates the request code returned after the ability using the AbilityInfo.AbilityType.PAGE + * template is started. You can define the request code to identify the results returned by abilities. The value + * ranges from 0 to 65535. This parameter takes effect only on abilities using the AbilityInfo.AbilityType.PAGE + * template. + * + */ +void ApplicationContext::StartAbility(const AAFwk::Want &want, int requestCode) +{} + +/** + * @brief Starts a new ability with special ability start setting. + * + * @param want Indicates the Want containing information about the target ability to start. + * @param requestCode Indicates the request code returned after the ability is started. You can define the request code + * to identify the results returned by abilities. The value ranges from 0 to 65535. + * @param abilityStartSetting Indicates the special start setting used in starting ability. + * + */ +void ApplicationContext::StartAbility(const Want &want, int requestCode, const AbilityStartSetting &abilityStartSetting) +{} + +/** + * @brief Destroys another ability you had previously started by calling Ability.startAbilityForResult + * (ohos.aafwk.content.Want, int, ohos.aafwk.ability.startsetting.AbilityStartSetting) with the same requestCode passed. + * + * @param requestCode Indicates the request code passed for starting the ability. + * + */ +void ApplicationContext::TerminateAbility(int requestCode) +{} + +/** + * @brief Destroys the current ability. + * + */ +void ApplicationContext::TerminateAbility() +{} + +/** + * @brief Obtains the bundle name of the ability that called the current ability. + * You can use the obtained bundle name to check whether the calling ability is allowed to receive the data you will + * send. If you did not use Ability.startAbilityForResult(ohos.aafwk.content.Want, int, + * ohos.aafwk.ability.startsetting.AbilityStartSetting) to start the calling ability, null is returned. + * + * @return Returns the bundle name of the calling ability; returns null if no calling ability is available. + */ +std::string ApplicationContext::GetCallingBundle() +{ + return ""; +} + +/** + * @brief Connects the current ability to an ability + * + * @param want Indicates the want containing information about the ability to connect + * + * @param conn Indicates the callback object when the target ability is connected. + * + * @return True means success and false means failure + */ +bool ApplicationContext::ConnectAbility(const Want &want, const sptr &conn) +{ + return false; +} + +/** + * @brief Disconnects the current ability from an ability + * + * @param conn Indicates the IAbilityConnection callback object passed by connectAbility after the connection + * is set up. The IAbilityConnection object uniquely identifies a connection between two abilities. + */ +void ApplicationContext::DisconnectAbility(const sptr &conn) +{} + +/** + * @brief Destroys another ability that uses the AbilityInfo.AbilityType.SERVICE template. + * The current ability using either the AbilityInfo.AbilityType.SERVICE or AbilityInfo.AbilityType.PAGE + * template can call this method to destroy another ability that uses the AbilityInfo.AbilityType.SERVICE + * template. The current ability itself can be destroyed by calling the terminateAbility() method. + * + * @param want Indicates the Want containing information about the ability to destroy. + * + * @return Returns true if the ability is destroyed successfully; returns false otherwise. + */ +bool ApplicationContext::StopAbility(const AAFwk::Want &want) +{ + return false; +} + +sptr ApplicationContext::GetToken() +{ + return nullptr; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/kits/appkit/native/app/src/application_env.cpp b/kits/appkit/native/app/src/application_env.cpp new file mode 100644 index 000000000..208aeaa11 --- /dev/null +++ b/kits/appkit/native/app/src/application_env.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 "application_env.h" +#include "application_env_impl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Obtains the bundle name of the application + * @param - + * @return Returns the pointer to the bundle name if the operation is successful; returns a null pointer otherwise. + */ +const char *GetBundleName() +{ + OHOS::AppExecFwk::ApplicationEnvImpl *pApplicationEnvIml = OHOS::AppExecFwk::ApplicationEnvImpl::GetInstance(); + const char *pBundleName = nullptr; + + if (pApplicationEnvIml) { + pBundleName = pApplicationEnvIml->GetBundleName().c_str(); + } + + return pBundleName; +} + +/** + * @brief Obtains the source code path of this application. + * @param - + * @return Returns the pointer to the source code path of this application. + */ +const char *GetSrcPath() +{ + OHOS::AppExecFwk::ApplicationEnvImpl *pApplicationEnvIml = OHOS::AppExecFwk::ApplicationEnvImpl::GetInstance(); + const char *pSrcPath = nullptr; + + if (pApplicationEnvIml) { + pSrcPath = pApplicationEnvIml->GetSrcPath().c_str(); + } + + return pSrcPath; +} + +/** + * @brief Obtains the data path of this application. + * @param - + * @return Returns the pointer to the data path of this application. + */ +const char *GetDataPath() +{ + OHOS::AppExecFwk::ApplicationEnvImpl *pApplicationEnvIml = OHOS::AppExecFwk::ApplicationEnvImpl::GetInstance(); + const char *pDataPath = nullptr; + + if (pApplicationEnvIml) { + pDataPath = pApplicationEnvIml->GetDataPath().c_str(); + } + + return pDataPath; +} + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/kits/appkit/native/app/src/application_env_impl.cpp b/kits/appkit/native/app/src/application_env_impl.cpp new file mode 100644 index 000000000..de9578845 --- /dev/null +++ b/kits/appkit/native/app/src/application_env_impl.cpp @@ -0,0 +1,79 @@ +/* + * 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 "application_env_impl.h" +#include "application_info.h" + +namespace OHOS { +namespace AppExecFwk { + +/** + * @brief Sets L1 information about the runtime environment of the application to which the + * ability belongs, including the bundle name, source code path, and data path. + * @param appInfo + * @return void + */ +void ApplicationEnvImpl::SetAppInfo(const AppInfo &appInfo) +{ + bundleName_ = appInfo.bundleName; + dataPath_ = appInfo.dataPath; + srcPath_ = appInfo.srcPath; +} + +/** + * @brief Sets information about the runtime environment of the application to which the + * ability belongs, including the bundle name, source code path, and data path. + * @param appInfo indicates + * @return void + */ +void ApplicationEnvImpl::SetAppInfo(const ApplicationInfo &appInfo) +{ + bundleName_ = appInfo.bundleName; + dataPath_ = appInfo.dataDir; + srcPath_ = appInfo.codePath; +} + +/** + * @brief Gets the bundlename of the application's runtime environment + * @param - + * @return bundleName + */ +const std::string &ApplicationEnvImpl::GetBundleName() const +{ + return bundleName_; +} + +/** + * @brief Gets the SrcPath of the application's runtime environment + * @param - + * @return SrcPath + */ +const std::string &ApplicationEnvImpl::GetSrcPath() const +{ + return srcPath_; +} + +/** + * @brief Gets the DataPath of the application's runtime environment + * @param - + * @return DataPath + */ +const std::string &ApplicationEnvImpl::GetDataPath() const +{ + return dataPath_; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/kits/appkit/native/app/src/application_impl.cpp b/kits/appkit/native/app/src/application_impl.cpp new file mode 100644 index 000000000..419f03946 --- /dev/null +++ b/kits/appkit/native/app/src/application_impl.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 "application_impl.h" +#include "ohos_application.h" +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { +ApplicationImpl::ApplicationImpl() : curState_(APP_STATE_CREATE), recordId_(0) +{} + +/** + * @brief Set the application to the ApplicationImpl. + * + * @param application The application which the mainthread launched. + * + */ +void ApplicationImpl::SetApplication(const std::shared_ptr &application) +{ + if (application == nullptr) { + APP_LOGE("ApplicationImpl::SetApplication failed, application is nullptr"); + return; + } + this->application_ = application; +} + +/** + * @brief Schedule the application to the APP_STATE_READY state. + * + * @return Returns true if performAppReady is scheduled successfully; + * Returns false otherwise. + */ +bool ApplicationImpl::PerformAppReady() +{ + APP_LOGD("ApplicationImpl::PerformAppReady called"); + if (curState_ == APP_STATE_CREATE) { + application_->OnStart(); + curState_ = APP_STATE_READY; + return true; + } + APP_LOGE("ApplicationImpl::PerformAppReady error! curState is %{public}d", curState_); + return false; +} + +/** + * @brief Schedule the application to the APP_STATE_FOREGROUND state. + * + * @return Returns true if PerformForeground is scheduled successfully; + * Returns false otherwise. + */ +bool ApplicationImpl::PerformForeground() +{ + APP_LOGD("ApplicationImpl::performForeground called"); + if ((curState_ == APP_STATE_READY) || (curState_ == APP_STATE_BACKGROUND)) { + application_->OnForeground(); + curState_ = APP_STATE_FOREGROUND; + return true; + } + APP_LOGE("ApplicationImpl::performForeground error! curState is %{public}d", curState_); + return false; +} + +/** + * @brief Schedule the application to the APP_STATE_BACKGROUND state. + * + * @return Returns true if PerformBackground is scheduled successfully; + * Returns false otherwise. + */ +bool ApplicationImpl::PerformBackground() +{ + APP_LOGD("ApplicationImpl::performBackground called"); + if (curState_ == APP_STATE_FOREGROUND) { + application_->OnBackground(); + curState_ = APP_STATE_BACKGROUND; + return true; + } + APP_LOGE("ApplicationImpl::performBackground error! curState is %{public}d", curState_); + return false; +} + +/** + * @brief Schedule the application to the APP_STATE_TERMINATED state. + * + * @return Returns true if PerformTerminate is scheduled successfully; + * Returns false otherwise. + */ +bool ApplicationImpl::PerformTerminate() +{ + APP_LOGD("ApplicationImpl::PerformTerminate called"); + if (curState_ == APP_STATE_BACKGROUND) { + application_->OnTerminate(); + curState_ = APP_STATE_TERMINATED; + return true; + } + APP_LOGE("ApplicationImpl::performTerminate error! curState is %{public}d", curState_); + return false; +} + +/** + * @brief Schedule the application to the APP_STATE_TERMINATED state. + * + * @return Returns true if PerformTerminate is scheduled successfully; + * Returns false otherwise. + */ +void ApplicationImpl::PerformTerminateStrong() +{ + APP_LOGD("ApplicationImpl::PerformTerminateStrong called"); + application_->OnTerminate(); +} + +/** + * @brief System determines to trim the memory. + * + * @param level Indicates the memory trim level, which shows the current memory usage status. + * + */ +void ApplicationImpl::PerformMemoryLevel(int level) +{ + APP_LOGD("ApplicationImpl::PerformMemoryLevel called"); + application_->OnMemoryLevel(level); +} + +/** + * @brief System determines to send the new config to application. + * + * @param config Indicates the updated configuration information. + * + */ +void ApplicationImpl::PerformConfigurationUpdated(const Configuration &config) +{ + APP_LOGD("ApplicationImpl::PerformConfigurationUpdated called"); + application_->OnConfigurationUpdated(config); +} + +/** + * @brief Set the target state to application. + * + * @param state The target state of application. + * + */ +int ApplicationImpl::SetState(int state) +{ + curState_ = state; + return curState_; +} + +/** + * @brief Get the current state of application. + * + * @return Returns the current state of application. + * + */ +int ApplicationImpl::GetState() const +{ + return curState_; +} + +/** + * @brief Set the RecordId to application. + * + * @param id recordId. + * + */ +void ApplicationImpl::SetRecordId(int id) +{ + recordId_ = id; +} + +/** + * @brief Get the recordId of application. + * + * @return Returns the recordId of application. + * + */ +int ApplicationImpl::GetRecordId() const +{ + return recordId_; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/kits/appkit/native/app/src/context_container.cpp b/kits/appkit/native/app/src/context_container.cpp new file mode 100755 index 000000000..c12148cfb --- /dev/null +++ b/kits/appkit/native/app/src/context_container.cpp @@ -0,0 +1,716 @@ +/* + * 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 "context_container.h" +#include "app_log_wrapper.h" +#include "ability_manager_errors.h" +#include "application_context.h" +#include "bundle_constants.h" + +namespace OHOS { +namespace AppExecFwk { + +/** + * Attaches a Context object to the current ability. + * Generally, this method is called after Ability is loaded to provide the application context for the current ability. + * + * @param base Indicates a Context object. + */ +void ContextContainer::AttachBaseContext(const std::shared_ptr &base) +{ + if (base == nullptr) { + APP_LOGE("ContextDeal::AttachBaseContext failed, base is nullptr"); + return; + } + baseContext_ = base; +} + +/** + * Called when getting the ProcessInfo + * + * @return ProcessInfo + */ +std::shared_ptr ContextContainer::GetProcessInfo() const +{ + if (baseContext_ != nullptr) { + return baseContext_->GetProcessInfo(); + } + return nullptr; +} + +/** + * @brief Obtains information about the current application. The returned application information includes basic + * information such as the application name and application permissions. + * + * @return Returns the ApplicationInfo for the current application. + */ +std::shared_ptr ContextContainer::GetApplicationInfo() const +{ + if (baseContext_ != nullptr) { + return baseContext_->GetApplicationInfo(); + } else { + APP_LOGE("ContextContainer::GetApplicationInfo baseContext_ is nullptr"); + return nullptr; + } +} + +/** + * @brief Obtains the Context object of the application. + * + * @return Returns the Context object of the application. + */ +std::shared_ptr ContextContainer::GetApplicationContext() const +{ + if (baseContext_ != nullptr) { + return baseContext_->GetApplicationContext(); + } else { + APP_LOGE("ContextContainer::GetApplicationContext baseContext_ is nullptr"); + return nullptr; + } +} + +/** + * @brief Obtains the path of the package containing the current ability. The returned path contains the resources, + * source code, and configuration files of a module. + * + * @return Returns the path of the package file. + */ +std::string ContextContainer::GetBundleCodePath() +{ + if (baseContext_ != nullptr) { + return baseContext_->GetBundleCodePath(); + } else { + APP_LOGE("ContextContainer::GetBundleCodePath baseContext_ is nullptr"); + return ""; + } +} + +/** + * @brief Obtains information about the current ability. + * The returned information includes the class name, bundle name, and other information about the current ability. + * + * @return Returns the AbilityInfo object for the current ability. + */ +const std::shared_ptr ContextContainer::GetAbilityInfo() +{ + if (baseContext_ != nullptr) { + return baseContext_->GetAbilityInfo(); + } else { + APP_LOGE("ContextContainer::GetAbilityInfo baseContext_ is nullptr"); + return nullptr; + } +} + +/** + * @brief Obtains the Context object of the application. + * + * @return Returns the Context object of the application. + */ +std::shared_ptr ContextContainer::GetContext() +{ + if (baseContext_ != nullptr) { + return baseContext_->GetContext(); + } else { + APP_LOGE("ContextContainer::GetContext baseContext_ is nullptr"); + return nullptr; + } +} + +/** + * @brief Obtains an IBundleMgr instance. + * You can use this instance to obtain information about the application bundle. + * + * @return Returns an IBundleMgr instance. + */ +sptr ContextContainer::GetBundleManager() const +{ + if (baseContext_ != nullptr) { + return baseContext_->GetBundleManager(); + } else { + APP_LOGE("ContextContainer::GetBundleManager baseContext_ is nullptr"); + return nullptr; + } +} + +/** + * @brief Obtains a resource manager. + * + * @return Returns a ResourceManager object. + */ +std::shared_ptr ContextContainer::GetResourceManager() const +{ + if (baseContext_ != nullptr) { + return baseContext_->GetResourceManager(); + } else { + APP_LOGE("ContextContainer::GetResourceManager baseContext_ is nullptr"); + return nullptr; + } +} + +/** + * @brief Deletes the specified private file associated with the application. + * + * @param fileName Indicates the name of the file to delete. The file name cannot contain path separators. + * + * @return Returns true if the file is deleted successfully; returns false otherwise. + */ +bool ContextContainer::DeleteFile(const std::string &fileName) +{ + if (baseContext_ != nullptr) { + return baseContext_->DeleteFile(fileName); + } else { + APP_LOGE("ContextContainer::DeleteFile baseContext_ is nullptr"); + return false; + } +} + +/** + * @brief Obtains the application-specific cache directory on the device's internal storage. The system + * automatically deletes files from the cache directory if disk space is required elsewhere on the device. + * Older files are always deleted first. + * + * @return Returns the application-specific cache directory. + */ +std::string ContextContainer::GetCacheDir() +{ + if (baseContext_ != nullptr) { + return baseContext_->GetCacheDir(); + } else { + APP_LOGE("ContextContainer::GetCacheDir baseContext_ is nullptr"); + return ""; + } +} + +/** + * @brief Obtains the application-specific code-cache directory on the device's internal storage. + * The system will delete any files stored in this location both when your specific application is upgraded, + * and when the entire platform is upgraded. + * + * @return Returns the application-specific code-cache directory. + */ +std::string ContextContainer::GetCodeCacheDir() +{ + if (baseContext_ != nullptr) { + return baseContext_->GetCodeCacheDir(); + } else { + APP_LOGE("ContextContainer::GetCodeCacheDir baseContext_ is nullptr"); + return ""; + } +} + +/** + * @brief Obtains the local database path. + * If the local database path does not exist, the system creates one and returns the created path. + * + * @return Returns the local database file. + */ +std::string ContextContainer::GetDatabaseDir() +{ + if (baseContext_ != nullptr) { + return baseContext_->GetDatabaseDir(); + } else { + APP_LOGE("ContextContainer::GetDatabaseDir baseContext_ is nullptr"); + return ""; + } +} + +/** + * @brief Obtains the absolute path where all private data files of this application are stored. + * + * @return Returns the absolute path storing all private data files of this application. + */ +std::string ContextContainer::GetDataDir() +{ + if (baseContext_ != nullptr) { + return baseContext_->GetDataDir(); + } else { + APP_LOGE("ContextContainer::GetDataDir baseContext_ is nullptr"); + return ""; + } +} + +/** + * @brief Obtains the directory for storing custom data files of the application. + * You can use the returned File object to create and access files in this directory. The files + * can be accessible only by the current application. + * + * @param name Indicates the name of the directory to retrieve. This directory is created as part + * of your application data. + * @param mode Indicates the file operating mode. The value can be 0 or a combination of MODE_PRIVATE. + * + * @return Returns a File object for the requested directory. + */ +std::string ContextContainer::GetDir(const std::string &name, int mode) +{ + if (baseContext_ != nullptr) { + return baseContext_->GetDir(name, mode); + } else { + APP_LOGE("ContextContainer::GetDir baseContext_ is nullptr"); + return ""; + } +} + +/** + * @brief Obtains the absolute path to the application-specific cache directory + * on the primary external or shared storage device. + * + * @return Returns the absolute path to the application-specific cache directory on the external or + * shared storage device; returns null if the external or shared storage device is temporarily unavailable. + */ +std::string ContextContainer::GetExternalCacheDir() +{ + if (baseContext_ != nullptr) { + return baseContext_->GetExternalCacheDir(); + } else { + APP_LOGE("ContextContainer::GetExternalCacheDir baseContext_ is nullptr"); + return ""; + } +} + +/** + * @brief Obtains the absolute path to the directory for storing files for the application on the + * primary external or shared storage device. + * + * @param type Indicates the type of the file directory to return + * + * @return Returns the absolute path to the application file directory on the external or shared storage + * device; returns null if the external or shared storage device is temporarily unavailable. + */ +std::string ContextContainer::GetExternalFilesDir(std::string &type) +{ + if (baseContext_ != nullptr) { + return baseContext_->GetExternalFilesDir(type); + } else { + APP_LOGE("ContextContainer::GetExternalFilesDir baseContext_ is nullptr"); + return ""; + } +} + +/** + * @brief Obtains the directory for storing files for the application on the device's internal storage. + * + * @return Returns the application file directory. + */ +std::string ContextContainer::GetFilesDir() +{ + if (baseContext_ != nullptr) { + return baseContext_->GetFilesDir(); + } else { + APP_LOGE("ContextContainer::GetFilesDir baseContext_ is nullptr"); + return ""; + } +} + +/** + * @brief Obtains the absolute path which app created and will be excluded from automatic backup to remote storage. + * The returned path maybe changed if the application is moved to an adopted storage device. + * + * @return The path of the directory holding application files that will not be automatically backed up to remote + * storage. + */ +std::string ContextContainer::GetNoBackupFilesDir() +{ + if (baseContext_ != nullptr) { + return baseContext_->GetNoBackupFilesDir(); + } else { + APP_LOGE("ContextContainer::GetNoBackupFilesDir baseContext_ is nullptr"); + return ""; + } +} + +/** + * @brief Checks whether the calling process for inter-process communication has the given permission. + * The calling process is not the current process. + * + * @param permission Indicates the permission to check. This parameter cannot be null. + * + * @return Returns 0 (IBundleManager.PERMISSION_GRANTED) if the calling process has the permission; + * returns -1 (IBundleManager.PERMISSION_DENIED) otherwise. + */ +int ContextContainer::VerifyCallingPermission(const std::string &permission) +{ + if (baseContext_ != nullptr) { + return baseContext_->VerifyCallingPermission(permission); + } else { + APP_LOGE("ContextContainer::VerifyCallingPermission baseContext_ is nullptr"); + return AppExecFwk::Constants::PERMISSION_NOT_GRANTED; + } +} + +/** + * @brief Checks whether the current process has the given permission. + * You need to call requestPermissionsFromUser(java.lang.std::string[],int) to request a permission only + * if the current process does not have the specific permission. + * + * @param permission Indicates the permission to check. This parameter cannot be null. + * + * @return Returns 0 (IBundleManager.PERMISSION_GRANTED) if the current process has the permission; + * returns -1 (IBundleManager.PERMISSION_DENIED) otherwise. + */ +int ContextContainer::VerifySelfPermission(const std::string &permission) +{ + if (baseContext_ != nullptr) { + return baseContext_->VerifySelfPermission(permission); + } else { + APP_LOGE("ContextContainer::VerifySelfPermission baseContext_ is nullptr"); + return AppExecFwk::Constants::PERMISSION_NOT_GRANTED; + } +} + +/** + * @brief Obtains the bundle name of the current ability. + * + * @return Returns the bundle name of the current ability. + */ +std::string ContextContainer::GetBundleName() +{ + if (baseContext_ != nullptr) { + return baseContext_->GetBundleName(); + } else { + APP_LOGE("ContextContainer::GetBundleName baseContext_ is nullptr"); + return ""; + } +} + +/** + * @brief Obtains the path of the OHOS Ability Package (HAP} containing this ability. + * + * @return Returns the path of the HAP containing this ability. + */ +std::string ContextContainer::GetBundleResourcePath() +{ + if (baseContext_ != nullptr) { + return baseContext_->GetBundleResourcePath(); + } else { + APP_LOGE("ContextContainer::GetBundleResourcePath baseContext_ is nullptr"); + return ""; + } +} + +/** + * @brief Remove permissions for all users who have access to specific permissions + * + * @param permission Indicates the permission to unauth. This parameter cannot be null. + * @param uri Indicates the URI to unauth. This parameter cannot be null. + * @param uid Indicates the UID of the unauth to check. + * + */ +void ContextContainer::UnauthUriPermission(const std::string &permission, const Uri &uri, int uid) +{ + if (baseContext_ != nullptr) { + baseContext_->UnauthUriPermission(permission, uri, uid); + } else { + APP_LOGE("ContextContainer::UnauthUriPermission baseContext_ is nullptr"); + } +} + +/** + * @brief Obtains an ability manager. + * The ability manager provides information about running processes and memory usage of an application. + * + * @return Returns an IAbilityManager instance. + */ +sptr ContextContainer::GetAbilityManager() +{ + if (baseContext_ != nullptr) { + return baseContext_->GetAbilityManager(); + } else { + APP_LOGE("ContextContainer::GetAbilityManager baseContext_ is nullptr"); + return nullptr; + } +} + +/** + * @brief Obtains the type of this application. + * + * @return Returns system if this application is a system application; + * returns normal if it is released in OHOS AppGallery; + * returns other if it is released by a third-party vendor; + * returns an empty string if the query fails. + */ +std::string ContextContainer::GetAppType() +{ + if (baseContext_ != nullptr) { + return baseContext_->GetAppType(); + } else { + APP_LOGE("ContextContainer::GetAppType baseContext_ is nullptr"); + return ""; + } +} + +/** + * @brief Confirms with the permission management module to check whether a request prompt is required for granting a + * certain permission. You need to call the current method to check whether a prompt is required before calling + * requestPermissionsFromUser(java.lang.String[],int) to request a permission. If a prompt is not required, permission + * request will not be initiated. + * + * @param requestCode Indicates the permission to be queried. This parameter cannot be null. + * + * @return Returns true if the current application does not have the permission and the user does not turn off further + * requests; returns false if the current application already has the permission, the permission is rejected by the + * system, or the permission is denied by the user and the user has turned off further requests. + */ +bool ContextContainer::CanRequestPermission(const std::string &permission) +{ + if (baseContext_ != nullptr) { + return baseContext_->CanRequestPermission(permission); + } else { + APP_LOGE("ContextContainer::CanRequestPermission baseContext_ is nullptr"); + return true; + } +} + +/** + * @brief When there is a remote call to check whether the remote has permission, otherwise check whether it has + * permission + * + * @param permissions Indicates the list of permissions to be requested. This parameter cannot be null. + * @return Returns 0 (IBundleManager.PERMISSION_GRANTED) if the current process has the permission; + * returns -1 (IBundleManager.PERMISSION_DENIED) otherwise. + */ +int ContextContainer::VerifyCallingOrSelfPermission(const std::string &permission) +{ + if (baseContext_ != nullptr) { + return baseContext_->VerifyCallingOrSelfPermission(permission); + } else { + APP_LOGE("ContextContainer::VerifyCallingOrSelfPermission baseContext_ is nullptr"); + return AppExecFwk::Constants::PERMISSION_NOT_GRANTED; + } +} + +/** + * @brief Query whether the application of the specified PID and UID has been granted a certain permission + * + * @param permissions Indicates the list of permissions to be requested. This parameter cannot be null. + * @param pid Process id + * @param uid + * @return Returns 0 (IBundleManager.PERMISSION_GRANTED) if the current process has the permission; + * returns -1 (IBundleManager.PERMISSION_DENIED) otherwise. + */ +int ContextContainer::VerifyPermission(const std::string &permission, int pid, int uid) +{ + if (baseContext_ != nullptr) { + return baseContext_->VerifyPermission(permission, pid, uid); + } else { + APP_LOGE("ContextContainer::VerifyPermission baseContext_ is nullptr"); + return AppExecFwk::Constants::PERMISSION_NOT_GRANTED; + } +} + +/** + * @brief Obtains the distributed file path. + * If the distributed file path does not exist, the system creates one and returns the created path. This method is + * applicable only to the context of an ability rather than that of an application. + * + * @return Returns the distributed file. + */ +std::string ContextContainer::GetDistributedDir() +{ + if (baseContext_ != nullptr) { + return baseContext_->GetDistributedDir(); + } else { + APP_LOGE("ContextContainer::GetDistributedDir baseContext_ is nullptr"); + return ""; + } +} +/** + * @brief Sets the pattern of this Context based on the specified pattern ID. + * + * @param patternId Indicates the resource ID of the pattern to set. + */ +void ContextContainer::SetPattern(int patternId) +{ + if (baseContext_ != nullptr) { + baseContext_->SetPattern(patternId); + } else { + APP_LOGE("ContextContainer::SetPattern baseContext_ is nullptr"); + } +} + +/** + * @brief Obtains the Context object of this ability. + * + * @return Returns the Context object of this ability. + */ +std::shared_ptr ContextContainer::GetAbilityPackageContext() +{ + if (baseContext_ != nullptr) { + return baseContext_->GetAbilityPackageContext(); + } else { + APP_LOGE("ContextContainer::GetAbilityPackageContext baseContext_ is nullptr"); + return nullptr; + } +} + +/** + * @brief Obtains the HapModuleInfo object of the application. + * + * @return Returns the HapModuleInfo object of the application. + */ +std::shared_ptr ContextContainer::GetHapModuleInfo() +{ + if (baseContext_ != nullptr) { + return baseContext_->GetHapModuleInfo(); + } else { + APP_LOGE("ContextContainer::GetHapModuleInfo baseContext_ is nullptr"); + return nullptr; + } +} + +/** + * @brief Obtains the name of the current process. + * + * @return Returns the current process name. + */ +std::string ContextContainer::GetProcessName() +{ + if (baseContext_ != nullptr) { + return baseContext_->GetProcessName(); + } else { + APP_LOGE("ContextContainer::GetProcessName baseContext_ is nullptr"); + return ""; + } +} + +/** + * @brief Requests certain permissions from the system. + * This method is called for permission request. This is an asynchronous method. When it is executed, + * the Ability.onRequestPermissionsFromUserResult(int, String[], int[]) method will be called back. + * + * @param permissions Indicates the list of permissions to be requested. This parameter cannot be null. + * @param requestCode Indicates the request code to be passed to the Ability.onRequestPermissionsFromUserResult(int, + * String[], int[]) callback method. This code cannot be a negative number. + * + */ +void ContextContainer::RequestPermissionsFromUser(std::vector &permissions, int requestCode) +{ + if (baseContext_ != nullptr) { + baseContext_->RequestPermissionsFromUser(permissions, requestCode); + } else { + APP_LOGE("ContextContainer::RequestPermissionsFromUser baseContext_ is nullptr"); + } +} + +/** + * @brief Creates a Context object for an application with the given bundle name. + * + * @param bundleName Indicates the bundle name of the application. + * + * @param flag Indicates the flag for creating a Context object. It can be 0, any of + * the following values, or any combination of the following values: CONTEXT_IGNORE_SECURITY, + * CONTEXT_INCLUDE_CODE, and CONTEXT_RESTRICTED. The value 0 indicates that there is no restriction + * on creating contexts for applications. + * + * @return Returns a Context object created for the specified application. + */ +std::shared_ptr ContextContainer::CreateBundleContext(std::string bundleName, int flag) +{ + if (bundleName.empty()) { + APP_LOGE("ContextContainer::CreateBundleContext bundleName is empty"); + return nullptr; + } + + if (strcmp(bundleName.c_str(), GetBundleName().c_str()) == 0) { + return GetApplicationContext(); + } + + sptr bundleMgr = GetBundleManager(); + if (nullptr == bundleMgr) { + APP_LOGE("ContextContainer::CreateBundleContext GetBundleManager is nullptr"); + return nullptr; + } + + BundleInfo bundleInfo; + APP_LOGI("ContextContainer::CreateBundleContext length: %{public}d, bundleName: %{public}s", + bundleName.length(), + bundleName.c_str()); + bundleMgr->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); + + if (bundleInfo.name.empty() || bundleInfo.applicationInfo.name.empty()) { + APP_LOGE("ContextContainer::CreateBundleContext GetBundleInfo is error"); + return nullptr; + } + + std::shared_ptr appContext = std::make_shared(); + if (appContext == nullptr) { + APP_LOGE("ContextContainer::CreateBundleContext appContext is nullptr"); + return nullptr; + } + std::shared_ptr deal = std::make_shared(); + if (deal == nullptr) { + APP_LOGE("ContextContainer::CreateBundleContext bundleName is empty"); + return nullptr; + } + + // init resourceManager. + InitResourceManager(bundleInfo, deal); + + deal->SetApplicationInfo(std::make_shared(bundleInfo.applicationInfo)); + appContext->AttachBaseContext(deal); + return appContext; +} + +void ContextContainer::InitResourceManager(BundleInfo &bundleInfo, std::shared_ptr &deal) +{ + std::shared_ptr resourceManager(Global::Resource::CreateResourceManager()); + if (deal == nullptr || resourceManager == nullptr) { + APP_LOGE("ContextContainer::InitResourceManager create resourceManager failed"); + return; + } + + APP_LOGI( + "ContextContainer::InitResourceManager moduleResPaths count: %{public}d", bundleInfo.moduleResPaths.size()); + for (auto moduleResPath : bundleInfo.moduleResPaths) { + if (!moduleResPath.empty()) { + APP_LOGI("ContextContainer::InitResourceManager length: %{public}d, moduleResPath: %{public}s", + moduleResPath.length(), + moduleResPath.c_str()); + if (!resourceManager->AddResource(moduleResPath.c_str())) { + APP_LOGE("ContextContainer::InitResourceManager AddResource failed"); + } + } + } + + std::unique_ptr resConfig(Global::Resource::CreateResConfig()); + resConfig->SetLocaleInfo("zh", "Hans", "CN"); + if (resConfig->GetLocaleInfo() != nullptr) { + APP_LOGI("ContextContainer::InitResourceManager language: %{public}s, script: %{public}s, region: %{public}s,", + resConfig->GetLocaleInfo()->GetLanguage(), + resConfig->GetLocaleInfo()->GetScript(), + resConfig->GetLocaleInfo()->GetRegion()); + } else { + APP_LOGI("ContextContainer::InitResourceManager language: GetLocaleInfo is null."); + } + resourceManager->UpdateResConfig(*resConfig); + deal->initResourceManager(resourceManager); +} +/** + * @brief Obtains information about the caller of this ability. + * + * @return Returns the caller information. + */ +Uri ContextContainer::GetCaller() +{ + if (baseContext_ != nullptr) { + return baseContext_->GetCaller(); + } else { + APP_LOGE("ContextContainer::GetCaller baseContext_ is nullptr"); + Uri uri(""); + return uri; + } +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/kits/appkit/native/app/src/context_deal.cpp b/kits/appkit/native/app/src/context_deal.cpp new file mode 100755 index 000000000..a9aeef297 --- /dev/null +++ b/kits/appkit/native/app/src/context_deal.cpp @@ -0,0 +1,714 @@ +/* + * 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 "context_deal.h" +#include "file_ex.h" +#include "directory_ex.h" +#include "iservice_registry.h" +#include "app_log_wrapper.h" +#include "ability_manager_interface.h" +#include "ability_manager_client.h" +#include "system_ability_definition.h" +#include "sys_mgr_client.h" + +#define MODE 0771 +namespace OHOS { +namespace AppExecFwk { + +/** + * Called when getting the ProcessInfo + * + * @return ProcessInfo + */ +std::shared_ptr ContextDeal::GetProcessInfo() const +{ + return processInfo_; +} + +/** + * Called when setting the ProcessInfo + * + * @param info ProcessInfo instance + */ +void ContextDeal::SetProcessInfo(const std::shared_ptr &info) +{ + if (info == nullptr) { + APP_LOGE("ContextDeal::SetProcessInfo failed, info is empty"); + return; + } + processInfo_ = info; +} + +/** + * @brief Obtains information about the current application. The returned application information includes basic + * information such as the application name and application permissions. + * + * @return Returns the ApplicationInfo for the current application. + */ +std::shared_ptr ContextDeal::GetApplicationInfo() const +{ + return applicationInfo_; +} + +/** + * @brief Set ApplicationInfo + * + * @param info ApplicationInfo instance. + */ +void ContextDeal::SetApplicationInfo(const std::shared_ptr &info) +{ + if (info == nullptr) { + APP_LOGE("ContextDeal::SetApplicationInfo failed, info is empty"); + return; + } + applicationInfo_ = info; +} + +/** + * @brief Obtains the Context object of the application. + * + * @return Returns the Context object of the application. + */ +std::shared_ptr ContextDeal::GetApplicationContext() const +{ + return appContext_; +} + +/** + * @brief Set ApplicationContext + * + * @param context ApplicationContext instance. + */ +void ContextDeal::SetApplicationContext(const std::shared_ptr &context) +{ + if (context == nullptr) { + APP_LOGE("ContextDeal::SetApplicationContext failed, context is empty"); + return; + } + appContext_ = context; +} + +/** + * @brief Obtains the path of the package containing the current ability. The returned path contains the resources, + * source code, and configuration files of a module. + * + * @return Returns the path of the package file. + */ +std::string ContextDeal::GetBundleCodePath() +{ + return (applicationInfo_ != nullptr) ? applicationInfo_->codePath : ""; +} + +/** + * @brief SetBundleCodePath + * + * @param Returns string path + */ +void ContextDeal::SetBundleCodePath(std::string &path) +{ + path_ = path; +} + +/** + * @brief Obtains information about the current ability. + * The returned information includes the class name, bundle name, and other information about the current ability. + * + * @return Returns the AbilityInfo object for the current ability. + */ +const std::shared_ptr ContextDeal::GetAbilityInfo() +{ + return abilityInfo_; +} + +/** + * @brief Set AbilityInfo + * + * @param info AbilityInfo instance. + */ +void ContextDeal::SetAbilityInfo(const std::shared_ptr &info) +{ + if (info == nullptr) { + APP_LOGE("ContextDeal::SetAbilityInfo failed, info is empty"); + return; + } + abilityInfo_ = info; +} + +/** + * @brief Obtains the Context object of the ability. + * + * @return Returns the Context object of the ability. + */ +std::shared_ptr ContextDeal::GetContext() +{ + return abilityContext_; +} + +/** + * @brief Set Ability context + * + * @param context Ability object + */ +void ContextDeal::SetContext(const std::shared_ptr &context) +{ + if (context == nullptr) { + APP_LOGE("ContextDeal::SetContext failed, context is empty"); + return; + } + abilityContext_ = context; +} + +/** + * @brief Obtains an IBundleMgr instance. + * You can use this instance to obtain information about the application bundle. + * + * @return Returns an IBundleMgr instance. + */ +sptr ContextDeal::GetBundleManager() const +{ + 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); +} + +/** + * @brief Obtains a resource manager. + * + * @return Returns a ResourceManager object. + */ +std::shared_ptr ContextDeal::GetResourceManager() const +{ + return resourceManager_; +} + +/** + * @brief Set Profile instance. + * + * @param Profile instance. + */ +void ContextDeal::SetProfile(const std::shared_ptr &profile) +{ + if (profile == nullptr) { + APP_LOGE("ContextDeal::SetProfile failed, profile is nullptr"); + return; + } + profile_ = profile; +} + +/** + * @brief Obtains an Profile instance. + * + * @return Returns an Profile instance. + */ +std::shared_ptr ContextDeal::GetProfile() const +{ + return profile_; +} + +/** + * @brief Deletes the specified private file associated with the application. + * + * @param fileName Indicates the name of the file to delete. The file name cannot contain path separators. + * + * @return Returns true if the file is deleted successfully; returns false otherwise. + */ +bool ContextDeal::DeleteFile(const std::string &fileName) +{ + std::string path = GetDataDir() + "/" + fileName; + return OHOS::RemoveFile(path); +} + +/** + * @brief Destroys another ability that uses the AbilityInfo.AbilityType.SERVICE template. + * The current ability using either the AbilityInfo.AbilityType.SERVICE or AbilityInfo.AbilityType.PAGE + * template can call this method to destroy another ability that uses the AbilityInfo.AbilityType.SERVICE + * template. The current ability itself can be destroyed by calling the terminateAbility() method. + * + * @param want Indicates the Want containing information about the ability to destroy. + * + * @return Returns true if the ability is destroyed successfully; returns false otherwise. + */ +bool ContextDeal::StopAbility(const AAFwk::Want &want) +{ + return false; +} + +/** + * @brief Obtains the application-specific cache directory on the device's internal storage. The system + * automatically deletes files from the cache directory if disk space is required elsewhere on the device. + * Older files are always deleted first. + * + * @return Returns the application-specific cache directory. + */ +std::string ContextDeal::GetCacheDir() +{ + return (applicationInfo_ != nullptr) ? applicationInfo_->cacheDir : ""; +} + +/** + * @brief Obtains the application-specific code-cache directory on the device's internal storage. + * The system will delete any files stored in this location both when your specific application is upgraded, + * and when the entire platform is upgraded. + * + * @return Returns the application-specific code-cache directory. + */ +std::string ContextDeal::GetCodeCacheDir() +{ + return (applicationInfo_ != nullptr) ? (applicationInfo_->dataDir + "/" + "code_cache") : ""; +} + +/** + * @brief Obtains the local database path. + * If the local database path does not exist, the system creates one and returns the created path. + * + * @return Returns the local database file. + */ +std::string ContextDeal::GetDatabaseDir() +{ + return (applicationInfo_ != nullptr) ? applicationInfo_->dataBaseDir : ""; +} + +/** + * @brief Obtains the absolute path where all private data files of this application are stored. + * + * @return Returns the absolute path storing all private data files of this application. + */ +std::string ContextDeal::GetDataDir() +{ + return (applicationInfo_ != nullptr) ? applicationInfo_->dataDir : ""; +} + +/** + * @brief Obtains the directory for storing custom data files of the application. + * You can use the returned File object to create and access files in this directory. The files + * can be accessible only by the current application. + * + * @param name Indicates the name of the directory to retrieve. This directory is created as part + * of your application data. + * @param mode Indicates the file operating mode. The value can be 0 or a combination of MODE_PRIVATE. + * + * @return Returns a File object for the requested directory. + */ +std::string ContextDeal::GetDir(const std::string &name, int mode) +{ + if (applicationInfo_ == nullptr) { + APP_LOGE("ContextDeal::GetDir failed, applicationInfo_ == nullptr"); + return ""; + } + std::string dir = applicationInfo_->dataDir + "/" + name; + if (!OHOS::FileExists(dir)) { + APP_LOGI("ContextDeal::GetDir File is not exits"); + OHOS::ForceCreateDirectory(dir); + OHOS::ChangeModeDirectory(dir, mode); + } + return dir; +} + +/** + * @brief Obtains the absolute path to the application-specific cache directory + * on the primary external or shared storage device. + * + * @return Returns the absolute path to the application-specific cache directory on the external or + * shared storage device; returns null if the external or shared storage device is temporarily unavailable. + */ +std::string ContextDeal::GetExternalCacheDir() +{ + return ""; +} + +/** + * @brief Obtains the absolute path to the directory for storing files for the application on the + * primary external or shared storage device. + * + * @param type Indicates the type of the file directory to return + * + * @return Returns the absolute path to the application file directory on the external or shared storage + * device; returns null if the external or shared storage device is temporarily unavailable. + */ +std::string ContextDeal::GetExternalFilesDir(std::string &type) +{ + return ""; +} + +/** + * @brief Obtains the directory for storing files for the application on the device's internal storage. + * + * @return Returns the application file directory. + */ +std::string ContextDeal::GetFilesDir() +{ + return (applicationInfo_ != nullptr) ? (applicationInfo_->dataDir + "/" + "files") : ""; +} + +/** + * @brief Obtains the absolute path which app created and will be excluded from automatic backup to remote storage. + * The returned path maybe changed if the application is moved to an adopted storage device. + * + * @return The path of the directory holding application files that will not be automatically backed up to remote + * storage. + */ +std::string ContextDeal::GetNoBackupFilesDir() +{ + std::string dir = applicationInfo_->dataDir + "no_backup"; + if (!OHOS::FileExists(dir)) { + APP_LOGI("ContextDeal::GetDir GetNoBackupFilesDir is not exits"); + OHOS::ForceCreateDirectory(dir); + OHOS::ChangeModeDirectory(dir, MODE); + } + return dir; +} + +/** + * @brief Checks whether the calling process for inter-process communication has the given permission. + * The calling process is not the current process. + * + * @param permission Indicates the permission to check. This parameter cannot be null. + * + * @return Returns 0 (IBundleManager.PERMISSION_GRANTED) if the calling process has the permission; + * returns -1 (IBundleManager.PERMISSION_DENIED) otherwise. + */ +int ContextDeal::VerifyCallingPermission(const std::string &permission) +{ + return 0; +} + +/** + * @brief Checks whether the current process has the given permission. + * You need to call requestPermissionsFromUser(java.lang.std::string[],int) to request a permission only + * if the current process does not have the specific permission. + * + * @param permission Indicates the permission to check. This parameter cannot be null. + * + * @return Returns 0 (IBundleManager.PERMISSION_GRANTED) if the current process has the permission; + * returns -1 (IBundleManager.PERMISSION_DENIED) otherwise. + */ +int ContextDeal::VerifySelfPermission(const std::string &permission) +{ + return 0; +} + +/** + * @brief Obtains the bundle name of the current ability. + * + * @return Returns the bundle name of the current ability. + */ +std::string ContextDeal::GetBundleName() +{ + return (applicationInfo_ != nullptr) ? applicationInfo_->bundleName : ""; +} + +/** + * @brief Obtains the path of the OHOS Ability Package (HAP} containing this ability. + * + * @return Returns the path of the HAP containing this ability. + */ +std::string ContextDeal::GetBundleResourcePath() +{ + return (abilityInfo_ != nullptr) ? abilityInfo_->resourcePath : ""; +} + +/** + * @brief Starts a new ability. + * An ability using the AbilityInfo.AbilityType.SERVICE or AbilityInfo.AbilityType.PAGE template uses this method + * to start a specific ability. The system locates the target ability from installed abilities based on the value + * of the want parameter and then starts it. You can specify the ability to start using the want parameter. + * + * @param want Indicates the Want containing information about the target ability to start. + * + * @param requestCode Indicates the request code returned after the ability using the AbilityInfo.AbilityType.PAGE + * template is started. You can define the request code to identify the results returned by abilities. The value + * ranges from 0 to 65535. This parameter takes effect only on abilities using the AbilityInfo.AbilityType.PAGE + * template. + * + */ +void ContextDeal::StartAbility(const AAFwk::Want &want, int requestCode) +{ + APP_LOGI("ContextDeal::StartAbility is called"); +} + +/** + * @brief Remove permissions for all users who have access to specific permissions + * + * @param permission Indicates the permission to unauth. This parameter cannot be null. + * @param uri Indicates the URI to unauth. This parameter cannot be null. + * @param uid Indicates the UID of the unauth to check. + * + */ +void ContextDeal::UnauthUriPermission(const std::string &permission, const Uri &uri, int uid) +{} + +/** + * @brief Obtains an ability manager. + * The ability manager provides information about running processes and memory usage of an application. + * + * @return Returns an IAbilityManager instance. + */ +sptr ContextDeal::GetAbilityManager() +{ + 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); +} + +/** + * @brief Obtains the type of this application. + * + * @return Returns system if this application is a system application; + * returns normal if it is released in OHOS AppGallery; + * returns other if it is released by a third-party vendor; + * returns an empty string if the query fails. + */ +std::string ContextDeal::GetAppType() +{ + sptr ptr = GetBundleManager(); + if (ptr == nullptr) { + APP_LOGE("GetAppType failed to get bundle manager service"); + return ""; + } + + return ptr->GetAppType(applicationInfo_->bundleName); +} + +/** + * @brief Destroys another ability you had previously started by calling Ability.startAbilityForResult + * (ohos.aafwk.content.Want, int, ohos.aafwk.ability.startsetting.AbilityStartSetting) with the same requestCode passed. + * + * @param requestCode Indicates the request code passed for starting the ability. + * + */ +void ContextDeal::TerminateAbility(int requestCode) +{} + +/** + * @brief Confirms with the permission management module to check whether a request prompt is required for granting a + * certain permission. You need to call the current method to check whether a prompt is required before calling + * requestPermissionsFromUser(java.lang.String[],int) to request a permission. If a prompt is not required, permission + * request will not be initiated. + * + * @param requestCode Indicates the permission to be queried. This parameter cannot be null. + * + * @return Returns true if the current application does not have the permission and the user does not turn off further + * requests; returns false if the current application already has the permission, the permission is rejected by the + * system, or the permission is denied by the user and the user has turned off further requests. + */ +bool ContextDeal::CanRequestPermission(const std::string &permission) +{ + return false; +} + +/** + * @brief When there is a remote call to check whether the remote has permission, otherwise check whether it has + * permission + * + * @param permissions Indicates the list of permissions to be requested. This parameter cannot be null. + * @return Returns 0 (IBundleManager.PERMISSION_GRANTED) if the current process has the permission; + * returns -1 (IBundleManager.PERMISSION_DENIED) otherwise. + */ +int ContextDeal::VerifyCallingOrSelfPermission(const std::string &permission) +{ + return 0; +} + +/** + * @brief Query whether the application of the specified PID and UID has been granted a certain permission + * + * @param permissions Indicates the list of permissions to be requested. This parameter cannot be null. + * @param pid Process id + * @param uid + * @return Returns 0 (IBundleManager.PERMISSION_GRANTED) if the current process has the permission; + * returns -1 (IBundleManager.PERMISSION_DENIED) otherwise. + */ +int ContextDeal::VerifyPermission(const std::string &permission, int pid, int uid) +{ + return 0; +} + +/** + * @brief Obtains the distributed file path. + * If the distributed file path does not exist, the system creates one and returns the created path. This method is + * applicable only to the context of an ability rather than that of an application. + * + * @return Returns the distributed file. + */ +std::string ContextDeal::GetDistributedDir() +{ + return ""; +} +/** + * @brief Sets the pattern of this Context based on the specified pattern ID. + * + * @param patternId Indicates the resource ID of the pattern to set. + */ +void ContextDeal::SetPattern(int patternId) +{} + +/** + * @brief Obtains the Context object of this ability. + * + * @return Returns the Context object of this ability. + */ +std::shared_ptr ContextDeal::GetAbilityPackageContext() +{ + return nullptr; +} + +/** + * @brief Obtains the HapModuleInfo object of the application. + * + * @return Returns the HapModuleInfo object of the application. + */ +std::shared_ptr ContextDeal::GetHapModuleInfo() +{ + sptr ptr = GetBundleManager(); + if (ptr == nullptr) { + APP_LOGE("GetHapModuleInfo failed to get bundle manager service"); + return nullptr; + } + + if (abilityInfo_ == nullptr) { + APP_LOGE("GetHapModuleInfo failed for abilityInfo_ is nullptr"); + return nullptr; + } + HapModuleInfo hapModuleInfo; + ptr->GetHapModuleInfo(*abilityInfo_.get(), hapModuleInfo); + return std::make_shared(hapModuleInfo); +} + +/** + * @brief Obtains the name of the current process. + * + * @return Returns the current process name. + */ +std::string ContextDeal::GetProcessName() +{ + return (processInfo_ != nullptr) ? processInfo_->GetProcessName() : ""; +} + +/** + * @brief Obtains the bundle name of the ability that called the current ability. + * You can use the obtained bundle name to check whether the calling ability is allowed to receive the data you will + * send. If you did not use Ability.startAbilityForResult(ohos.aafwk.content.Want, int, + * ohos.aafwk.ability.startsetting.AbilityStartSetting) to start the calling ability, null is returned. + * + * @return Returns the bundle name of the calling ability; returns null if no calling ability is available. + */ +std::string ContextDeal::GetCallingBundle() +{ + return ""; +} + +/** + * @brief Requests certain permissions from the system. + * This method is called for permission request. This is an asynchronous method. When it is executed, + * the Ability.onRequestPermissionsFromUserResult(int, String[], int[]) method will be called back. + * + * @param permissions Indicates the list of permissions to be requested. This parameter cannot be null. + * @param requestCode Indicates the request code to be passed to the Ability.onRequestPermissionsFromUserResult(int, + * String[], int[]) callback method. This code cannot be a negative number. + * + */ +void ContextDeal::RequestPermissionsFromUser(std::vector &permissions, int requestCode) +{} + +/** + * @brief Starts a new ability with special ability start setting. + * + * @param want Indicates the Want containing information about the target ability to start. + * @param requestCode Indicates the request code returned after the ability is started. You can define the request code + * to identify the results returned by abilities. The value ranges from 0 to 65535. + * @param abilityStartSetting Indicates the special start setting used in starting ability. + * + */ +void ContextDeal::StartAbility(const Want &want, int requestCode, const AbilityStartSetting &abilityStartSetting) +{} + +/** + * @brief Destroys the current ability. + * + */ +void ContextDeal::TerminateAbility() +{} + +/** + * @brief Connects the current ability to an ability + * + * @param want Indicates the want containing information about the ability to connect + * + * @param conn Indicates the callback object when the target ability is connected. + * + * @return True means success and false means failure + */ +bool ContextDeal::ConnectAbility(const Want &want, const sptr &conn) +{ + return false; +} + +/** + * @brief Disconnects the current ability from an ability + * + * @param conn Indicates the IAbilityConnection callback object passed by connectAbility after the connection + * is set up. The IAbilityConnection object uniquely identifies a connection between two abilities. + */ +void ContextDeal::DisconnectAbility(const sptr &conn) +{} + +sptr ContextDeal::GetToken() +{ + return nullptr; +} + +/** + * @brief init the ResourceManager for ContextDeal. + * + * @param the ResourceManager has been inited. + * + */ +void ContextDeal::initResourceManager(const std::shared_ptr &resourceManager) +{ + resourceManager_ = resourceManager; +} + +/** + * @brief Obtains information about the caller of this ability. + * + * @return Returns the caller information. + */ +Uri ContextDeal::GetCaller() +{ + Uri uri(uriString_); + return uri; +} + +/** + * @brief SerUriString + */ +void ContextDeal::SerUriString(const std::string &uri) +{ + uriString_ = uri; +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/kits/appkit/native/app/src/main.cpp b/kits/appkit/native/app/src/main.cpp new file mode 100644 index 000000000..96355533a --- /dev/null +++ b/kits/appkit/native/app/src/main.cpp @@ -0,0 +1,26 @@ +/* + * 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 "main_thread.h" +#include "app_log_wrapper.h" + +using namespace OHOS; +using namespace OHOS::AppExecFwk; + +int main(const int argc, const char *argv[]) +{ + MainThread::Start(); + return 0; +} diff --git a/kits/appkit/native/app/src/main_thread.cpp b/kits/appkit/native/app/src/main_thread.cpp new file mode 100644 index 000000000..25a80e9e7 --- /dev/null +++ b/kits/appkit/native/app/src/main_thread.cpp @@ -0,0 +1,1147 @@ +/* + * 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 "main_thread.h" +#include +#include "ohos_application.h" +#include "app_loader.h" +#include "application_env_impl.h" +#include "ability_thread.h" +#include "task_handler_client.h" +#include "context_deal.h" +#include "if_system_ability_manager.h" +#include "iservice_registry.h" +#include "resource_manager.h" +#include "sys_mgr_client.h" +#include "system_ability_definition.h" +#include "app_log_wrapper.h" + +#if defined(ABILITY_LIBRARY_LOADER) || defined(APPLICATION_LIBRARY_LOADER) +#include +#include +#endif + +namespace OHOS { +namespace AppExecFwk { +#define ACEABILITY_LIBRARY_LOADER +#ifdef ABILITY_LIBRARY_LOADER +#endif + +/** + * + * @brief Notify the AppMgrDeathRecipient that the remote is dead. + * + * @param remote The remote whitch is dead. + */ +void AppMgrDeathRecipient::OnRemoteDied(const wptr &remote) +{ + APP_LOGE("MainThread::AppMgrDeathRecipient remote died receive"); +} + +MainThread::MainThread() +{ +#ifdef ABILITY_LIBRARY_LOADER + fileEntries_.clear(); + handleAbilityLib_.clear(); +#endif // ABILITY_LIBRARY_LOADER +} + +MainThread::~MainThread() +{ +#ifdef ABILITY_LIBRARY_LOADER + CloseAbilityLibrary(); +#endif // ABILITY_LIBRARY_LOADER +} + +/** + * + * @brief Get the current MainThreadState. + * + * @return Returns the current MainThreadState. + */ +MainThreadState MainThread::GetMainThreadState() const +{ + return mainThreadState_; +} + +/** + * + * @brief Set the runner state of mainthread. + * + * @param runnerStart whether the runner is started. + */ +void MainThread::SetRunnerStarted(bool runnerStart) +{ + isRunnerStarted_ = runnerStart; +} + +/** + * + * @brief Get the runner state of mainthread. + * + * @return Returns the runner state of mainthread. + */ +bool MainThread::GetRunnerStarted() const +{ + return isRunnerStarted_; +} + +/** + * + * @brief Get the newThreadId. + * + * @return Returns the newThreadId. + */ +int MainThread::GetNewThreadId() +{ + return newThreadId_++; +} + +/** + * + * @brief Get the application. + * + * @return Returns the application. + */ +std::shared_ptr MainThread::GetApplication() const +{ + return application_; +} + +/** + * + * @brief Get the applicationInfo. + * + * @return Returns the applicationInfo. + */ +std::shared_ptr MainThread::GetApplicationInfo() const +{ + return applicationInfo_; +} + +/** + * + * @brief Get the applicationImpl. + * + * @return Returns the applicationImpl. + */ +std::shared_ptr MainThread::GetApplicationImpl() +{ + return applicationImpl_; +} + +/** + * + * @brief Connect the mainthread to the AppMgr. + * + */ +bool MainThread::ConnectToAppMgr() +{ + 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"); + return false; + } + deathRecipient_ = new (std::nothrow) AppMgrDeathRecipient(); + if (deathRecipient_ == nullptr) { + APP_LOGE("failed to new AppMgrDeathRecipient"); + return false; + } + + if (!object->AddDeathRecipient(deathRecipient_)) { + APP_LOGE("failed to AddDeathRecipient"); + return false; + } + + appMgr_ = iface_cast(object); + if (appMgr_ == nullptr) { + APP_LOGE("failed to iface_cast object to appMgr_"); + return false; + } + appMgr_->AttachApplication(this); + APP_LOGI("MainThread::connectToAppMgr end"); + return true; +} + +/** + * + * @brief Attach the mainthread to the AppMgr. + * + */ +void MainThread::Attach() +{ + APP_LOGI("MainThread::attach called"); + if (!ConnectToAppMgr()) { + APP_LOGE("attachApplication failed"); + return; + } + mainThreadState_ = MainThreadState::ATTACH; + APP_LOGI("MainThread::attach mainThreadState: %{public}d", mainThreadState_); +} + +/** + * + * @brief remove the deathRecipient from appMgr. + * + */ +void MainThread::RemoveAppMgrDeathRecipient() +{ + APP_LOGD("MainThread::RemoveAppMgrDeathRecipient called"); + if (appMgr_ == nullptr) { + APP_LOGE("MainThread::RemoveAppMgrDeathRecipient failed"); + return; + } + + sptr object = appMgr_->AsObject(); + if (object != nullptr) { + object->RemoveDeathRecipient(deathRecipient_); + } else { + APP_LOGE("appMgr_->AsObject() failed"); + } +} + +/** + * + * @brief Get the eventHandler of mainthread. + * + * @return Returns the eventHandler of mainthread. + */ +std::shared_ptr MainThread::GetMainHandler() const +{ + return mainHandler_; +} + +/** + * + * @brief Schedule the foreground lifecycle of application. + * + */ +void MainThread::ScheduleForegroundApplication() +{ + APP_LOGI("MainThread::scheduleForegroundApplication called"); + auto task = [appThread = this]() { appThread->HandleForegroundApplication(); }; + if (!mainHandler_->PostTask(task)) { + APP_LOGE("PostTask task failed"); + } +} + +/** + * + * @brief Schedule the background lifecycle of application. + * + */ +void MainThread::ScheduleBackgroundApplication() +{ + APP_LOGI("MainThread::scheduleBackgroundApplication called"); + + auto task = [appThread = this]() { appThread->HandleBackgroundApplication(); }; + if (!mainHandler_->PostTask(task)) { + APP_LOGE("MainThread::ScheduleBackgroundApplication PostTask task failed"); + } +} + +/** + * + * @brief Schedule the terminate lifecycle of application. + * + */ +void MainThread::ScheduleTerminateApplication() +{ + APP_LOGI("MainThread::scheduleTerminateApplication called"); + + auto task = [appThread = this]() { appThread->HandleTerminateApplication(); }; + if (!mainHandler_->PostTask(task)) { + APP_LOGE("MainThread::ScheduleTerminateApplication PostTask task failed"); + } +} + +/** + * + * @brief Shrink the memory whitch used by application. + * + * @param level Indicates the memory trim level, which shows the current memory usage status. + */ +void MainThread::ScheduleShrinkMemory(const int level) +{ + APP_LOGI("MainThread::scheduleShrinkMemory level: %{public}d", level); + + auto task = [appThread = this, level]() { appThread->HandleShrinkMemory(level); }; + if (!mainHandler_->PostTask(task)) { + APP_LOGE("MainThread::ScheduleShrinkMemory PostTask task failed"); + } +} + +/** + * + * @brief Schedule the application process exit safely. + * + */ +void MainThread::ScheduleProcessSecurityExit() +{ + APP_LOGI("MainThread::ScheduleProcessSecurityExit called"); + + auto task = [appThread = this]() { appThread->HandleProcessSecurityExit(); }; + if (!mainHandler_->PostTask(task)) { + APP_LOGE("MainThread::ScheduleProcessSecurityExit PostTask task failed"); + } +} + +/** + * + * @brief Low the memory whitch used by application. + * + */ +void MainThread::ScheduleLowMemory() +{ + APP_LOGI("MainThread::scheduleLowMemory called"); +} + +/** + * + * @brief Launch the application. + * + * @param data The launchdata of the application witch launced. + * + */ +void MainThread::ScheduleLaunchApplication(const AppLaunchData &data) +{ + APP_LOGI("MainThread::scheduleLaunchApplication called"); + + auto task = [appThread = this, data]() { appThread->HandleLaunchApplication(data); }; + if (!mainHandler_->PostTask(task)) { + APP_LOGE("MainThread::ScheduleLaunchApplication PostTask task failed"); + } +} + +/** + * + * @brief launch the application. + * + * @param info The launchdata of the application witch launced. + * @param token The launchdata of the application witch launced. + * + */ +void MainThread::ScheduleLaunchAbility(const AbilityInfo &info, const sptr &token) +{ + APP_LOGI("MainThread::scheduleLaunchAbility called"); + APP_LOGI( + "MainThread::scheduleLaunchAbility AbilityInfo name:%{public}s type:%{public}d", info.name.c_str(), info.type); + + std::shared_ptr abilityInfo = std::make_shared(info); + if (abilityInfo == nullptr) { + APP_LOGE("MainThread::ScheduleLaunchAbility abilityInfo is nullptr"); + return; + } + sptr abilityToken = token; + std::shared_ptr abilityRecord = std::make_shared(abilityInfo, abilityToken); + + auto task = [appThread = this, abilityRecord]() { appThread->HandleLaunchAbility(abilityRecord); }; + if (!mainHandler_->PostTask(task)) { + APP_LOGE("MainThread::ScheduleLaunchAbility PostTask task failed"); + } +} + +/** + * + * @brief clean the ability by token. + * + * @param token The token belong to the ability whitch want to be cleaned. + * + */ +void MainThread::ScheduleCleanAbility(const sptr &token) +{ + APP_LOGI("MainThread::scheduleCleanAbility called"); + auto task = [appThread = this, token]() { appThread->HandleCleanAbility(token); }; + if (!mainHandler_->PostTask(task)) { + APP_LOGE("MainThread::ScheduleCleanAbility PostTask task failed"); + } +} + +/** + * + * @brief send the new profile. + * + * @param profile The updated profile. + * + */ +void MainThread::ScheduleProfileChanged(const Profile &profile) +{ + APP_LOGI("MainThread::scheduleProfileChanged profile name: %{public}s", profile.GetName().c_str()); +} + +/** + * + * @brief send the new config to the application. + * + * @param config The updated config. + * + */ +void MainThread::ScheduleConfigurationUpdated(const Configuration &config) +{ + APP_LOGI("MainThread::ScheduleConfigurationUpdated called"); + auto task = [appThread = this, config]() { appThread->HandleConfigurationUpdated(config); }; + if (!mainHandler_->PostTask(task)) { + APP_LOGE("MainThread::ScheduleConfigurationUpdated PostTask task failed"); + } +} + +/** + * + * @brief Check whether the appLaunchData is legal. + * + * @param appLaunchData The appLaunchData should be checked. + * + * @return if the appLaunchData is legal, return true. else return false. + */ +bool MainThread::CheckLaunchApplicationParam(const AppLaunchData &appLaunchData) const +{ + ApplicationInfo appInfo = appLaunchData.GetApplicationInfo(); + ProcessInfo processInfo = appLaunchData.GetProcessInfo(); + + if (appInfo.name.empty()) { + APP_LOGE("MainThread::checkLaunchApplicationParam applicationName is empty"); + return false; + } + + if (processInfo.GetProcessName().empty()) { + APP_LOGE("MainThread::checkLaunchApplicationParam processName is empty"); + return false; + } + + return true; +} + +/** + * + * @brief Check whether the record is legal. + * + * @param record The record should be checked. + * + * @return if the record is legal, return true. else return false. + */ +bool MainThread::CheckAbilityItem(const std::shared_ptr &record) const +{ + if (record == nullptr) { + APP_LOGE("MainThread::checkAbilityItem record is null"); + return false; + } + + std::shared_ptr abilityInfo = record->GetAbilityInfo(); + sptr token = record->GetToken(); + + if (abilityInfo == nullptr) { + APP_LOGE("MainThread::checkAbilityItem abilityInfo is null"); + return false; + } + + if (token == nullptr) { + APP_LOGE("MainThread::checkAbilityItem token is null"); + return false; + } + + return true; +} + +/** + * + * @brief Terminate the application but don't notify ams. + * + */ +void MainThread::HandleTerminateApplicationLocal() +{ + APP_LOGI("MainThread::HandleTerminateApplicationLocal called..."); + if (application_ == nullptr) { + APP_LOGE("MainThread::HandleTerminateApplicationLocal error!"); + return; + } + applicationImpl_->PerformTerminateStrong(); + std::shared_ptr runner = mainHandler_->GetEventRunner(); + if (runner == nullptr) { + APP_LOGE("MainThread::HandleTerminateApplicationLocal get manHandler error"); + return; + } + int ret = runner->Stop(); + if (ret != ERR_OK) { + APP_LOGE("MainThread::HandleTerminateApplicationLocal failed. runner->Run failed ret = %{public}d", ret); + } + APP_LOGI("runner is stopped"); + SetRunnerStarted(false); + +#ifdef ABILITY_LIBRARY_LOADER + CloseAbilityLibrary(); +#endif // ABILITY_LIBRARY_LOADER +#ifdef APPLICATION_LIBRARY_LOADER + if (handleAppLib_ != nullptr) { + dlclose(handleAppLib_); + handleAppLib_ = nullptr; + } +#endif // APPLICATION_LIBRARY_LOADER +} + +/** + * + * @brief Schedule the application process exit safely. + * + */ +void MainThread::HandleProcessSecurityExit() +{ + APP_LOGI("MainThread::HandleProcessSecurityExit called"); + if (abilityRecordMgr_ == nullptr) { + APP_LOGE("MainThread::HandleProcessSecurityExit abilityRecordMgr_ is null"); + return; + } + + std::vector> tokens = (abilityRecordMgr_->GetAllTokens()); + + for (auto iter = tokens.begin(); iter != tokens.end(); ++iter) { + HandleCleanAbilityLocal(*iter); + } + + HandleTerminateApplicationLocal(); +} + +/** + * + * @brief Launch the application. + * + * @param appLaunchData The launchdata of the application witch launced. + * + */ +void MainThread::HandleLaunchApplication(const AppLaunchData &appLaunchData) +{ + APP_LOGI("MainThread::handleLaunchApplication called"); + if (application_ != nullptr) { + APP_LOGE("MainThread::handleLaunchApplication already create application"); + return; + } + + if (!CheckLaunchApplicationParam(appLaunchData)) { + APP_LOGE("MainThread::handleLaunchApplication appLaunchData invalid"); + return; + } + +#ifdef ABILITY_LIBRARY_LOADER + LoadAbilityLibrary(appLaunchData.GetApplicationInfo().moduleSourceDirs); +#endif // ABILITY_LIBRARY_LOADER +#ifdef APPLICATION_LIBRARY_LOADER + std::string appPath = applicationLibraryPath; + 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); + } +#endif // APPLICATION_LIBRARY_LOADER + + ApplicationInfo appInfo = appLaunchData.GetApplicationInfo(); + ProcessInfo processInfo = appLaunchData.GetProcessInfo(); + Profile appProfile = appLaunchData.GetProfile(); + + applicationInfo_ = std::make_shared(appInfo); + if (applicationInfo_ == nullptr) { + APP_LOGE("MainThread::handleLaunchApplication create applicationInfo_ failed"); + return; + } + + processInfo_ = std::make_shared(processInfo); + if (processInfo_ == nullptr) { + APP_LOGE("MainThread::handleLaunchApplication create processInfo_ failed"); + return; + } + + appProfile_ = std::make_shared(appProfile); + if (appProfile_ == nullptr) { + APP_LOGE("MainThread::handleLaunchApplication create appProfile_ failed"); + return; + } + + applicationImpl_ = std::make_shared(); + if (applicationImpl_ == nullptr) { + APP_LOGE("MainThread::handleLaunchApplication create applicationImpl_ failed"); + return; + } + + std::shared_ptr contextDeal = std::make_shared(); + if (contextDeal == nullptr) { + APP_LOGE("MainThread::handleLaunchApplication create contextDeal failed"); + return; + } + + contextDeal->SetProcessInfo(processInfo_); + contextDeal->SetApplicationInfo(applicationInfo_); + contextDeal->SetProfile(appProfile_); + contextDeal->SetBundleCodePath(applicationInfo_->codePath); // BMS need to add cpath + + // BMS should set the type (native or ace) of application + bool isNativeApp = true; + std::string appName = isNativeApp ? appInfo.name : aceApplicationName_; + application_ = std::shared_ptr(ApplicationLoader::GetInstance().GetApplicationByName(appName)); + if (application_ == nullptr) { + APP_LOGE("HandleLaunchApplication::application launch failed"); + return; + } + + // init resourceManager. + std::shared_ptr resourceManager(Global::Resource::CreateResourceManager()); + if (resourceManager == nullptr) { + APP_LOGE("MainThread::handleLaunchApplication create resourceManager failed"); + return; + } + + sptr bundleMgr = contextDeal->GetBundleManager(); + if (bundleMgr == nullptr) { + APP_LOGE("MainThread::handleLaunchApplication GetBundleManager is nullptr"); + return; + } + + BundleInfo bundleInfo; + APP_LOGI("MainThread::handleLaunchApplication length: %{public}d, bundleName: %{public}s", + appInfo.bundleName.length(), + appInfo.bundleName.c_str()); + bundleMgr->GetBundleInfo(appInfo.bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); + + APP_LOGI("MainThread::handleLaunchApplication moduleResPaths count: %{public}d", bundleInfo.moduleResPaths.size()); + for (auto moduleResPath : bundleInfo.moduleResPaths) { + if (!moduleResPath.empty()) { + APP_LOGI("MainThread::handleLaunchApplication length: %{public}d, moduleResPath: %{public}s", + moduleResPath.length(), + moduleResPath.c_str()); + if (!resourceManager->AddResource(moduleResPath.c_str())) { + APP_LOGE("MainThread::handleLaunchApplication AddResource failed"); + } + } + } + + std::unique_ptr resConfig(Global::Resource::CreateResConfig()); + resConfig->SetLocaleInfo("zh", "Hans", "CN"); + const Global::Resource::LocaleInfo *localeInfo = resConfig->GetLocaleInfo(); + if (localeInfo != nullptr) { + APP_LOGI("MainThread::handleLaunchApplication language: %{public}s, script: %{public}s, region: %{public}s,", + localeInfo->GetLanguage(), + localeInfo->GetScript(), + localeInfo->GetRegion()); + } else { + APP_LOGI("MainThread::handleLaunchApplication localeInfo is nullptr."); + } + + resourceManager->UpdateResConfig(*resConfig); + contextDeal->initResourceManager(resourceManager); + contextDeal->SetApplicationContext(application_); + application_->AttachBaseContext(contextDeal); + + abilityRecordMgr_ = std::make_shared(); + if (abilityRecordMgr_ == nullptr) { + APP_LOGE("HandleLaunchApplication::application create AbilityRecordMgr failed"); + return; + } + + application_->SetAbilityRecordMgr(abilityRecordMgr_); + + applicationImpl_->SetRecordId(appLaunchData.GetRecordId()); + applicationImpl_->SetApplication(application_); + mainThreadState_ = MainThreadState::READY; + if (!applicationImpl_->PerformAppReady()) { + APP_LOGE("HandleLaunchApplication::application applicationImpl_->PerformAppReady failed"); + return; + } + + // L1 needs to add corresponding interface + ApplicationEnvImpl *pAppEvnIml = ApplicationEnvImpl::GetInstance(); + + if (pAppEvnIml) { + pAppEvnIml->SetAppInfo(*applicationInfo_.get()); + } +} + +/** + * + * @brief launch the ability. + * + * @param abilityRecord The abilityRecord whitch belongs to the ability launched. + * + */ +void MainThread::HandleLaunchAbility(const std::shared_ptr &abilityRecord) +{ + APP_LOGI("MainThread::handleLaunchAbility called"); + + if (applicationImpl_ == nullptr) { + APP_LOGE("MainThread::ScheduleLaunchAbility applicationImpl_ is null"); + return; + } + + if (abilityRecordMgr_ == nullptr) { + APP_LOGE("MainThread::ScheduleLaunchAbility abilityRecordMgr_ is null"); + return; + } + + if (abilityRecord == nullptr) { + APP_LOGE("MainThread::ScheduleLaunchAbility parameter(abilityRecord) is null"); + return; + } + + auto abilityToken = abilityRecord->GetToken(); + if (abilityToken == nullptr) { + APP_LOGE("MainThread::ScheduleLaunchAbility failed. abilityRecord->GetToken failed"); + return; + } + + abilityRecordMgr_->SetToken(abilityToken); + abilityRecordMgr_->AddAbilityRecord(abilityToken, abilityRecord); + + if (!IsApplicationReady()) { + APP_LOGE("MainThread::handleLaunchAbility not init OHOSApplication, should launch application first"); + return; + } + + if (!CheckAbilityItem(abilityRecord)) { + APP_LOGE("MainThread::handleLaunchAbility record is invalid"); + return; + } + + mainThreadState_ = MainThreadState::RUNNING; +#ifdef APP_ABILITY_USE_TWO_RUNNER + AbilityThread::AbilityThreadMain(application_, abilityRecord); +#else + AbilityThread::AbilityThreadMain(application_, abilityRecord, mainHandler_->GetEventRunner()); +#endif +} + +/** + * + * @brief Clean the ability but don't notify ams. + * + * @param token The token whitch belongs to the ability launched. + * + */ +void MainThread::HandleCleanAbilityLocal(const sptr &token) +{ + APP_LOGI("MainThread::HandleCleanAbilityLocal called"); + if (!IsApplicationReady()) { + APP_LOGE("MainThread::HandleCleanAbilityLocal not init OHOSApplication, should launch application first"); + return; + } + + if (token == nullptr) { + APP_LOGE("MainThread::HandleCleanAbilityLocal token is null"); + return; + } + + std::shared_ptr record = abilityRecordMgr_->GetAbilityItem(token); + if (record == nullptr) { + APP_LOGE("MainThread::HandleCleanAbilityLocal abilityRecord not found"); + return; + } + std::shared_ptr abilityInfo = record->GetAbilityInfo(); + if (abilityInfo == nullptr) { + APP_LOGE("MainThread::HandleCleanAbilityLocal record->GetAbilityInfo() failed"); + return; + } + APP_LOGI("MainThread::HandleCleanAbilityLocal ability name: %{public}s", abilityInfo->name.c_str()); + + abilityRecordMgr_->RemoveAbilityRecord(token); + +#ifdef APP_ABILITY_USE_TWO_RUNNER + std::shared_ptr runner = record->GetEventRunner(); + + if (runner != nullptr) { + int ret = runner->Stop(); + if (ret != ERR_OK) { + APP_LOGE("MainThread::main failed. ability runner->Run failed ret = %{public}d", ret); + } + abilityRecordMgr_->RemoveAbilityRecord(token); + } else { + APP_LOGW("MainThread::HandleCleanAbilityLocal runner not found"); + } +#endif +} + +/** + * + * @brief Clean the ability. + * + * @param token The token whitch belongs to the ability launched. + * + */ +void MainThread::HandleCleanAbility(const sptr &token) +{ + APP_LOGI("MainThread::handleCleanAbility called"); + if (!IsApplicationReady()) { + APP_LOGE("MainThread::handleCleanAbility not init OHOSApplication, should launch application first"); + return; + } + + if (token == nullptr) { + APP_LOGE("MainThread::handleCleanAbility token is null"); + return; + } + + std::shared_ptr record = abilityRecordMgr_->GetAbilityItem(token); + if (record == nullptr) { + APP_LOGE("MainThread::handleCleanAbility abilityRecord not found"); + return; + } + std::shared_ptr abilityInfo = record->GetAbilityInfo(); + if (abilityInfo == nullptr) { + APP_LOGE("MainThread::handleCleanAbility record->GetAbilityInfo() failed"); + return; + } + APP_LOGI("MainThread::handleCleanAbility ability name: %{public}s", abilityInfo->name.c_str()); + + abilityRecordMgr_->RemoveAbilityRecord(token); + +#ifdef APP_ABILITY_USE_TWO_RUNNER + std::shared_ptr runner = record->GetEventRunner(); + + if (runner != nullptr) { + int ret = runner->Stop(); + if (ret != ERR_OK) { + APP_LOGE("MainThread::main failed. ability runner->Run failed ret = %{public}d", ret); + } + abilityRecordMgr_->RemoveAbilityRecord(token); + } else { + APP_LOGW("MainThread::handleCleanAbility runner not found"); + } +#endif + appMgr_->AbilityCleaned(token); +} + +/** + * + * @brief Foreground the application. + * + */ +void MainThread::HandleForegroundApplication() +{ + APP_LOGI("MainThread::handleForegroundApplication called..."); + if ((application_ == nullptr) || (appMgr_ == nullptr)) { + APP_LOGE("MainThread::handleForegroundApplication error!"); + return; + } + + if (!applicationImpl_->PerformForeground()) { + APP_LOGE("MainThread::handleForegroundApplication error!, applicationImpl_->PerformForeground() failed"); + return; + } + + appMgr_->ApplicationForegrounded(applicationImpl_->GetRecordId()); +} + +/** + * + * @brief Background the application. + * + */ +void MainThread::HandleBackgroundApplication() +{ + APP_LOGI("MainThread::handleBackgroundApplication called..."); + + if ((application_ == nullptr) || (appMgr_ == nullptr)) { + APP_LOGE("MainThread::handleBackgroundApplication error!"); + return; + } + + if (!applicationImpl_->PerformBackground()) { + APP_LOGE("MainThread::handleForegroundApplication error!, applicationImpl_->PerformBackground() failed"); + return; + } + + appMgr_->ApplicationBackgrounded(applicationImpl_->GetRecordId()); +} + +/** + * + * @brief Terminate the application. + * + */ +void MainThread::HandleTerminateApplication() +{ + APP_LOGI("MainThread::handleTerminateApplication called..."); + if ((application_ == nullptr) || (appMgr_ == nullptr)) { + APP_LOGE("MainThread::handleTerminateApplication error!"); + return; + } + + if (!applicationImpl_->PerformTerminate()) { + APP_LOGE("MainThread::handleForegroundApplication error!, applicationImpl_->PerformTerminate() failed"); + return; + } + + appMgr_->ApplicationTerminated(applicationImpl_->GetRecordId()); + std::shared_ptr runner = mainHandler_->GetEventRunner(); + if (runner == nullptr) { + APP_LOGE("MainThread::handleTerminateApplication get manHandler error"); + return; + } + int ret = runner->Stop(); + if (ret != ERR_OK) { + APP_LOGE("MainThread::handleTerminateApplication failed. runner->Run failed ret = %{public}d", ret); + } + SetRunnerStarted(false); + +#ifdef ABILITY_LIBRARY_LOADER + CloseAbilityLibrary(); +#endif // ABILITY_LIBRARY_LOADER +#ifdef APPLICATION_LIBRARY_LOADER + if (handleAppLib_ != nullptr) { + dlclose(handleAppLib_); + handleAppLib_ = nullptr; + } +#endif // APPLICATION_LIBRARY_LOADER +} + +/** + * + * @brief Shrink the memory whitch used by application. + * + * @param level Indicates the memory trim level, which shows the current memory usage status. + * + */ +void MainThread::HandleShrinkMemory(const int level) +{ + APP_LOGI("MainThread::HandleShrinkMemory called..."); + + if (applicationImpl_ == nullptr) { + APP_LOGE("MainThread::HandleShrinkMemory error! applicationImpl_ is null"); + return; + } + + applicationImpl_->PerformMemoryLevel(level); +} + +/** + * + * @brief send the new config to the application. + * + * @param config The updated config. + * + */ +void MainThread::HandleConfigurationUpdated(const Configuration &config) +{ + APP_LOGI("MainThread::HandleConfigurationUpdated called..."); + + if (applicationImpl_ == nullptr) { + APP_LOGE("MainThread::HandleConfigurationUpdated error! applicationImpl_ is null"); + return; + } + + applicationImpl_->PerformConfigurationUpdated(config); +} + +void MainThread::Init(const std::shared_ptr &runner) +{ + mainHandler_ = std::make_shared(runner, this); + auto task = [appThread = this]() { + APP_LOGI("MainThread:MainHandler Start"); + appThread->SetRunnerStarted(true); + }; + if (!mainHandler_->PostTask(task)) { + APP_LOGE("MainThread::Init PostTask task failed"); + } + + TaskHandlerClient::GetInstance()->CreateRunner(); +} + +void MainThread::Start() +{ + APP_LOGI("MainThread::main called start"); + std::shared_ptr runner = EventRunner::GetMainEventRunner(); + if (runner == nullptr) { + APP_LOGE("MainThread::main called start"); + return; + } + sptr thread = sptr(new (std::nothrow) MainThread()); + if (thread == nullptr) { + APP_LOGE("MainThread::static failed. new MainThread failed"); + return; + } + + thread->Init(runner); + thread->Attach(); + + int ret = runner->Run(); + if (ret != ERR_OK) { + APP_LOGE("MainThread::main failed. runner->Run failed ret = %{public}d", ret); + } + + thread->RemoveAppMgrDeathRecipient(); + APP_LOGW("MainThread::main runner stopped"); +} + +MainThread::MainHandler::MainHandler(const std::shared_ptr &runner, const sptr &thread) + : AppExecFwk::EventHandler(runner), mainThreadObj_(thread) +{} + +/** + * + * @brief Process the event. + * + * @param event the event want to be processed. + * + */ +void MainThread::MainHandler::ProcessEvent(const OHOS::AppExecFwk::InnerEvent::Pointer &event) +{} + +/** + * + * @brief Check whether the OHOSApplication is ready. + * + * @return if the record is legal, return true. else return false. + * + */ +bool MainThread::IsApplicationReady() const +{ + if (application_ == nullptr || applicationImpl_ == nullptr) { + return false; + } + + return true; +} + +#ifdef ABILITY_LIBRARY_LOADER +/** + * + * @brief Load the ability library. + * + * @param libraryPaths the library paths. + * + */ +void MainThread::LoadAbilityLibrary(const std::vector &libraryPaths) +{ +#ifdef ACEABILITY_LIBRARY_LOADER + std::string acelibdir("/system/lib/libace.z.so"); + void *AceAbilityLib = nullptr; + 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()); + } else { + APP_LOGI("Success to dlopen %{public}s", acelibdir.c_str()); + handleAbilityLib_.emplace_back(AceAbilityLib); + } +#endif // ACEABILITY_LIBRARY_LOADER + int size = libraryPaths.size(); + for (int index = 0; index < size; index++) { + std::string libraryPath = libraryPaths[index]; + if (!ScanDir(libraryPath)) { + APP_LOGE("Fail to scanDir %{public}s", libraryPath.c_str()); + continue; + } + } + + if (fileEntries_.empty()) { + APP_LOGE("No ability library"); + return; + } + + void *handleAbilityLib = nullptr; + for (auto fileEntry : fileEntries_) { + if (!fileEntry.empty()) { + handleAbilityLib = dlopen(fileEntry.c_str(), RTLD_NOW | RTLD_GLOBAL); + if (handleAbilityLib == nullptr) { + APP_LOGE("Fail to dlopen %{public}s, [%{public}s]", fileEntry.c_str(), dlerror()); + exit(-1); + } else { + APP_LOGI("Success to dlopen %{public}s", fileEntry.c_str()); + } + handleAbilityLib_.emplace_back(handleAbilityLib); + } + } +} + +/** + * + * @brief Close the ability library loaded. + * + */ +void MainThread::CloseAbilityLibrary() +{ + for (auto iter : handleAbilityLib_) { + if (iter != nullptr) { + dlclose(iter); + iter = nullptr; + } + } + handleAbilityLib_.clear(); + fileEntries_.clear(); +} + +/** + * + * @brief Scan the dir ability library loaded. + * + * @param dirPath the the path should be scan. + * + */ +bool MainThread::ScanDir(const std::string &dirPath) +{ + DIR *dirp = opendir(dirPath.c_str()); + if (dirp == nullptr) { + APP_LOGE("MainThread::ScanDir open dir:%{private}s fail", dirPath.c_str()); + return false; + } + + struct dirent *df = nullptr; + for (;;) { + df = readdir(dirp); + if (df == nullptr) { + break; + } + + std::string currentName(df->d_name); + APP_LOGD("folder found:'%{private}s'", df->d_name); + if (currentName.compare(".") == 0 || currentName.compare("..") == 0) { + continue; + } + + if (CheckFileType(currentName, abilityLibraryType_)) { + fileEntries_.emplace_back(dirPath + pathSeparator_ + currentName); + } + } + + if (closedir(dirp) == -1) { + APP_LOGW("close dir fail"); + } + return true; +} + +/** + * + * @brief Check the fileType. + * + * @param fileName The fileName of the lib. + * @param extensionName The extensionName of the lib. + * + * @return if the FileType is legal, return true. else return false. + * + */ +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()); + if (fileName.empty()) { + APP_LOGE("the file name is empty"); + return false; + } + + auto position = fileName.rfind('.'); + if (position == std::string::npos) { + APP_LOGE("filename no extension name"); + return false; + } + + std::string suffixStr = fileName.substr(position); + return LowerStr(suffixStr) == extensionName; +} +#endif // ABILITY_LIBRARY_LOADER +} // namespace AppExecFwk +} // namespace OHOS diff --git a/kits/appkit/native/app/src/ohos_application.cpp b/kits/appkit/native/app/src/ohos_application.cpp new file mode 100644 index 000000000..dd11ac95d --- /dev/null +++ b/kits/appkit/native/app/src/ohos_application.cpp @@ -0,0 +1,393 @@ +/* + * 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 "ohos_application.h" +#include "application_impl.h" +#include "ability_record_mgr.h" +#include "app_loader.h" +#include "app_log_wrapper.h" +#include "iservice_registry.h" +#include "system_ability_definition.h" + +namespace OHOS { +namespace AppExecFwk { + +REGISTER_APPLICATION(OHOSApplication, OHOSApplication) + +OHOSApplication::OHOSApplication() +{ + abilityLifecycleCallbacks_.clear(); + elementsCallbacks_.clear(); +} + +/** + * + * @brief Called when Ability#onSaveAbilityState(PacMap) was called on an ability. + * + * @param outState Indicates the PacMap object passed to Ability#onSaveAbilityState(PacMap) + * for storing user data and states. This parameter cannot be null. + */ + +void OHOSApplication::DispatchAbilitySavedState(const PacMap &outState) +{ + APP_LOGI("OHOSApplication::dispatchAbilitySavedState: called"); + for (auto callback : abilityLifecycleCallbacks_) { + if (callback != nullptr) { + callback->OnAbilitySaveState(outState); + } + } +} + +/** + * + * @brief Will be called the application foregrounds + * + */ +void OHOSApplication::OnForeground() +{} + +/** + * + * @brief Will be called the application backgrounds + * + */ +void OHOSApplication::OnBackground() +{} + +void OHOSApplication::DumpApplication() +{ + APP_LOGD("OHOSApplication::Dump called"); + // create and initialize abilityInfos + std::shared_ptr abilityInfo = nullptr; + std::shared_ptr record = nullptr; + + if (abilityRecordMgr_) { + record = abilityRecordMgr_->GetAbilityItem(abilityRecordMgr_->GetToken()); + } + + if (record) { + abilityInfo = record->GetAbilityInfo(); + } + + if (abilityInfo) { + APP_LOGD("==============AbilityInfo=============="); + APP_LOGD("abilityInfo: package: %{public}s", abilityInfo->package.c_str()); + APP_LOGD("abilityInfo: name: %{public}s", abilityInfo->name.c_str()); + APP_LOGD("abilityInfo: label: %{public}s", abilityInfo->label.c_str()); + APP_LOGD("abilityInfo: description: %{public}s", abilityInfo->description.c_str()); + APP_LOGD("abilityInfo: iconPath: %{public}s", abilityInfo->iconPath.c_str()); + APP_LOGD("abilityInfo: visible: %{public}d", abilityInfo->visible); + APP_LOGD("abilityInfo: kind: %{public}s", abilityInfo->kind.c_str()); + APP_LOGD("abilityInfo: type: %{public}d", abilityInfo->type); + APP_LOGD("abilityInfo: orientation: %{public}d", abilityInfo->orientation); + APP_LOGD("abilityInfo: launchMode: %{public}d", abilityInfo->launchMode); + for (auto permission : abilityInfo->permissions) { + APP_LOGD("abilityInfo: permission: %{public}s", permission.c_str()); + } + APP_LOGD("abilityInfo: bundleName: %{public}s", abilityInfo->bundleName.c_str()); + APP_LOGD("abilityInfo: applicationName: %{public}s", abilityInfo->applicationName.c_str()); + } + + // create and initialize applicationInfo + APP_LOGD("==============applicationInfo=============="); + std::shared_ptr applicationInfoPtr = GetApplicationInfo(); + if (applicationInfoPtr != nullptr) { + APP_LOGD("applicationInfo: name: %{public}s", applicationInfoPtr->name.c_str()); + APP_LOGD("applicationInfo: bundleName: %{public}s", applicationInfoPtr->bundleName.c_str()); + APP_LOGD("applicationInfo: signatureKey: %{public}s", applicationInfoPtr->signatureKey.c_str()); + } +} + +/** + * + * @brief Set the abilityRecordMgr to the OHOSApplication. + * + * @param abilityRecordMgr + */ +void OHOSApplication::SetAbilityRecordMgr(const std::shared_ptr &abilityRecordMgr) +{ + if (abilityRecordMgr == nullptr) { + APP_LOGE("ContextDeal::SetAbilityRecordMgr failed, abilityRecordMgr is nullptr"); + return; + } + abilityRecordMgr_ = abilityRecordMgr; +} + +/** + * + * Register AbilityLifecycleCallbacks with OHOSApplication + * + * @param callBack callBack When the life cycle of the ability in the application changes, + */ +void OHOSApplication::RegisterAbilityLifecycleCallbacks(const std::shared_ptr &callBack) +{ + APP_LOGI("OHOSApplication::RegisterAbilityLifecycleCallbacks: called"); + + if (callBack == nullptr) { + APP_LOGI("OHOSApplication::RegisterAbilityLifecycleCallbacks: observer is null"); + return; + } + + abilityLifecycleCallbacks_.emplace_back(callBack); +} + +/** + * + * Unregister AbilityLifecycleCallbacks with OHOSApplication + * + * @param callBack RegisterAbilityLifecycleCallbacks`s callBack + */ +void OHOSApplication::UnregisterAbilityLifecycleCallbacks(const std::shared_ptr &callBack) +{ + APP_LOGI("OHOSApplication::UnregisterAbilityLifecycleCallbacks: called"); + + if (callBack == nullptr) { + APP_LOGI("OHOSApplication::UnregisterAbilityLifecycleCallbacks: observer is null"); + return; + } + + abilityLifecycleCallbacks_.remove(callBack); +} + +/** + * + * Will be called when the given ability calls Ability->onStart + * + * @param Ability Indicates the ability object that calls the onStart() method. + */ +void OHOSApplication::OnAbilityStart(const std::shared_ptr &ability) +{ + if (ability == nullptr) { + APP_LOGE("ContextDeal::OnAbilityStart failed, ability is nullptr"); + return; + } + + APP_LOGI("OHOSApplication::OnAbilityStart: called"); + for (auto callback : abilityLifecycleCallbacks_) { + if (callback != nullptr) { + callback->OnAbilityStart(ability); + } + } +} + +/** + * + * Will be called when the given ability calls Ability->onInactive + * + * @param Ability Indicates the Ability object that calls the onInactive() method. + */ +void OHOSApplication::OnAbilityInactive(const std::shared_ptr &ability) +{ + if (ability == nullptr) { + APP_LOGE("ContextDeal::OnAbilityInactive failed, ability is nullptr"); + return; + } + + APP_LOGI("OHOSApplication::OnAbilityInactive: called"); + for (auto callback : abilityLifecycleCallbacks_) { + if (callback != nullptr) { + callback->OnAbilityInactive(ability); + } + } +} + +/** + * + * Will be called when the given ability calls Ability->onBackground + * + * @param Ability Indicates the Ability object that calls the onBackground() method. + */ +void OHOSApplication::OnAbilityBackground(const std::shared_ptr &ability) +{ + if (ability == nullptr) { + APP_LOGE("ContextDeal::OnAbilityBackground failed, ability is nullptr"); + return; + } + + APP_LOGI("OHOSApplication::OnAbilityBackground: called"); + for (auto callback : abilityLifecycleCallbacks_) { + if (callback != nullptr) { + callback->OnAbilityBackground(ability); + } + } +} + +/** + * + * Will be called when the given ability calls Ability->onForeground + * + * @param Ability Indicates the Ability object that calls the onForeground() method. + */ +void OHOSApplication::OnAbilityForeground(const std::shared_ptr &ability) +{ + if (ability == nullptr) { + APP_LOGE("ContextDeal::OnAbilityForeground failed, ability is nullptr"); + return; + } + + APP_LOGI("OHOSApplication::OnAbilityForeground: called"); + for (auto callback : abilityLifecycleCallbacks_) { + if (callback != nullptr) { + callback->OnAbilityForeground(ability); + } + } +} + +/** + * + * Will be called when the given ability calls Ability->onActive + * + * @param Ability Indicates the Ability object that calls the onActive() method. + */ +void OHOSApplication::OnAbilityActive(const std::shared_ptr &ability) +{ + if (ability == nullptr) { + APP_LOGE("ContextDeal::OnAbilityActive failed, ability is nullptr"); + return; + } + + APP_LOGI("OHOSApplication::OnAbilityActive: called"); + for (auto callback : abilityLifecycleCallbacks_) { + if (callback != nullptr) { + callback->OnAbilityActive(ability); + } + } +} + +/** + * + * Will be called when the given ability calls Ability->onStop + * + * @param Ability Indicates the Ability object that calls the onStop() method. + */ +void OHOSApplication::OnAbilityStop(const std::shared_ptr &ability) +{ + if (ability == nullptr) { + APP_LOGE("ContextDeal::OnAbilityStop failed, ability is nullptr"); + return; + } + + APP_LOGI("OHOSApplication::OnAbilityStop: called"); + for (auto callback : abilityLifecycleCallbacks_) { + if (callback != nullptr) { + callback->OnAbilityStop(ability); + } + } +} + +/** + * + * @brief Register ElementsCallback with OHOSApplication + * + * @param callBack callBack when the system configuration of the device changes. + */ +void OHOSApplication::RegisterElementsCallbacks(const std::shared_ptr &callback) +{ + APP_LOGI("OHOSApplication::RegisterElementsCallbacks: called"); + + if (callback == nullptr) { + APP_LOGI("OHOSApplication::RegisterElementsCallbacks: observer is null"); + return; + } + + elementsCallbacks_.emplace_back(callback); +} + +/** + * + * @brief Unregister ElementsCallback with OHOSApplication + * + * @param callback RegisterElementsCallbacks`s callback + */ +void OHOSApplication::UnregisterElementsCallbacks(const std::shared_ptr &callback) +{ + APP_LOGI("OHOSApplication::UnregisterElementsCallbacks: called"); + + if (callback == nullptr) { + APP_LOGI("OHOSApplication::UnregisterElementsCallbacks: observer is null"); + return; + } + + elementsCallbacks_.remove(callback); +} + +/** + * + * @brief Will be Called when the system configuration of the device changes. + * + * @param config Indicates the new Configuration object. + */ +void OHOSApplication::OnConfigurationUpdated(const Configuration &config) +{ + APP_LOGI("OHOSApplication::OnConfigurationUpdated: called"); + for (auto callback : elementsCallbacks_) { + if (callback != nullptr) { + callback->OnConfigurationUpdated(nullptr, config); + } + } +} + +/** + * + * @brief Called when the system has determined to trim the memory, for example, + * when the ability is running in the background and there is no enough memory for + * running as many background processes as possible. + * + * @param level Indicates the memory trim level, which shows the current memory usage status. + */ +void OHOSApplication::OnMemoryLevel(int level) +{ + APP_LOGI("OHOSApplication::OnMemoryLevel: called"); + for (auto callback : elementsCallbacks_) { + if (callback != nullptr) { + callback->OnMemoryLevel(level); + } + } +} + +/** + * + * @brief Will be called the application starts + * + */ +void OHOSApplication::OnStart() +{ + APP_LOGI("OHOSApplication::OnStart: called"); +} + +/** + * + * @brief Will be called the application ends + * + */ +void OHOSApplication::OnTerminate() +{ + APP_LOGI("OHOSApplication::OnTerminate: called"); +} + +/** + * + * @brief Called when an ability calls Ability#onSaveAbilityState(PacMap). + * You can implement your own logic in this method. + * @param outState IIndicates the {@link PacMap} object passed to the onSaveAbilityState() callback. + * + */ +void OHOSApplication::OnAbilitySaveState(const PacMap &outState) +{ + DispatchAbilitySavedState(outState); +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/kits/appkit/native/app/src/sys_mgr_client.cpp b/kits/appkit/native/app/src/sys_mgr_client.cpp new file mode 100644 index 000000000..6735b563c --- /dev/null +++ b/kits/appkit/native/app/src/sys_mgr_client.cpp @@ -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. + */ + +#include "sys_mgr_client.h" + +#include "app_log_wrapper.h" +#include "if_system_ability_manager.h" +#include "iservice_registry.h" +#include "ipc_skeleton.h" +#include "string_ex.h" + +namespace OHOS { +namespace AppExecFwk { + +SysMrgClient::SysMrgClient() : abilityManager_(nullptr) +{} + +SysMrgClient::~SysMrgClient() +{} + +/** + * + * Get the systemAbility by ID. + * + * @param systemAbilityId The ID of systemAbility which want to get. + */ +sptr SysMrgClient::GetSystemAbility(const int32_t systemAbilityId) +{ + // use single instance of abilityManager_ + if (abilityManager_ == nullptr) { + std::lock_guard lock(saMutex_); + if (abilityManager_ == nullptr) { + abilityManager_ = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (abilityManager_ == nullptr) { + APP_LOGE("fail to GetSystemAbility abilityManager_ == nullptr."); + return nullptr; + } + } + } + return abilityManager_->GetSystemAbility(systemAbilityId); +} + +/** + * + * Register the systemAbility by ID. + * + * @param systemAbilityId The ID of systemAbility which want to register. + * @param broker The systemAbility which want to be registered. + */ +void SysMrgClient::RegisterSystemAbility( + const int32_t __attribute__((unused)) systemAbilityId, sptr __attribute__((unused)) broker) +{ + (void)servicesMap_; +} + +/** + * + * Unregister the systemAbility by ID. + * + * @param systemAbilityId The ID of systemAbility which want to unregister. + */ +void SysMrgClient::UnregisterSystemAbility(const int32_t systemAbilityId) +{} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/kits/appkit/native/test/BUILD.gn b/kits/appkit/native/test/BUILD.gn new file mode 100644 index 000000000..ff71e4590 --- /dev/null +++ b/kits/appkit/native/test/BUILD.gn @@ -0,0 +1,208 @@ +# 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") + +module_output_path = "appexecfwk_standard/application_test" + +#APP_INNERKITS_PATH = "//foundation/appexecfwk/standard/interfaces/innerkits" +ABILITY_INNERKITS_PATH = "//foundation/aafwk/standard/interfaces/innerkits" + +############################################################################### +config("module_private_config") { + visibility = [ ":*" ] + include_dirs = [ + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/appmgr", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/bundlemgr", + "//foundation/aafwk/standard/interfaces/innerkits/want/include/ohos/aafwk_L2/content", + "//EOSP/communication/libsoftbus/../../../foundation/distributedschedule/dmsfwk/services/dtbschedmgr/include", + "//foundation/aafwk/standard/interfaces/innerkits/want/include/ohos/aafwk_L2/content", + "//foundation/appexecfwk/standard/kits/appkit/native/test/mock/include", + "//foundation/aafwk/standard/frameworks/kits/ability/native/test/mock/include", + "//foundation/aafwk/standard/frameworks/kits/ability/native/include", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + defines = [ + "APP_LOG_TAG = \"ApplicationUnitTest\"", + "LOG_DOMAIN = 0xD001151", + ] +} + +config("module_context_config") { + visibility = [ ":*" ] + include_dirs = [ + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/appmgr", + "//foundation/aafwk/standard/interfaces/innerkits/want/include/ohos/aafwk_L2/content", + "//EOSP/communication/libsoftbus/../../../foundation/distributedschedule/dmsfwk/services/dtbschedmgr/include", + "//foundation/aafwk/standard/interfaces/innerkits/want/include/ohos/aafwk_L2/content", + "//foundation/appexecfwk/standard/kits/appkit/native/test/mock/include", + "//foundation/aafwk/standard/frameworks/kits/ability/native/test/mock/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/bundlemgr", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + defines = [ + "APP_LOG_TAG = \"ApplicationUnitTest\"", + "LOG_DOMAIN = 0xD001151", + ] +} + +ohos_unittest("application_test") { + module_out_path = module_output_path + sources = [ + "../app/src/ohos_application.cpp", + "//foundation/appexecfwk/standard/kits/appkit/native/app/src/app_loader.cpp", + "//foundation/appexecfwk/standard/kits/appkit/native/app/src/application_context.cpp", + "unittest/application_test.cpp", + ] + + configs = [ ":module_private_config" ] + + deps = [ + "${ABILITY_INNERKITS_PATH}/want:want", + "//foundation/aafwk/standard/frameworks/kits/ability/native:abilitykit_native", + "//foundation/aafwk/standard/interfaces/innerkits/ability_manager:ability_manager", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/appexecfwk/standard/common:libappexecfwk_common", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "//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/googletest:gtest_main", + "//utils/native/base:utils", + + #"//foundation/appexecfwk/standard/kits:appkit_native", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +ohos_unittest("context_container_test") { + module_out_path = module_output_path + sources = [ + "../app/src/ohos_application.cpp", + "//foundation/aafwk/standard/frameworks/kits/ability/native/test/mock/include/mock_bundle_manager.cpp", + "//foundation/aafwk/standard/frameworks/kits/ability/native/test/mock/include/sys_mgr_client_mock.cpp", + "//foundation/appexecfwk/standard/kits/appkit/native/app/src/app_loader.cpp", + "unittest/context_container_test.cpp", + ] + + configs = [ ":module_context_config" ] + + deps = [ + "${ABILITY_INNERKITS_PATH}/want:want", + "//foundation/aafwk/standard/frameworks/kits/ability/native:abilitykit_native", + "//foundation/aafwk/standard/interfaces/innerkits/ability_manager:ability_manager", + "//foundation/appexecfwk/standard/common:libappexecfwk_common", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler:libeventhandler", + "//foundation/appexecfwk/standard/kits:appkit_native", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +ohos_unittest("context_deal_test") { + module_out_path = module_output_path + sources = [ + "../app/src/ohos_application.cpp", + "//foundation/aafwk/standard/frameworks/kits/ability/native/test/mock/include/mock_bundle_manager.cpp", + "//foundation/aafwk/standard/frameworks/kits/ability/native/test/mock/include/sys_mgr_client_mock.cpp", + "//foundation/appexecfwk/standard/kits/appkit/native/app/src/app_loader.cpp", + "unittest/context_deal_test.cpp", + ] + + configs = [ ":module_context_config" ] + + deps = [ + "${ABILITY_INNERKITS_PATH}/want:want", + "//foundation/aafwk/standard/frameworks/kits/ability/native:abilitykit_native", + "//foundation/aafwk/standard/interfaces/innerkits/ability_manager:ability_manager", + "//foundation/appexecfwk/standard/common:libappexecfwk_common", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler:libeventhandler", + "//foundation/appexecfwk/standard/kits:appkit_native", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +ohos_unittest("application_impl_test") { + module_out_path = module_output_path + sources = [ + "../app/src/application_impl.cpp", + "../app/src/ohos_application.cpp", + "//foundation/appexecfwk/standard/kits/appkit/native/app/src/app_loader.cpp", + "//foundation/appexecfwk/standard/kits/appkit/native/app/src/application_context.cpp", + "unittest/application_impl_test.cpp", + ] + + configs = [ ":module_private_config" ] + + deps = [ + "${ABILITY_INNERKITS_PATH}/want:want", + "//foundation/aafwk/standard/frameworks/kits/ability/native:abilitykit_native", + "//foundation/aafwk/standard/interfaces/innerkits/ability_manager:ability_manager", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/appexecfwk/standard/common:libappexecfwk_common", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler:libeventhandler", + "//foundation/appexecfwk/standard/kits:appkit_native", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +############################################################################### + +group("unittest") { + testonly = true + deps = [] + + deps += [ + ":application_impl_test", + ":application_test", + ":context_container_test", + ":context_deal_test", + ] +} +############################################################################### diff --git a/kits/appkit/native/test/mock/include/mock_ability_lifecycle_callbacks.h b/kits/appkit/native/test/mock/include/mock_ability_lifecycle_callbacks.h new file mode 100644 index 000000000..0a4b08b94 --- /dev/null +++ b/kits/appkit/native/test/mock/include/mock_ability_lifecycle_callbacks.h @@ -0,0 +1,112 @@ +/* + * 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_MOCK_ABILITY_LIFECYCLE_CALLBACK_H +#define FOUNDATION_APPEXECFWK_OHOS_MOCK_ABILITY_LIFECYCLE_CALLBACK_H + +#include "want.h" +#include "ability_lifecycle_callbacks.h" +#include +namespace OHOS { +namespace AppExecFwk { + +using Want = OHOS::AAFwk::Want; + +class MockAbilityLifecycleCallbacks : public AbilityLifecycleCallbacks { +public: + MockAbilityLifecycleCallbacks() = default; + virtual ~MockAbilityLifecycleCallbacks() = default; + + /** + * + * Will be called when the given ability calls Ability->onStart + * + * @param Ability Indicates the ability object that calls the onStart() method. + */ + virtual void OnAbilityStart(const std::shared_ptr &ability) + { + GTEST_LOG_(INFO) << "MockAbilityLifecycleCallbacks::OnAbilityStart called"; + } + + /** + * + * Will be called when the given ability calls Ability->onInactive + * + * @param Ability Indicates the Ability object that calls the onInactive() method. + */ + virtual void OnAbilityInactive(const std::shared_ptr &ability) + { + GTEST_LOG_(INFO) << "MockAbilityLifecycleCallbacks::OnAbilityInactive called"; + } + + /** + * + * Will be called when the given ability calls Ability->onBackground + * + * @param Ability Indicates the Ability object that calls the onBackground() method. + */ + virtual void OnAbilityBackground(const std::shared_ptr &ability) + { + GTEST_LOG_(INFO) << "MockAbilityLifecycleCallbacks::OnAbilityBackground called"; + } + + /** + * + * Will be called when the given ability calls Ability->onForeground + * + * @param Ability Indicates the Ability object that calls the onForeground() method. + */ + virtual void OnAbilityForeground(const std::shared_ptr &ability) + { + GTEST_LOG_(INFO) << "MockAbilityLifecycleCallbacks::OnAbilityForeground called"; + } + + /** + * + * Will be called when the given ability calls Ability->onActive + * + * @param Ability Indicates the Ability object that calls the onActive() method. + */ + virtual void OnAbilityActive(const std::shared_ptr &ability) + { + GTEST_LOG_(INFO) << "MockAbilityLifecycleCallbacks::OnAbilityActive called"; + } + + /** + * + * Will be called when the given ability calls Ability->onStop + * + * @param Ability Indicates the Ability object that calls the onStop() method. + */ + virtual void OnAbilityStop(const std::shared_ptr &ability) + { + GTEST_LOG_(INFO) << "MockAbilityLifecycleCallbacks::OnAbilityStop called"; + } + + /** + * + * Will be Called when an ability calls Ability#onSaveAbilityState(PacMap). + * + * @param outState Indicates the PacMap object passed to the onSaveAbilityState() callback. + */ + virtual void OnAbilitySaveState(const PacMap &outState) + { + GTEST_LOG_(INFO) << "MockAbilityLifecycleCallbacks::OnAbilityStop called"; + } +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_OHOS_MOCK_ABILITY_LIFECYCLE_CALLBACK_H \ No newline at end of file diff --git a/kits/appkit/native/test/mock/include/mock_application.h b/kits/appkit/native/test/mock/include/mock_application.h new file mode 100644 index 000000000..d4847c3d0 --- /dev/null +++ b/kits/appkit/native/test/mock/include/mock_application.h @@ -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. + */ + +#ifndef FOUNDATION_APPEXECFWK_OHOS_MOCK_APPLICATION_H +#define FOUNDATION_APPEXECFWK_OHOS_MOCK_APPLICATION_H + +#include "ohos_application.h" +#include + +namespace OHOS { +namespace AppExecFwk { + +class OHOSApplication; +class MockApplication : public OHOSApplication { +public: + MockApplication() = default; + virtual ~MockApplication() = default; + + enum { + APP_STATE_CREATE = 0, + APP_STATE_READY = 1, + APP_STATE_FOREGROUND = 2, + APP_STATE_BACKGROUND = 3, + APP_STATE_TERMINATED = 4 + }; + + virtual void OnReady() + { + GTEST_LOG_(INFO) << "MockApplication::OnReady called"; + state_ = APP_STATE_READY; + } + + virtual void OnForeground() + { + GTEST_LOG_(INFO) << "MockApplication::OnForeground called"; + state_ = APP_STATE_FOREGROUND; + } + + virtual void OnBackground() + { + GTEST_LOG_(INFO) << "MockApplication::OnBackground called"; + state_ = APP_STATE_BACKGROUND; + } + + virtual void OnConfigurationUpdated(const Configuration &config) + { + GTEST_LOG_(INFO) << "MockApplication::OnConfigurationUpdated called"; + onConfigurationUpdatedCalled_ = true; + } + + virtual void OnMemoryLevel(int level) + { + GTEST_LOG_(INFO) << "MockApplication::OnMemoryLevel called"; + onMemoryLevelCalled_ = true; + } + + virtual void OnStart() + { + GTEST_LOG_(INFO) << "MockApplication::OnStart called"; + state_ = APP_STATE_READY; + } + + virtual void OnTerminate() + { + GTEST_LOG_(INFO) << "MockApplication::OnTerminate called"; + state_ = APP_STATE_TERMINATED; + } + + int state_ = APP_STATE_CREATE; + bool onMemoryLevelCalled_ = false; + bool onConfigurationUpdatedCalled_ = false; +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_OHOS_MOCK_APPLICATION_H diff --git a/kits/appkit/native/test/mock/include/mock_element_callback.h b/kits/appkit/native/test/mock/include/mock_element_callback.h new file mode 100644 index 000000000..d725fc600 --- /dev/null +++ b/kits/appkit/native/test/mock/include/mock_element_callback.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_OHOS_MOCK_ELEMENTS_CALLBACK_H +#define FOUNDATION_APPEXECFWK_OHOS_MOCK_ELEMENTS_CALLBACK_H + +#include "mock_element_callback.h" +#include + +namespace OHOS { +namespace AppExecFwk { + +class MockElementsCallback : public ElementsCallback { +public: + MockElementsCallback() = default; + virtual ~MockElementsCallback() = default; + + /** + * + * Called when the system configuration of the device changes. + * + * @param config Indicates the new Configuration object. + * @param ability Indicates the new Ability object. + */ + virtual void OnConfigurationUpdated(const std::shared_ptr &ability, const Configuration &config) + { + GTEST_LOG_(INFO) << "MockElementsCallback::OnConfigurationUpdated called"; + } + + /** + * + * Will be called when the system has determined to trim the memory + * + * @param level Indicates the memory trim level, which shows the current memory usage status. + */ + virtual void OnMemoryLevel(int level) + { + GTEST_LOG_(INFO) << "MockElementsCallback::OnMemoryLevel called"; + } +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_OHOS_MOCK_ELEMENTS_CALLBACK_H \ No newline at end of file diff --git a/kits/appkit/native/test/unittest/application_impl_test.cpp b/kits/appkit/native/test/unittest/application_impl_test.cpp new file mode 100644 index 000000000..0e3729c8b --- /dev/null +++ b/kits/appkit/native/test/unittest/application_impl_test.cpp @@ -0,0 +1,308 @@ +/* + * 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 "application_impl.h" +#include "mock_application.h" + +namespace OHOS { +namespace AppExecFwk { +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; + +class ApplicationImplTest : public testing::Test { +public: + ApplicationImplTest() : applicationImpl_(nullptr) + {} + ~ApplicationImplTest() + { + applicationImpl_ = nullptr; + } + ApplicationImpl *applicationImpl_ = nullptr; + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void ApplicationImplTest::SetUpTestCase(void) +{} + +void ApplicationImplTest::TearDownTestCase(void) +{} + +void ApplicationImplTest::SetUp(void) +{ + applicationImpl_ = new (std::nothrow) ApplicationImpl(); +} + +void ApplicationImplTest::TearDown(void) +{ + delete applicationImpl_; + applicationImpl_ = nullptr; +} + +/** + * @tc.number: AppExecFwk_ApplicationImpl_PerformAppReady_0100 + * @tc.name: PerformAppReady + * @tc.desc: Test whether the performapready return value is false. + */ +HWTEST_F(ApplicationImplTest, AppExecFwk_ApplicationImpl_PerformAppReady_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_ApplicationImpl_PerformAppReady_0100 start"; + + EXPECT_NE(applicationImpl_, nullptr); + if (applicationImpl_ != nullptr) { + std::shared_ptr application = std::make_shared(); + applicationImpl_->SetApplication(application); + applicationImpl_->SetState(MockApplication::APP_STATE_CREATE); + bool ret = applicationImpl_->PerformAppReady(); + EXPECT_EQ(MockApplication::APP_STATE_READY, applicationImpl_->GetState()); + EXPECT_EQ(MockApplication::APP_STATE_READY, application->state_); + EXPECT_EQ(true, ret); + } + GTEST_LOG_(INFO) << "AppExecFwk_ApplicationImpl_PerformAppReady_0100 end"; +} + +/** + * @tc.number: AppExecFwk_ApplicationImpl_PerformAppReady_0200 + * @tc.name: PerformAppReady + * @tc.desc: Test whether the performapready return value is false. + */ +HWTEST_F(ApplicationImplTest, AppExecFwk_ApplicationImpl_PerformAppReady_0200, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_ApplicationImpl_PerformAppReady_0200 start"; + + EXPECT_NE(applicationImpl_, nullptr); + if (applicationImpl_ != nullptr) { + std::shared_ptr application = std::make_shared(); + applicationImpl_->SetApplication(application); + applicationImpl_->SetState(MockApplication::APP_STATE_BACKGROUND); + bool ret = applicationImpl_->PerformAppReady(); + EXPECT_EQ(false, ret); + } + GTEST_LOG_(INFO) << "AppExecFwk_ApplicationImpl_PerformAppReady_0200 end"; +} + +/** + * @tc.number: AppExecFwk_ApplicationImpl_PerformForeground_0100 + * @tc.name: PerformForeground + * @tc.desc: Test whether setapplication and setstate are called normally, + * and verify whether the return value of performforegroup is true. + */ +HWTEST_F(ApplicationImplTest, AppExecFwk_ApplicationImpl_PerformForeground_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_ApplicationImpl_PerformForeground_0100 start"; + + EXPECT_NE(applicationImpl_, nullptr); + if (applicationImpl_ != nullptr) { + std::shared_ptr application = std::make_shared(); + applicationImpl_->SetApplication(application); + applicationImpl_->SetState(MockApplication::APP_STATE_READY); + bool ret = applicationImpl_->PerformForeground(); + EXPECT_EQ(MockApplication::APP_STATE_FOREGROUND, applicationImpl_->GetState()); + EXPECT_EQ(MockApplication::APP_STATE_FOREGROUND, application->state_); + EXPECT_EQ(true, ret); + } + GTEST_LOG_(INFO) << "AppExecFwk_ApplicationImpl_PerformForeground_0100 end"; +} + +/** + * @tc.number: AppExecFwk_ApplicationImpl_PerformForeground_0200 + * @tc.name: PerformForeground + * @tc.desc: Test whether setapplication and setstate are called normally, + * and verify whether the return value of performforegroup is false. + */ +HWTEST_F(ApplicationImplTest, AppExecFwk_ApplicationImpl_PerformForeground_0200, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_ApplicationImpl_PerformForeground_0200 start"; + + EXPECT_NE(applicationImpl_, nullptr); + if (applicationImpl_ != nullptr) { + std::shared_ptr application = std::make_shared(); + applicationImpl_->SetApplication(application); + applicationImpl_->SetState(MockApplication::APP_STATE_CREATE); + bool ret = applicationImpl_->PerformForeground(); + EXPECT_EQ(false, ret); + } + GTEST_LOG_(INFO) << "AppExecFwk_ApplicationImpl_PerformForeground_0200 end"; +} + +/** + * @tc.number: AppExecFwk_ApplicationImpl_PerformForeground_0300 + * @tc.name: PerformForeground + * @tc.desc: Test whether setapplication and setstate are called normally, + * and verify whether the return value of performforegroup is true. + */ +HWTEST_F(ApplicationImplTest, AppExecFwk_ApplicationImpl_PerformForeground_0300, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_ApplicationImpl_PerformForeground_0300 start"; + + EXPECT_NE(applicationImpl_, nullptr); + if (applicationImpl_ != nullptr) { + std::shared_ptr application = std::make_shared(); + applicationImpl_->SetApplication(application); + applicationImpl_->SetState(MockApplication::APP_STATE_BACKGROUND); + bool ret = applicationImpl_->PerformForeground(); + EXPECT_EQ(MockApplication::APP_STATE_FOREGROUND, applicationImpl_->GetState()); + EXPECT_EQ(MockApplication::APP_STATE_FOREGROUND, application->state_); + EXPECT_EQ(true, ret); + } + GTEST_LOG_(INFO) << "AppExecFwk_ApplicationImpl_PerformForeground_0300 end"; +} + +/** + * @tc.number: AppExecFwk_ApplicationImpl_PerformBackground_0100 + * @tc.name: PerformBackground + * @tc.desc: Test whether setapplication and setstate are called normally, + * and verify whether the return value of performbackground is false. + */ +HWTEST_F(ApplicationImplTest, AppExecFwk_ApplicationImpl_PerformBackground_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_ApplicationImpl_PerformBackground_0100 start"; + + EXPECT_NE(applicationImpl_, nullptr); + if (applicationImpl_ != nullptr) { + std::shared_ptr application = std::make_shared(); + applicationImpl_->SetApplication(application); + applicationImpl_->SetState(MockApplication::APP_STATE_CREATE); + bool ret = applicationImpl_->PerformBackground(); + EXPECT_EQ(false, ret); + } + GTEST_LOG_(INFO) << "AppExecFwk_ApplicationImpl_PerformBackground_0100 end"; +} + +/** + * @tc.number: AppExecFwk_ApplicationImpl_PerformBackground_0200 + * @tc.name: PerformBackground + * @tc.desc: Test whether setapplication and setstate are called normally, + * and verify whether the return value of performbackground is true. + */ +HWTEST_F(ApplicationImplTest, AppExecFwk_ApplicationImpl_PerformBackground_0200, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_ApplicationImpl_PerformBackground_0200 start"; + + EXPECT_NE(applicationImpl_, nullptr); + if (applicationImpl_ != nullptr) { + std::shared_ptr application = std::make_shared(); + applicationImpl_->SetApplication(application); + applicationImpl_->SetState(MockApplication::APP_STATE_FOREGROUND); + bool ret = applicationImpl_->PerformBackground(); + EXPECT_EQ(MockApplication::APP_STATE_BACKGROUND, applicationImpl_->GetState()); + EXPECT_EQ(MockApplication::APP_STATE_BACKGROUND, application->state_); + EXPECT_EQ(true, ret); + } + GTEST_LOG_(INFO) << "AppExecFwk_ApplicationImpl_PerformBackground_0200 end"; +} + +/** + * @tc.number: AppExecFwk_ApplicationImpl_PerformTerminate_0100 + * @tc.name: PerformTerminate + * @tc.desc: Test whether setapplication and setstate are called normally, + * and verify whether the return value of performterminate is false. + */ +HWTEST_F(ApplicationImplTest, AppExecFwk_ApplicationImpl_PerformTerminate_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_ApplicationImpl_PerformTerminate_0100 start"; + EXPECT_NE(applicationImpl_, nullptr); + if (applicationImpl_ != nullptr) { + std::shared_ptr application = std::make_shared(); + applicationImpl_->SetApplication(application); + applicationImpl_->SetState(MockApplication::APP_STATE_CREATE); + bool ret = applicationImpl_->PerformTerminate(); + EXPECT_EQ(false, ret); + } + GTEST_LOG_(INFO) << "AppExecFwk_ApplicationImpl_PerformTerminate_0100 end"; +} + +/** + * @tc.number: AppExecFwk_ApplicationImpl_PerformTerminate_0200 + * @tc.name: PerformTerminate + * @tc.desc: Test whether setapplication and setstate are called normally, + * and verify whether the return value of performterminate is true. + */ +HWTEST_F(ApplicationImplTest, AppExecFwk_ApplicationImpl_PerformTerminate_0200, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_ApplicationImpl_PerformTerminate_0200 start"; + EXPECT_NE(applicationImpl_, nullptr); + if (applicationImpl_ != nullptr) { + std::shared_ptr application = std::make_shared(); + applicationImpl_->SetApplication(application); + applicationImpl_->SetState(MockApplication::APP_STATE_BACKGROUND); + bool ret = applicationImpl_->PerformTerminate(); + EXPECT_EQ(MockApplication::APP_STATE_TERMINATED, applicationImpl_->GetState()); + EXPECT_EQ(MockApplication::APP_STATE_TERMINATED, application->state_); + EXPECT_EQ(true, ret); + } + GTEST_LOG_(INFO) << "AppExecFwk_ApplicationImpl_PerformTerminate_0200 end"; +} + +/** + * @tc.number: AppExecFwk_ApplicationImpl_PerformMemoryLevel_0100 + * @tc.name: PerformMemoryLevel + * @tc.desc: Test whether setapplication and performmemorylevel are called normally. + */ +HWTEST_F(ApplicationImplTest, AppExecFwk_ApplicationImpl_PerformMemoryLevel_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_ApplicationImpl_PerformMemoryLevel_0100 start"; + EXPECT_NE(applicationImpl_, nullptr); + if (applicationImpl_ != nullptr) { + std::shared_ptr application = std::make_shared(); + applicationImpl_->SetApplication(application); + applicationImpl_->PerformMemoryLevel(1); + EXPECT_EQ(true, application->onMemoryLevelCalled_); + } + GTEST_LOG_(INFO) << "AppExecFwk_ApplicationImpl_PerformMemoryLevel_0100 end"; +} + +/** + * @tc.number: AppExecFwk_ApplicationImpl_PerformConfigurationUpdated_0100 + * @tc.name: PerformConfigurationUpdated + * @tc.desc: Test whether setapplication and performmemorylevel are called normally. + */ +HWTEST_F( + ApplicationImplTest, AppExecFwk_ApplicationImpl_PerformConfigurationUpdated_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_ApplicationImpl_PerformConfigurationUpdated_0100 start"; + EXPECT_NE(applicationImpl_, nullptr); + if (applicationImpl_ != nullptr) { + std::shared_ptr application = std::make_shared(); + applicationImpl_->SetApplication(application); + Configuration config; + applicationImpl_->PerformConfigurationUpdated(config); + EXPECT_EQ(true, application->onConfigurationUpdatedCalled_); + } + GTEST_LOG_(INFO) << "AppExecFwk_ApplicationImpl_PerformConfigurationUpdated_0100 end"; +} + +/** + * @tc.number: AppExecFwk_ApplicationImpl_GetRecordId_0100 + * @tc.name: GetRecordId + * @tc.desc: Test whether setrecordid is called normally, and verify whether the return value of getrecordid is correct. + */ +HWTEST_F(ApplicationImplTest, AppExecFwk_ApplicationImpl_GetRecordId_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_ApplicationImpl_GetRecordId_0100 start"; + EXPECT_NE(applicationImpl_, nullptr); + if (applicationImpl_ != nullptr) { + applicationImpl_->SetRecordId(1); + EXPECT_EQ(1, applicationImpl_->GetRecordId()); + } + GTEST_LOG_(INFO) << "AppExecFwk_ApplicationImpl_GetRecordId_0100 end"; +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/kits/appkit/native/test/unittest/application_test.cpp b/kits/appkit/native/test/unittest/application_test.cpp new file mode 100644 index 000000000..08ea6c739 --- /dev/null +++ b/kits/appkit/native/test/unittest/application_test.cpp @@ -0,0 +1,481 @@ +/* + * 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 "ohos_application.h" +#include "ability.h" +#include "mock_ability_lifecycle_callbacks.h" +#include "mock_element_callback.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; + +namespace OHOS { +namespace AppExecFwk { +class ApplicationTest : public testing::Test { +public: + ApplicationTest() : ApplicationTest_(nullptr) + {} + ~ApplicationTest() + { + ApplicationTest_ = nullptr; + } + OHOSApplication *ApplicationTest_ = nullptr; + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void ApplicationTest::SetUpTestCase(void) +{} + +void ApplicationTest::TearDownTestCase(void) +{} + +void ApplicationTest::SetUp(void) +{ + ApplicationTest_ = new (std::nothrow) OHOSApplication(); +} + +void ApplicationTest::TearDown(void) +{ + delete ApplicationTest_; + ApplicationTest_ = nullptr; +} + +/** + * @tc.number: AppExecFwk_Application_RegisterAbilityLifecycleCallbacks_0100 + * @tc.name: RegisterAbilityLifecycleCallbacks + * @tc.desc: Test whether registerabilitylifecyclecallbacks and are called normally. + */ +HWTEST_F(ApplicationTest, AppExecFwk_Application_RegisterAbilityLifecycleCallbacks_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_Application_RegisterAbilityLifecycleCallbacks_0100 start"; + + EXPECT_NE(ApplicationTest_, nullptr); + if (ApplicationTest_ != nullptr) { + std::shared_ptr callback = std::make_shared(); + ApplicationTest_->RegisterAbilityLifecycleCallbacks(callback); + + std::shared_ptr ability = std::make_shared(); + ApplicationTest_->OnAbilityActive(ability); + + ApplicationTest_->UnregisterAbilityLifecycleCallbacks(callback); + } + GTEST_LOG_(INFO) << "AppExecFwk_Application_RegisterAbilityLifecycleCallbacks_0100 end"; +} + +/** + * @tc.number: AppExecFwk_Application_RegisterAbilityLifecycleCallbacks_0200 + * @tc.name: RegisterAbilityLifecycleCallbacks + * @tc.desc: Test the abnormal state of registerabilitylifecyclecallbacks. + */ +HWTEST_F(ApplicationTest, AppExecFwk_Application_RegisterAbilityLifecycleCallbacks_0200, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_Application_RegisterAbilityLifecycleCallbacks_0200 start"; + + EXPECT_NE(ApplicationTest_, nullptr); + if (ApplicationTest_ != nullptr) { + ApplicationTest_->RegisterAbilityLifecycleCallbacks(nullptr); + + std::shared_ptr ability = std::make_shared(); + ApplicationTest_->OnAbilityActive(ability); + } + GTEST_LOG_(INFO) << "AppExecFwk_Application_RegisterAbilityLifecycleCallbacks_0200 end"; +} + +/** + * @tc.number: AppExecFwk_Application_UnregisterAbilityLifecycleCallbacks_0100 + * @tc.name: UnregisterAbilityLifecycleCallbacks + * @tc.desc: Test whether unregisterabilitylife callbacks is successfully called. + */ +HWTEST_F( + ApplicationTest, AppExecFwk_Application_UnregisterAbilityLifecycleCallbacks_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_Application_UnregisterAbilityLifecycleCallbacks_0100 start"; + + EXPECT_NE(ApplicationTest_, nullptr); + if (ApplicationTest_ != nullptr) { + std::shared_ptr callback = std::make_shared(); + ApplicationTest_->RegisterAbilityLifecycleCallbacks(callback); + ApplicationTest_->UnregisterAbilityLifecycleCallbacks(callback); + + std::shared_ptr ability = std::make_shared(); + ApplicationTest_->OnAbilityActive(ability); + } + GTEST_LOG_(INFO) << "AppExecFwk_Application_UnregisterAbilityLifecycleCallbacks_0100 end"; +} + +/** + * @tc.number: AppExecFwk_Application_UnregisterAbilityLifecycleCallbacks_0200 + * @tc.name: UnregisterAbilityLifecycleCallbacks + * @tc.desc: Test the abnormal state of unregisterability lifecycle callbacks. + */ +HWTEST_F( + ApplicationTest, AppExecFwk_Application_UnregisterAbilityLifecycleCallbacks_0200, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_Application_UnregisterAbilityLifecycleCallbacks_0200 start"; + + EXPECT_NE(ApplicationTest_, nullptr); + if (ApplicationTest_ != nullptr) { + std::shared_ptr callback = std::make_shared(); + ApplicationTest_->RegisterAbilityLifecycleCallbacks(callback); + ApplicationTest_->UnregisterAbilityLifecycleCallbacks(nullptr); + + std::shared_ptr ability = std::make_shared(); + ApplicationTest_->OnAbilityActive(ability); + + ApplicationTest_->UnregisterAbilityLifecycleCallbacks(callback); + } + GTEST_LOG_(INFO) << "AppExecFwk_Application_UnregisterAbilityLifecycleCallbacks_0200 end"; +} + +/** + * @tc.number: AppExecFwk_Application_OnAbilityStart_0100 + * @tc.name: OnAbilityStart + * @tc.desc: Test whether onabilitystart is called normally. + */ +HWTEST_F(ApplicationTest, AppExecFwk_Application_OnAbilityStart_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_Application_OnAbilityStart_0100 start"; + + EXPECT_NE(ApplicationTest_, nullptr); + if (ApplicationTest_ != nullptr) { + std::shared_ptr callback = std::make_shared(); + ApplicationTest_->RegisterAbilityLifecycleCallbacks(callback); + + std::shared_ptr ability = std::make_shared(); + ApplicationTest_->OnAbilityStart(ability); + + ApplicationTest_->UnregisterAbilityLifecycleCallbacks(callback); + } + GTEST_LOG_(INFO) << "AppExecFwk_Application_OnAbilityStart_0100 end"; +} + +/** + * @tc.number: AppExecFwk_Application_OnAbilityInactive_0100 + * @tc.name: OnAbilityInactive + * @tc.desc: Test whether onabilityinactive is called normally. + */ +HWTEST_F(ApplicationTest, AppExecFwk_Application_OnAbilityInactive_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_Application_OnAbilityInactive_0100 start"; + + EXPECT_NE(ApplicationTest_, nullptr); + if (ApplicationTest_ != nullptr) { + std::shared_ptr callback = std::make_shared(); + ApplicationTest_->RegisterAbilityLifecycleCallbacks(callback); + + std::shared_ptr ability = std::make_shared(); + ApplicationTest_->OnAbilityInactive(ability); + + ApplicationTest_->UnregisterAbilityLifecycleCallbacks(callback); + } + GTEST_LOG_(INFO) << "AppExecFwk_Application_OnAbilityInactive_0100 end"; +} + +/** + * @tc.number: AppExecFwk_Application_OnAbilityBackground_0100 + * @tc.name: OnAbilityBackground + * @tc.desc: Test whether onabilitybackground is called normally. + */ +HWTEST_F(ApplicationTest, AppExecFwk_Application_OnAbilityBackground_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_Application_OnAbilityBackground_0100 start"; + + EXPECT_NE(ApplicationTest_, nullptr); + if (ApplicationTest_ != nullptr) { + std::shared_ptr callback = std::make_shared(); + ApplicationTest_->RegisterAbilityLifecycleCallbacks(callback); + + std::shared_ptr ability = std::make_shared(); + ApplicationTest_->OnAbilityBackground(ability); + + ApplicationTest_->UnregisterAbilityLifecycleCallbacks(callback); + } + GTEST_LOG_(INFO) << "AppExecFwk_Application_OnAbilityBackground_0100 end"; +} + +/** + * @tc.number: AppExecFwk_Application_OnAbilityForeground_0100 + * @tc.name: OnAbilityForeground + * @tc.desc: Test whether onabilityforegroup is called normally. + */ +HWTEST_F(ApplicationTest, AppExecFwk_Application_OnAbilityForeground_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_Application_OnAbilityForeground_0100 start"; + + EXPECT_NE(ApplicationTest_, nullptr); + if (ApplicationTest_ != nullptr) { + std::shared_ptr callback = std::make_shared(); + ApplicationTest_->RegisterAbilityLifecycleCallbacks(callback); + + std::shared_ptr ability = std::make_shared(); + ApplicationTest_->OnAbilityForeground(ability); + + ApplicationTest_->UnregisterAbilityLifecycleCallbacks(callback); + } + GTEST_LOG_(INFO) << "AppExecFwk_Application_OnAbilityForeground_0100 end"; +} + +/** + * @tc.number: AppExecFwk_Application_OnAbilityActive_0100 + * @tc.name: OnAbilityActive + * @tc.desc: Test whether onabilityactive is called normally. + */ +HWTEST_F(ApplicationTest, AppExecFwk_Application_OnAbilityActive_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_Application_OnAbilityActive_0100 start"; + + EXPECT_NE(ApplicationTest_, nullptr); + if (ApplicationTest_ != nullptr) { + std::shared_ptr callback = std::make_shared(); + ApplicationTest_->RegisterAbilityLifecycleCallbacks(callback); + + std::shared_ptr ability = std::make_shared(); + ApplicationTest_->OnAbilityActive(ability); + + ApplicationTest_->UnregisterAbilityLifecycleCallbacks(callback); + } + GTEST_LOG_(INFO) << "AppExecFwk_Application_OnAbilityActive_0100 end"; +} + +/** + * @tc.number: AppExecFwk_Application_OnAbilityStop_0100 + * @tc.name: OnAbilityStop + * @tc.desc: Test whether onabilitystop is called normally. + */ +HWTEST_F(ApplicationTest, AppExecFwk_Application_OnAbilityStop_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_Application_OnAbilityStop_0100 start"; + + EXPECT_NE(ApplicationTest_, nullptr); + if (ApplicationTest_ != nullptr) { + std::shared_ptr callback = std::make_shared(); + ApplicationTest_->RegisterAbilityLifecycleCallbacks(callback); + + std::shared_ptr ability = std::make_shared(); + ApplicationTest_->OnAbilityStop(ability); + + ApplicationTest_->UnregisterAbilityLifecycleCallbacks(callback); + } + GTEST_LOG_(INFO) << "AppExecFwk_Application_OnAbilityStop_0100 end"; +} + +/** + * @tc.number: AppExecFwk_Application_OnConfigurationUpdated_0100 + * @tc.name: OnConfigurationUpdated + * @tc.desc: Test whether onconfigurationupdated is called normally. + */ +HWTEST_F(ApplicationTest, AppExecFwk_Application_OnConfigurationUpdated_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_Application_OnConfigurationUpdated_0100 start"; + + EXPECT_NE(ApplicationTest_, nullptr); + if (ApplicationTest_ != nullptr) { + std::shared_ptr callback = std::make_shared(); + ApplicationTest_->RegisterElementsCallbacks(callback); + + Configuration configuration; + ApplicationTest_->OnConfigurationUpdated(configuration); + + ApplicationTest_->UnregisterElementsCallbacks(callback); + } + GTEST_LOG_(INFO) << "AppExecFwk_Application_OnConfigurationUpdated_0100 end"; +} + +/** + * @tc.number: AppExecFwk_Application_OnMemoryLevel_0100 + * @tc.name: OnMemoryLevel + * @tc.desc: Test whether onmemorylevel is called normally. + */ +HWTEST_F(ApplicationTest, AppExecFwk_Application_OnMemoryLevel_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_Application_OnMemoryLevel_0100 start"; + + EXPECT_NE(ApplicationTest_, nullptr); + if (ApplicationTest_ != nullptr) { + std::shared_ptr callback = std::make_shared(); + ApplicationTest_->RegisterElementsCallbacks(callback); + + ApplicationTest_->OnMemoryLevel(1); + + ApplicationTest_->UnregisterElementsCallbacks(callback); + } + GTEST_LOG_(INFO) << "AppExecFwk_Application_OnMemoryLevel_0100 end"; +} + +/** + * @tc.number: AppExecFwk_Application_OnStart_0100 + * @tc.name: OnStart + * @tc.desc: Test whether OnStart is called normally. + */ +HWTEST_F(ApplicationTest, AppExecFwk_Application_OnStart_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_Application_OnStart_0100 start"; + + EXPECT_NE(ApplicationTest_, nullptr); + if (ApplicationTest_ != nullptr) { + ApplicationTest_->OnStart(); + } + + GTEST_LOG_(INFO) << "AppExecFwk_Application_OnStart_0100 end"; +} + +/** + * @tc.number: AppExecFwk_Application_OnTerminate_0100 + * @tc.name: OnTerminate + * @tc.desc: Test whether OnTerminate is called normally. + */ +HWTEST_F(ApplicationTest, AppExecFwk_Application_OnTerminate_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_Application_OnTerminate_0100 start"; + + EXPECT_NE(ApplicationTest_, nullptr); + if (ApplicationTest_ != nullptr) { + ApplicationTest_->OnTerminate(); + } + + GTEST_LOG_(INFO) << "AppExecFwk_Application_OnTerminate_0100 end"; +} + +/** + * @tc.number: AppExecFwk_Application_DispatchAbilitySavedState_0100 + * @tc.name: DispatchAbilitySavedState + * @tc.desc: Test whether dispatchabilitysavedstate is called normally. + */ +HWTEST_F(ApplicationTest, AppExecFwk_Application_DispatchAbilitySavedState_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_Application_DispatchAbilitySavedState_0100 start"; + + EXPECT_NE(ApplicationTest_, nullptr); + if (ApplicationTest_ != nullptr) { + std::shared_ptr callback = std::make_shared(); + ApplicationTest_->RegisterAbilityLifecycleCallbacks(callback); + + PacMap outState; + ApplicationTest_->DispatchAbilitySavedState(outState); + + ApplicationTest_->UnregisterAbilityLifecycleCallbacks(callback); + } + GTEST_LOG_(INFO) << "AppExecFwk_Application_DispatchAbilitySavedState_0100 end"; +} + +/** + * @tc.number: AppExecFwk_Application_OnAbilitySaveState_0100 + * @tc.name: OnAbilitySaveState + * @tc.desc: Test whether the onablitysavestate is called normally. + */ +HWTEST_F(ApplicationTest, AppExecFwk_Application_OnAbilitySaveState_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_Application_OnAbilitySaveState_0100 start"; + + EXPECT_NE(ApplicationTest_, nullptr); + if (ApplicationTest_ != nullptr) { + std::shared_ptr callback = std::make_shared(); + ApplicationTest_->RegisterAbilityLifecycleCallbacks(callback); + + PacMap outState; + ApplicationTest_->OnAbilitySaveState(outState); + + ApplicationTest_->UnregisterAbilityLifecycleCallbacks(callback); + } + GTEST_LOG_(INFO) << "AppExecFwk_Application_OnAbilitySaveState_0100 end"; +} + +/** + * @tc.number: AppExecFwk_Application_OnMemoryLevel_0100 + * @tc.name: OnMemoryLevel + * @tc.desc: Test whether onmemorylevel is called normally. + */ +HWTEST_F(ApplicationTest, AppExecFwk_Application_RegisterElementsCallbacks_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_Application_RegisterElementsCallbacks_0100 start"; + + EXPECT_NE(ApplicationTest_, nullptr); + if (ApplicationTest_ != nullptr) { + std::shared_ptr callback = std::make_shared(); + ApplicationTest_->RegisterElementsCallbacks(callback); + + ApplicationTest_->OnMemoryLevel(1); + + ApplicationTest_->UnregisterElementsCallbacks(callback); + } + GTEST_LOG_(INFO) << "AppExecFwk_Application_RegisterElementsCallbacks_0100 end"; +} + +/** + * @tc.number: AppExecFwk_Application_OnMemoryLevel_0200 + * @tc.name: OnMemoryLevel + * @tc.desc: Test the abnormal state of onmemorylevel. + */ +HWTEST_F(ApplicationTest, AppExecFwk_Application_RegisterElementsCallbacks_0200, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_Application_RegisterElementsCallbacks_0200 start"; + + EXPECT_NE(ApplicationTest_, nullptr); + if (ApplicationTest_ != nullptr) { + std::shared_ptr callback = std::make_shared(); + ApplicationTest_->RegisterElementsCallbacks(nullptr); + + ApplicationTest_->OnMemoryLevel(1); + } + GTEST_LOG_(INFO) << "AppExecFwk_Application_RegisterElementsCallbacks_0200 end"; +} + +/** + * @tc.number: AppExecFwk_Application_UnregisterElementsCallbacks_0100 + * @tc.name: UnregisterElementsCallbacks + * @tc.desc: Test whether unregisterelementcallbacks are called normally. + */ +HWTEST_F(ApplicationTest, AppExecFwk_Application_UnregisterElementsCallbacks_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_Application_UnregisterElementsCallbacks_0100 start"; + + EXPECT_NE(ApplicationTest_, nullptr); + if (ApplicationTest_ != nullptr) { + std::shared_ptr callback = std::make_shared(); + ApplicationTest_->RegisterElementsCallbacks(callback); + ApplicationTest_->UnregisterElementsCallbacks(callback); + ApplicationTest_->OnMemoryLevel(1); + } + GTEST_LOG_(INFO) << "AppExecFwk_Application_UnregisterElementsCallbacks_0100 end"; +} + +/** + * @tc.number: AppExecFwk_Application_UnregisterElementsCallbacks_0200 + * @tc.name: UnregisterElementsCallbacks + * @tc.desc: Test the unregisterelementcallbacks exception state. + */ +HWTEST_F(ApplicationTest, AppExecFwk_Application_UnregisterElementsCallbacks_0200, Function | MediumTest | Level3) +{ + GTEST_LOG_(INFO) << "AppExecFwk_Application_UnregisterElementsCallbacks_0200 start"; + + EXPECT_NE(ApplicationTest_, nullptr); + if (ApplicationTest_ != nullptr) { + std::shared_ptr callback = std::make_shared(); + ApplicationTest_->RegisterElementsCallbacks(callback); + ApplicationTest_->UnregisterElementsCallbacks(nullptr); + ApplicationTest_->OnMemoryLevel(1); + + ApplicationTest_->UnregisterElementsCallbacks(callback); + } + GTEST_LOG_(INFO) << "AppExecFwk_Application_UnregisterElementsCallbacks_0200 end"; +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/kits/appkit/native/test/unittest/context_container_test.cpp b/kits/appkit/native/test/unittest/context_container_test.cpp new file mode 100644 index 000000000..c9a1cda31 --- /dev/null +++ b/kits/appkit/native/test/unittest/context_container_test.cpp @@ -0,0 +1,578 @@ +/* + * 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 "ohos_application.h" +#include "system_ability_definition.h" +#include "sys_mgr_client.h" +#include "ability_context.h" +#include "ability.h" +#include "context_container.h" +#include "context_deal.h" +#include "mock_bundle_manager.h" + +namespace OHOS { +namespace AppExecFwk { +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; + +class ContextContainerTest : public testing::Test { +public: + ContextContainerTest() : context_(nullptr), contextDeal_(nullptr) + {} + ~ContextContainerTest() + {} + std::shared_ptr context_ = nullptr; + std::shared_ptr contextDeal_ = nullptr; + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void ContextContainerTest::SetUpTestCase(void) +{} + +void ContextContainerTest::TearDownTestCase(void) +{} + +void ContextContainerTest::SetUp(void) +{ + OHOS::sptr bundleObject = new (std::nothrow) BundleMgrService(); + + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility( + OHOS::BUNDLE_MGR_SERVICE_SYS_ABILITY_ID, bundleObject); + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility( + OHOS::ABILITY_MGR_SERVICE_ID, bundleObject); + context_ = std::make_shared(); + contextDeal_ = std::make_shared(); +} + +void ContextContainerTest::TearDown(void) +{} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetBundleName_0100 + * @tc.name: GetBundleName + * @tc.desc: Test whether attachbasecontext is called normally, + * and verify whether the return value of getbundlename is correct. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetBundleName_0100, Function | MediumTest | Level1) +{ + std::shared_ptr info = std::make_shared(); + std::string bundleName = "BundleName"; + info->bundleName = bundleName; + contextDeal_->SetApplicationInfo(info); + context_->AttachBaseContext(contextDeal_); + + EXPECT_STREQ(context_->GetBundleName().c_str(), bundleName.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetBundleName_0200 + * @tc.name: GetBundleName + * @tc.desc: Test getbundlename exception status. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetBundleName_0200, Function | MediumTest | Level3) +{ + std::string bundleName = ""; + + EXPECT_STREQ(context_->GetBundleName().c_str(), bundleName.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetBundleManager_0100 + * @tc.name: GetBundleManager + * @tc.desc: Test whether attachbasecontext is called normally, + * and verify whether the return value of getbundlemanager is correct. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetBundleManager_0100, Function | MediumTest | Level1) +{ + context_->AttachBaseContext(contextDeal_); + + sptr ptr = context_->GetBundleManager(); + + EXPECT_NE(ptr, nullptr); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetBundleManager_0200 + * @tc.name: GetBundleManager + * @tc.desc: Test getbundlemanager exception status. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetBundleManager_0200, Function | MediumTest | Level3) +{ + sptr ptr = context_->GetBundleManager(); + EXPECT_EQ(ptr, nullptr); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetBundleCodePath_0100 + * @tc.name: GetBundleCodePath + * @tc.desc: Test whether attachbasecontext is called normally, + * and verify whether the return value of getbundlecodepath is correct. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetBundleCodePath_0100, Function | MediumTest | Level1) +{ + std::shared_ptr info = std::make_shared(); + std::string codePath = "CodePath"; + info->codePath = codePath; + contextDeal_->SetApplicationInfo(info); + context_->AttachBaseContext(contextDeal_); + + EXPECT_STREQ(context_->GetBundleCodePath().c_str(), codePath.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetBundleCodePath_0200 + * @tc.name: GetBundleCodePath + * @tc.desc: Test getbundlecodepath exception status. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetBundleCodePath_0200, Function | MediumTest | Level3) +{ + std::string codePath = ""; + std::string path = context_->GetBundleCodePath(); + + EXPECT_STREQ(path.c_str(), codePath.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetApplicationInfo_0100 + * @tc.name: GetApplicationInfo + * @tc.desc: Test whether attachbasecontext is called normally, + * and verify whether the return value of getapplicationinfo is correct. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetApplicationInfo_0100, Function | MediumTest | Level1) +{ + std::shared_ptr info = std::make_shared(); + std::string bundleName = "BundleName"; + info->bundleName = bundleName; + contextDeal_->SetApplicationInfo(info); + context_->AttachBaseContext(contextDeal_); + + EXPECT_STREQ(context_->GetApplicationInfo()->bundleName.c_str(), bundleName.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetApplicationInfo_0200 + * @tc.name: GetApplicationInfo + * @tc.desc: Test getapplicationinfo exception status. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetApplicationInfo_0200, Function | MediumTest | Level3) +{ + std::shared_ptr info = context_->GetApplicationInfo(); + EXPECT_EQ(info, nullptr); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetBundleResourcePath_0100 + * @tc.name: GetBundleResourcePath + * @tc.desc: Test whether AttachBaseContext is called normally, + * and verify whether the return value of GetBundleResourcePath is correct. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetBundleResourcePath_0100, Function | MediumTest | Level1) +{ + std::shared_ptr info = std::make_shared(); + std::string resourcePath = "ResourcePath"; + info->resourcePath = resourcePath; + contextDeal_->SetAbilityInfo(info); + context_->AttachBaseContext(contextDeal_); + + EXPECT_STREQ(context_->GetBundleResourcePath().c_str(), resourcePath.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetBundleResourcePath_0200 + * @tc.name: GetBundleResourcePath + * @tc.desc: Test GetBundleResourcePath exception status. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetBundleResourcePath_0200, Function | MediumTest | Level3) +{ + std::string path = context_->GetBundleResourcePath(); + std::string empty = ""; + EXPECT_STREQ(context_->GetBundleResourcePath().c_str(), empty.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetAppType_0100 + * @tc.name: GetAppType + * @tc.desc: Test whether AttachBaseContext is called normally, + * and verify whether the return value of GetAppType is correct. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetAppType_0100, Function | MediumTest | Level1) +{ + std::shared_ptr info = std::make_shared(); + info->bundleName = "hello"; + contextDeal_->SetApplicationInfo(info); + context_->AttachBaseContext(contextDeal_); + std::string path = context_->GetAppType(); + std::string appType = "system"; + + EXPECT_STREQ(context_->GetAppType().c_str(), appType.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetAppType_0200 + * @tc.name: GetAppType + * @tc.desc: Test GetAppType exception status. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetAppType_0200, Function | MediumTest | Level3) +{ + std::string path = context_->GetAppType(); + std::string empty = ""; + EXPECT_STREQ(context_->GetAppType().c_str(), empty.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetAbilityManager_0100 + * @tc.name: GetAbilityManager + * @tc.desc: Test whether AttachBaseContext is called normally, + * and verify whether the return value of GetAbilityManager is correct. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetAbilityManager_0100, Function | MediumTest | Level1) +{ + context_->AttachBaseContext(contextDeal_); + + sptr ptr = context_->GetAbilityManager(); + EXPECT_NE(ptr, nullptr); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetAbilityManager_0200 + * @tc.name: GetAbilityManager + * @tc.desc: Test GetAbilityManager exception status. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetAbilityManager_0200, Function | MediumTest | Level3) +{ + sptr ptr = context_->GetAbilityManager(); + EXPECT_EQ(ptr, nullptr); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetCodeCacheDir_0100 + * @tc.name: GetCodeCacheDir + * @tc.desc: Test whether AttachBaseContext is called normally, + * and verify whether the return value of GetCodeCacheDir is correct. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetCodeCacheDir_0100, Function | MediumTest | Level1) +{ + std::shared_ptr info = std::make_shared(); + std::string dir = "CodeCacheDir"; + info->dataDir = dir; + contextDeal_->SetApplicationInfo(info); + context_->AttachBaseContext(contextDeal_); + std::string dirCompare = "CodeCacheDir/code_cache"; + EXPECT_STREQ(context_->GetCodeCacheDir().c_str(), dirCompare.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetCodeCacheDir_0200 + * @tc.name: GetCodeCacheDir + * @tc.desc: Test GetCodeCacheDir exception status. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetCodeCacheDir_0200, Function | MediumTest | Level3) +{ + std::string empty = ""; + EXPECT_STREQ(context_->GetCodeCacheDir().c_str(), empty.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetCacheDir_0100 + * @tc.name: GetCacheDir + * @tc.desc: Test whether AttachBaseContext is called normally, + * and verify whether the return value of GetCacheDir is correct. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetCacheDir_0100, Function | MediumTest | Level1) +{ + std::shared_ptr info = std::make_shared(); + std::string dir = "CacheDir"; + info->cacheDir = dir; + contextDeal_->SetApplicationInfo(info); + context_->AttachBaseContext(contextDeal_); + + EXPECT_STREQ(context_->GetCacheDir().c_str(), dir.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetCacheDir_0200 + * @tc.name: GetCacheDir + * @tc.desc: Test GetCacheDir exception status. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetCacheDir_0200, Function | MediumTest | Level3) +{ + std::string empty = ""; + EXPECT_STREQ(context_->GetCacheDir().c_str(), empty.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetDatabaseDir_0100 + * @tc.name: GetDatabaseDir + * @tc.desc: Test whether AttachBaseContext is called normally, + * and verify whether the return value of GetDatabaseDir is correct. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetDatabaseDir_0100, Function | MediumTest | Level1) +{ + std::shared_ptr info = std::make_shared(); + std::string dir = "dataBaseDir"; + info->dataBaseDir = dir; + contextDeal_->SetApplicationInfo(info); + context_->AttachBaseContext(contextDeal_); + + EXPECT_STREQ(context_->GetDatabaseDir().c_str(), dir.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetCacheDir_0200 + * @tc.name: GetDatabaseDir + * @tc.desc: Test GetDatabaseDir exception status. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetDatabaseDir_0200, Function | MediumTest | Level3) +{ + std::string empty = ""; + EXPECT_STREQ(context_->GetDatabaseDir().c_str(), empty.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetDataDir_0100 + * @tc.name: GetDataDir + * @tc.desc: Test whether AttachBaseContext is called normally, + * and verify whether the return value of GetDataDir is correct. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetDataDir_0100, Function | MediumTest | Level1) +{ + std::shared_ptr info = std::make_shared(); + std::string dir = "dataDir"; + info->dataDir = dir; + contextDeal_->SetApplicationInfo(info); + context_->AttachBaseContext(contextDeal_); + + EXPECT_STREQ(context_->GetDataDir().c_str(), dir.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetDataDir_0200 + * @tc.name: GetDataDir + * @tc.desc: Test GetDataDir exception status. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetDataDir_0200, Function | MediumTest | Level3) +{ + std::string empty = ""; + EXPECT_STREQ(context_->GetDataDir().c_str(), empty.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetDir_0100 + * @tc.name: GetDir + * @tc.desc: Test whether AttachBaseContext is called normally, + * and verify whether the return value of GetDir is correct. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetDir_0100, Function | MediumTest | Level1) +{ + std::shared_ptr info = std::make_shared(); + std::string dir = "dataDir"; + info->dataDir = dir; + contextDeal_->SetApplicationInfo(info); + context_->AttachBaseContext(contextDeal_); + + std::string name = "name"; + std::string dirCompare = "dataDir/name"; + int mode = 0; + EXPECT_STREQ(context_->GetDir(name, mode).c_str(), dirCompare.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetDir_0200 + * @tc.name: GetDir + * @tc.desc: Test GetDir exception status. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetDir_0200, Function | MediumTest | Level3) +{ + std::string empty = ""; + std::string name = "name"; + int mode = 0; + EXPECT_STREQ(context_->GetDir(name, mode).c_str(), empty.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetFilesDir_0100 + * @tc.name: GetFilesDir + * @tc.desc: Test whether AttachBaseContext is called normally, + * and verify whether the return value of GetFilesDir is correct. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetFilesDir_0100, Function | MediumTest | Level1) +{ + std::shared_ptr info = std::make_shared(); + std::string dir = "codePath"; + info->dataDir = dir; + contextDeal_->SetApplicationInfo(info); + context_->AttachBaseContext(contextDeal_); + std::string dirCompare = "codePath/files"; + EXPECT_STREQ(context_->GetFilesDir().c_str(), dirCompare.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetFilesDir_0200 + * @tc.name: GetFilesDir + * @tc.desc: Test GetFilesDir exception status. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetFilesDir_0200, Function | MediumTest | Level3) +{ + std::string empty = ""; + EXPECT_STREQ(context_->GetFilesDir().c_str(), empty.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetAbilityInfo_0100 + * @tc.name: GetAbilityInfo + * @tc.desc: Test whether AttachBaseContext is called normally, + * and verify whether the return value of GetAbilityInfo is correct. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetAbilityInfo_0100, Function | MediumTest | Level1) +{ + std::shared_ptr info = std::make_shared(); + std::string resourcePath = "ResourcePath"; + info->resourcePath = resourcePath; + contextDeal_->SetAbilityInfo(info); + context_->AttachBaseContext(contextDeal_); + + EXPECT_STREQ(context_->GetAbilityInfo()->resourcePath.c_str(), resourcePath.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetAbilityInfo_0200 + * @tc.name: GetAbilityInfo + * @tc.desc: Test GetAbilityInfo exception status. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetAbilityInfo_0200, Function | MediumTest | Level3) +{ + std::shared_ptr ptr = context_->GetAbilityInfo(); + EXPECT_EQ(ptr, nullptr); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetContext_0100 + * @tc.name: GetContext + * @tc.desc: Test whether AttachBaseContext is called normally, + * and verify whether the return value of GetContext is correct. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetContext_0100, Function | MediumTest | Level1) +{ + std::shared_ptr ability = std::make_shared(); + std::shared_ptr context(ability); + contextDeal_->SetContext(context); + context_->AttachBaseContext(contextDeal_); + + EXPECT_NE(context_->GetContext(), nullptr); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetContext_0200 + * @tc.name: GetContext + * @tc.desc: Test GetContext exception status. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetContext_0200, Function | MediumTest | Level3) +{ + std::shared_ptr ptr = context_->GetContext(); + EXPECT_EQ(ptr, nullptr); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetApplicationContext_0100 + * @tc.name: GetApplicationContext + * @tc.desc: Test whether AttachBaseContext is called normally, + * and verify whether the return value of GetApplicationContext is correct. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetApplicationContext_0100, Function | MediumTest | Level1) +{ + std::shared_ptr application = std::make_shared(); + contextDeal_->SetApplicationContext(application); + context_->AttachBaseContext(contextDeal_); + + EXPECT_NE(nullptr, context_->GetApplicationContext()); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetApplicationContext_0200 + * @tc.name: GetApplicationContext + * @tc.desc: Test GetApplicationContext exception status. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetApplicationContext_0200, Function | MediumTest | Level3) +{ + std::shared_ptr ptr = context_->GetApplicationContext(); + EXPECT_EQ(ptr, nullptr); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetProcessInfo_0100 + * @tc.name: GetProcessInfo + * @tc.desc: Test whether AttachBaseContext is called normally, + * and verify whether the return value of GetProcessInfo is correct. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetProcessInfo_0100, Function | MediumTest | Level1) +{ + std::string name = "OHOS"; + pid_t id = 0; + ProcessInfo info(name, id); + std::shared_ptr processinfo = std::make_shared(info); + contextDeal_->SetProcessInfo(processinfo); + context_->AttachBaseContext(contextDeal_); + + EXPECT_STREQ(name.c_str(), context_->GetProcessInfo()->GetProcessName().c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetProcessInfo_0200 + * @tc.name: GetProcessInfo + * @tc.desc: Test GetProcessInfo exception status. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetProcessInfo_0200, Function | MediumTest | Level3) +{ + std::shared_ptr ptr = context_->GetProcessInfo(); + EXPECT_EQ(ptr, nullptr); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetProcessName_0100 + * @tc.name: GetProcessName + * @tc.desc: Test whether AttachBaseContext is called normally, + * and verify whether the return value of GetProcessName is correct. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextDeal_GetProcessName_0100, Function | MediumTest | Level1) +{ + std::string name = "OHOS"; + pid_t id = 0; + ProcessInfo info(name, id); + std::shared_ptr processinfo = std::make_shared(info); + contextDeal_->SetProcessInfo(processinfo); + context_->AttachBaseContext(contextDeal_); + + EXPECT_STREQ(name.c_str(), context_->GetProcessName().c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextContainer_GetProcessName_0200 + * @tc.name: GetProcessName + * @tc.desc: Test GetProcessName exception status. + */ +HWTEST_F(ContextContainerTest, AppExecFwk_ContextContainer_GetProcessName_0200, Function | MediumTest | Level3) +{ + std::string empty = ""; + std::string name = context_->GetProcessName(); + EXPECT_STREQ(empty.c_str(), name.c_str()); +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/kits/appkit/native/test/unittest/context_deal_test.cpp b/kits/appkit/native/test/unittest/context_deal_test.cpp new file mode 100644 index 000000000..a3035f3a1 --- /dev/null +++ b/kits/appkit/native/test/unittest/context_deal_test.cpp @@ -0,0 +1,326 @@ +/* + * 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 "ohos_application.h" +#include "ability.h" +#include "context_deal.h" +#include "process_info.h" +#include "system_ability_definition.h" +#include "sys_mgr_client.h" +#include "mock_bundle_manager.h" + +namespace OHOS { +namespace AppExecFwk { +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; + +class ContextDealTest : public testing::Test { +public: + ContextDealTest() : context_(nullptr) + {} + ~ContextDealTest() + {} + std::shared_ptr context_ = nullptr; + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void ContextDealTest::SetUpTestCase(void) +{} + +void ContextDealTest::TearDownTestCase(void) +{} + +void ContextDealTest::SetUp(void) +{ + + OHOS::sptr bundleObject = new (std::nothrow) BundleMgrService(); + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility( + OHOS::BUNDLE_MGR_SERVICE_SYS_ABILITY_ID, bundleObject); + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility( + OHOS::ABILITY_MGR_SERVICE_ID, bundleObject); + context_ = std::make_shared(); +} + +void ContextDealTest::TearDown(void) +{} + +/** + * @tc.number: AppExecFwk_ContextDeal_StartAbility_0100 + * @tc.name: StartAbility + * @tc.desc: Test whether startability is called normally. + */ +HWTEST_F(ContextDealTest, AppExecFwk_ContextDeal_StartAbility_0100, Function | MediumTest | Level1) +{ + GTEST_LOG_(INFO) << "AppExecFwk_ContextDeal_StartAbility_0100 start"; + AAFwk::Want want; + int requestCode = 0; + context_->StartAbility(want, requestCode); + GTEST_LOG_(INFO) << "AppExecFwk_ContextDeal_StartAbility_0100 end, StartAbility is empty"; +} + +/** + * @tc.number: AppExecFwk_ContextDeal_GetBundleName_0100 + * @tc.name: GetBundleName + * @tc.desc: Verify that the GetBundleName return value is correct. + */ +HWTEST_F(ContextDealTest, AppExecFwk_ContextDeal_GetBundleName_0100, Function | MediumTest | Level1) +{ + std::shared_ptr info = std::make_shared(); + std::string bundleName = "BundleName"; + info->bundleName = bundleName; + context_->SetApplicationInfo(info); + + EXPECT_STREQ(context_->GetBundleName().c_str(), bundleName.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextDeal_GetBundleManager_0100 + * @tc.name: GetBundleManager + * @tc.desc: Verify that the GetBundleManager return value is correct. + */ +HWTEST_F(ContextDealTest, AppExecFwk_ContextDeal_GetBundleManager_0100, Function | MediumTest | Level3) +{ + sptr ptr = context_->GetBundleManager(); + EXPECT_NE(ptr, nullptr); +} + +/** + * @tc.number: AppExecFwk_ContextDeal_GetBundleCodePath_0100 + * @tc.name: GetBundleCodePath + * @tc.desc: Verify that the GetBundleCodePath return value is correct. + */ +HWTEST_F(ContextDealTest, AppExecFwk_ContextDeal_GetBundleCodePath_0100, Function | MediumTest | Level1) +{ + std::shared_ptr info = std::make_shared(); + std::string codePath = "CodePath"; + info->codePath = codePath; + context_->SetApplicationInfo(info); + + EXPECT_STREQ(context_->GetBundleCodePath().c_str(), codePath.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextDeal_GetApplicationInfo_0100 + * @tc.name: GetApplicationInfo + * @tc.desc: Verify that the GetApplicationInfo return value is correct. + */ +HWTEST_F(ContextDealTest, AppExecFwk_ContextDeal_GetApplicationInfo_0100, Function | MediumTest | Level1) +{ + std::shared_ptr info = std::make_shared(); + std::string bundleName = "BundleName"; + info->bundleName = bundleName; + context_->SetApplicationInfo(info); + + EXPECT_STREQ(context_->GetApplicationInfo()->bundleName.c_str(), bundleName.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextDeal_GetBundleResourcePath_0100 + * @tc.name: GetBundleResourcePath + * @tc.desc: Verify that the GetBundleResourcePath return value is correct. + */ +HWTEST_F(ContextDealTest, AppExecFwk_ContextDeal_GetBundleResourcePath_0100, Function | MediumTest | Level1) +{ + std::shared_ptr info = std::make_shared(); + std::string resourcePath = "ResourcePath"; + info->resourcePath = resourcePath; + context_->SetAbilityInfo(info); + + EXPECT_STREQ(context_->GetBundleResourcePath().c_str(), resourcePath.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextDeal_GetAbilityManager_0100 + * @tc.name: GetAbilityManager + * @tc.desc: Verify that the GetAbilityManager return value is correct. + */ +HWTEST_F(ContextDealTest, AppExecFwk_ContextDeal_GetAbilityManager_0100, Function | MediumTest | Level3) +{ + sptr ptr = context_->GetAbilityManager(); + EXPECT_NE(ptr, nullptr); +} + +/** + * @tc.number: AppExecFwk_ContextDeal_GetCodeCacheDir_0100 + * @tc.name: GetCodeCacheDir + * @tc.desc: Verify that the GetCodeCacheDir return value is correct. + */ +HWTEST_F(ContextDealTest, AppExecFwk_ContextDeal_GetCodeCacheDir_0100, Function | MediumTest | Level1) +{ + std::shared_ptr info = std::make_shared(); + std::string dir = "CodeCacheDir"; + info->dataDir = dir; + context_->SetApplicationInfo(info); + dir = dir + "/" + "code_cache"; + + EXPECT_STREQ(context_->GetCodeCacheDir().c_str(), dir.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextDeal_GetCacheDir_0100 + * @tc.name: GetCacheDir + * @tc.desc: Verify that the GetCacheDir return value is correct. + */ +HWTEST_F(ContextDealTest, AppExecFwk_ContextDeal_GetCacheDir_0100, Function | MediumTest | Level1) +{ + std::shared_ptr info = std::make_shared(); + std::string dir = "CacheDir"; + info->cacheDir = dir; + context_->SetApplicationInfo(info); + + EXPECT_STREQ(context_->GetCacheDir().c_str(), dir.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextDeal_GetDatabaseDir_0100 + * @tc.name: GetDatabaseDir + * @tc.desc: Verify that the GetDatabaseDir return value is correct. + */ +HWTEST_F(ContextDealTest, AppExecFwk_ContextDeal_GetDatabaseDir_0100, Function | MediumTest | Level1) +{ + std::shared_ptr info = std::make_shared(); + std::string dir = "dataBaseDir"; + info->dataBaseDir = dir; + context_->SetApplicationInfo(info); + + EXPECT_STREQ(context_->GetDatabaseDir().c_str(), dir.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextDeal_GetFilesDir_0100 + * @tc.name: GetFilesDir + * @tc.desc: Verify that the GetFilesDir return value is correct. + */ +HWTEST_F(ContextDealTest, AppExecFwk_ContextDeal_GetFilesDir_0100, Function | MediumTest | Level1) +{ + std::shared_ptr info = std::make_shared(); + std::string dir = "codePath"; + info->dataDir = dir; + context_->SetApplicationInfo(info); + dir = dir + "/" + "files"; + + EXPECT_STREQ(context_->GetFilesDir().c_str(), dir.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextDeal_GetDataDir_0100 + * @tc.name: GetDataDir + * @tc.desc: Verify that the GetDataDir return value is correct. + */ +HWTEST_F(ContextDealTest, AppExecFwk_ContextDeal_GetDataDir_0100, Function | MediumTest | Level1) +{ + std::shared_ptr info = std::make_shared(); + std::string dir = "dataDir"; + info->dataDir = dir; + context_->SetApplicationInfo(info); + + EXPECT_STREQ(context_->GetDataDir().c_str(), dir.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextDeal_GetAppType_0100 + * @tc.name: GetAppType + * @tc.desc: Verify that the GetAppType return value is correct. + */ +HWTEST_F(ContextDealTest, AppExecFwk_ContextDeal_GetAppType_0100, Function | MediumTest | Level1) +{ + std::shared_ptr info = std::make_shared(); + info->bundleName = "hello"; + context_->SetApplicationInfo(info); + + std::string path = context_->GetAppType(); + std::string AppType = "system"; + + EXPECT_NE(path.c_str(), AppType.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextDeal_GetAbilityInfo_0100 + * @tc.name: GetAbilityInfo + * @tc.desc: Verify that the GetAbilityInfo return value is correct. + */ +HWTEST_F(ContextDealTest, AppExecFwk_ContextDeal_GetAbilityInfo_0100, Function | MediumTest | Level1) +{ + std::shared_ptr info = std::make_shared(); + std::string codePath = "CodePath"; + info->codePath = codePath; + context_->SetAbilityInfo(info); + + EXPECT_STREQ(context_->GetAbilityInfo()->codePath.c_str(), codePath.c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextDeal_GetContext_0100 + * @tc.name: GetContext + * @tc.desc: Verify that the GetContext return value is correct. + */ +HWTEST_F(ContextDealTest, AppExecFwk_ContextDeal_GetContext_0100, Function | MediumTest | Level3) +{ + std::shared_ptr ability = std::make_shared(); + std::shared_ptr context(ability); + context_->SetContext(context); + + EXPECT_NE(context_->GetContext(), nullptr); +} + +/** + * @tc.number: AppExecFwk_ContextDeal_GetApplicationContext_0100 + * @tc.name: GetApplicationContext + * @tc.desc: Verify that the GetApplicationContext return value is correct. + */ +HWTEST_F(ContextDealTest, AppExecFwk_ContextDeal_GetApplicationContext_0100, Function | MediumTest | Level3) +{ + std::shared_ptr application = std::make_shared(); + context_->SetApplicationContext(application); + EXPECT_NE(nullptr, context_->GetApplicationContext()); +} + +/** + * @tc.number: AppExecFwk_ContextDeal_GetProcessInfo_0100 + * @tc.name: GetProcessInfo + * @tc.desc: Verify that the GetProcessInfo return value is correct. + */ +HWTEST_F(ContextDealTest, AppExecFwk_ContextDeal_GetProcessInfo_0100, Function | MediumTest | Level1) +{ + std::string name = "OHOS"; + pid_t id = 0; + ProcessInfo info(name, id); + std::shared_ptr processinfo = std::make_shared(info); + context_->SetProcessInfo(processinfo); + EXPECT_STREQ(name.c_str(), context_->GetProcessInfo()->GetProcessName().c_str()); +} + +/** + * @tc.number: AppExecFwk_ContextDeal_GetProcessName_0100 + * @tc.name: GetProcessName + * @tc.desc: Verify that the GetProcessName return value is correct. + */ +HWTEST_F(ContextDealTest, AppExecFwk_ContextDeal_GetProcessName_0100, Function | MediumTest | Level1) +{ + std::string name = "OHOS"; + pid_t id = 0; + ProcessInfo info(name, id); + std::shared_ptr processinfo = std::make_shared(info); + context_->SetProcessInfo(processinfo); + EXPECT_STREQ(name.c_str(), context_->GetProcessName().c_str()); +} +} // namespace AppExecFwk +} \ No newline at end of file diff --git a/kits/appkit/test/BUILD.gn b/kits/appkit/test/BUILD.gn new file mode 100755 index 000000000..c2069eb70 --- /dev/null +++ b/kits/appkit/test/BUILD.gn @@ -0,0 +1,214 @@ +# 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") + +module_output_path = "appexecfwk_standard/moduletest/application_test/" + +#APP_INNERKITS_PATH = "//foundation/appexecfwk/standard/interfaces/innerkits" +ABILITY_INNERKITS_PATH = "//foundation/aafwk/standard/interfaces/innerkits" + +############################################################################### +config("module_private_config") { + visibility = [ ":*" ] + include_dirs = [ + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include/appmgr", + "//foundation/aafwk/standard/interfaces/innerkits/want/include/ohos/aafwk_L2/content", + "//EOSP/communication/libsoftbus/../../../foundation/distributedschedule/dmsfwk/services/dtbschedmgr/include", + "//foundation/appexecfwk/standard/kits/appkit/native/test/mock/include", + + #"//foundation/aafwk/standard/frameworks/kits/ability/native/test/mock/include", + "//foundation/appexecfwk/standard/kits/appkit/test/Mock/include", + "//foundation/appexecfwk/standard/kits/appkit/native/app/include", + + #"//foundation/communication/utils/include", + #"//foundation/communication/ipc/ipc/native/src/core/include", + #"//foundation/communication/ipc/utils/include", + ] + + defines = [ + "APP_LOG_TAG = \"ApplicationModuleTest\"", + "LOG_DOMAIN = 0xD001152", + ] +} + +ohos_moduletest("appexecfwk_appkit_native_app_module_test_first") { + module_out_path = module_output_path + sources = [ + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/src/appmgr/app_mgr_stub.cpp", + "Mock/include/mock_app_thread.cpp", + "Mock/include/mock_application.cpp", + + #"Mock/include/mock_ipc_object_stub.cpp", + "Mock/include/sys_mgr_client_mock.cpp", + "moduletest/appexecfwk_appkit_native_app_module_test_first.cpp", + ] + + configs = [ ":module_private_config" ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${ABILITY_INNERKITS_PATH}/want:want", + "//foundation/aafwk/standard/frameworks/kits/ability/native:abilitykit_native", + "//foundation/aafwk/standard/interfaces/innerkits/ability_manager:ability_manager", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/appexecfwk/standard/common:libappexecfwk_common", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler:libeventhandler", + "//foundation/appexecfwk/standard/kits:appkit_native", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/googletest:gmock_main", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +ohos_moduletest("appexecfwk_appkit_native_app_module_test_second") { + module_out_path = module_output_path + sources = [ + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/src/appmgr/app_mgr_stub.cpp", + "Mock/include/mock_app_thread.cpp", + "Mock/include/mock_application.cpp", + + #"Mock/include/mock_ipc_object_stub.cpp", + "Mock/include/sys_mgr_client_mock.cpp", + "moduletest/appexecfwk_appkit_native_app_module_test_second.cpp", + ] + + configs = [ ":module_private_config" ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${ABILITY_INNERKITS_PATH}/want:want", + "//foundation/aafwk/standard/frameworks/kits/ability/native:abilitykit_native", + "//foundation/aafwk/standard/interfaces/innerkits/ability_manager:ability_manager", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/appexecfwk/standard/common:libappexecfwk_common", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler:libeventhandler", + "//foundation/appexecfwk/standard/kits:appkit_native", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/googletest:gmock_main", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +ohos_moduletest("appexecfwk_appkit_native_app_module_test_third") { + module_out_path = module_output_path + sources = [ + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/src/appmgr/app_mgr_stub.cpp", + "Mock/include/mock_app_thread.cpp", + "Mock/include/mock_application.cpp", + + #"Mock/include/mock_ipc_object_stub.cpp", + "Mock/include/sys_mgr_client_mock.cpp", + "moduletest/appexecfwk_appkit_native_app_module_test_third.cpp", + ] + + configs = [ ":module_private_config" ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${ABILITY_INNERKITS_PATH}/want:want", + "//foundation/aafwk/standard/frameworks/kits/ability/native:abilitykit_native", + "//foundation/aafwk/standard/interfaces/innerkits/ability_manager:ability_manager", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/appexecfwk/standard/common:libappexecfwk_common", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler:libeventhandler", + "//foundation/appexecfwk/standard/kits:appkit_native", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/googletest:gmock_main", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +ohos_moduletest("appexecfwk_appkit_native_app_module_test_fourth") { + module_out_path = module_output_path + sources = [ + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/src/appmgr/app_mgr_stub.cpp", + "Mock/include/mock_app_thread.cpp", + "Mock/include/mock_application.cpp", + + #"Mock/include/mock_ipc_object_stub.cpp", + "Mock/include/sys_mgr_client_mock.cpp", + "moduletest/appexecfwk_appkit_native_app_module_test_fourth.cpp", + ] + + configs = [ ":module_private_config" ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${ABILITY_INNERKITS_PATH}/want:want", + "//foundation/aafwk/standard/frameworks/kits/ability/native:abilitykit_native", + "//foundation/aafwk/standard/interfaces/innerkits/ability_manager:ability_manager", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/appexecfwk/standard/common:libappexecfwk_common", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler:libeventhandler", + "//foundation/appexecfwk/standard/kits:appkit_native", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/googletest:gmock_main", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +############################################################################### + +group("moduletest") { + testonly = true + deps = [] + + deps += [ + ":appexecfwk_appkit_native_app_module_test_first", + ":appexecfwk_appkit_native_app_module_test_fourth", + ":appexecfwk_appkit_native_app_module_test_second", + ":appexecfwk_appkit_native_app_module_test_third", + ] +} +############################################################################### diff --git a/kits/appkit/test/Mock/include/mock_ability_mgr_service.h b/kits/appkit/test/Mock/include/mock_ability_mgr_service.h new file mode 100644 index 000000000..dc86444d2 --- /dev/null +++ b/kits/appkit/test/Mock/include/mock_ability_mgr_service.h @@ -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. + */ + +#ifndef FOUNDATION_APPEXECFWK_KITS_APPKIT_TEST_MOCK_ABILITY_MGR_SERVICE_H +#define FOUNDATION_APPEXECFWK_KITS_APPKIT_TEST_MOCK_ABILITY_MGR_SERVICE_H + +#include "gmock/gmock.h" +#include "semaphore_ex.h" +#include "ability_manager_stub.h" + +namespace OHOS { +namespace AAFwk { +class MockAbilityMgrService : public AbilityManagerStub { +public: + MOCK_METHOD2(StartAbility, int(const Want &want, int requestCode)); + MOCK_METHOD3(StartAbility, int(const Want &want, const sptr &callerToken, int requestCode)); + MOCK_METHOD3(TerminateAbility, int(const sptr &token, int resultCode, const Want *resultWant)); + MOCK_METHOD3(ConnectAbility, + int(const Want &want, const sptr &connect, const sptr &callerToken)); + MOCK_METHOD1(DisconnectAbility, int(const sptr &connect)); + MOCK_METHOD3(AcquireDataAbility, sptr(const Uri &, bool, const sptr &)); + MOCK_METHOD2(ReleaseDataAbility, int(sptr, const sptr &)); + MOCK_METHOD2(AddWindowInfo, void(const sptr &token, int32_t windowToken)); + MOCK_METHOD2(AttachAbilityThread, int(const sptr &scheduler, const sptr &token)); + MOCK_METHOD2(AbilityTransitionDone, int(const sptr &token, int state)); + MOCK_METHOD2( + ScheduleConnectAbilityDone, int(const sptr &token, const sptr &remoteObject)); + MOCK_METHOD1(ScheduleDisconnectAbilityDone, int(const sptr &token)); + MOCK_METHOD1(ScheduleCommandAbilityDone, int(const sptr &token)); + void DumpState(const std::string &args, std::vector &state) + { + GTEST_LOG_(INFO) << "MockAbilityMgrService::DumpState called"; + DumpStateCalled_ = true; + EXPECT_TRUE(DumpStateCalled_); + return; + } + MOCK_METHOD2(TerminateAbilityResult, int(const sptr &, int startId)); + MOCK_METHOD2(TerminateAbilityByCaller, int(const sptr &callerToken, int requestCode)); + MOCK_METHOD1(StopServiceAbility, int(const Want &)); + MOCK_METHOD1(GetAllStackInfo, int(StackInfo &stackInfo)); + MOCK_METHOD3(GetRecentMissions, int(const int32_t, const int32_t, std::vector &)); + MOCK_METHOD2(GetMissionSnapshot, int(const int32_t, MissionSnapshotInfo &)); + MOCK_METHOD1(RemoveMission, int(int)); + MOCK_METHOD1(RemoveStack, int(int)); + MOCK_METHOD4(OnRemoteRequest, int(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option)); + + MOCK_METHOD1(MoveMissionToTop, int(int32_t)); + MOCK_METHOD1(KillProcess, int(const std::string &bundleName)); + MOCK_METHOD1(UninstallApp, int(const std::string &bundleName)); + MOCK_METHOD1(TerminateAbilityByRecordId, int(const int64_t recordId)); + + void Wait() + { + sem_.Wait(); + } + + int Post() + { + sem_.Post(); + return 0; + } + + void PostVoid() + { + sem_.Post(); + } + +private: + bool DumpStateCalled_ = false; + Semaphore sem_; +}; + +} // namespace AAFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_KITS_APPKIT_TEST_MOCK_ABILITY_MGR_SERVICE_H \ No newline at end of file diff --git a/kits/appkit/test/Mock/include/mock_ability_token.h b/kits/appkit/test/Mock/include/mock_ability_token.h new file mode 100644 index 000000000..76db37b1c --- /dev/null +++ b/kits/appkit/test/Mock/include/mock_ability_token.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_KITS_APPKIT_TEST_MOCK_INCLUDE_MOCK_ABILITY_TOKEN_H +#define FOUNDATION_APPEXECFWK_KITS_APPKIT_TEST_MOCK_INCLUDE_MOCK_ABILITY_TOKEN_H + +#include "nocopyable.h" +#include "iremote_broker.h" +#include "iremote_object.h" +#include "iremote_proxy.h" +#include "iremote_stub.h" + +namespace OHOS { +namespace AppExecFwk { + +class IAbilityToken : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.appexecfwk.AbilityToken"); +}; + +class MockAbilityToken : public IRemoteStub { +public: + MockAbilityToken() = default; + virtual ~MockAbilityToken() = default; + + virtual int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) + { + return 0; + } + +private: + DISALLOW_COPY_AND_MOVE(MockAbilityToken); +}; + +class AbilityTokenProxy : public IRemoteProxy { +public: + explicit AbilityTokenProxy(const sptr &impl) : IRemoteProxy(impl) + {} + + virtual ~AbilityTokenProxy() = default; + +private: + DISALLOW_COPY_AND_MOVE(AbilityTokenProxy); +}; + +DECLARE_INTERFACE_DESCRIPTOR(u"IAbilityToken"); + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_KITS_APPKIT_TEST_MOCK_INCLUDE_MOCK_ABILITY_TOKEN_H diff --git a/kits/appkit/test/Mock/include/mock_app_mgr_service.h b/kits/appkit/test/Mock/include/mock_app_mgr_service.h new file mode 100755 index 000000000..426122233 --- /dev/null +++ b/kits/appkit/test/Mock/include/mock_app_mgr_service.h @@ -0,0 +1,265 @@ +/* + * 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_KITS_APPKIT_TEST_MOCK_INCLUDE_MOCK_APP_MGR_SERVICE_H +#define FOUNDATION_APPEXECFWK_KITS_APPKIT_TEST_MOCK_INCLUDE_MOCK_APP_MGR_SERVICE_H + +#include +#include "gmock/gmock.h" +#include "semaphore_ex.h" +#include "app_scheduler_interface.h" +#include "app_mgr_stub.h" +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { +class MockAppMgrService : public AppMgrStub { +public: + MOCK_METHOD4(LoadAbility, + void(const sptr &token, const sptr &preToken, + const std::shared_ptr &abilityInfo, const std::shared_ptr &appInfo)); + MOCK_METHOD1(TerminateAbility, void(const sptr &token)); + MOCK_METHOD2(UpdateAbilityState, void(const sptr &token, const AbilityState state)); + + virtual void AttachApplication(const sptr &app) override + { + GTEST_LOG_(INFO) << "MockAppMgrService::AttachApplication called"; + Attached_ = true; + EXPECT_TRUE(Attached_); + Appthread_ = iface_cast(app); + } + + virtual void ApplicationForegrounded(const int32_t recordId) + { + GTEST_LOG_(INFO) << "MockAppMgrService::ApplicationForegrounded called"; + Foregrounded_ = true; + EXPECT_TRUE(Foregrounded_); + } + + virtual void ApplicationBackgrounded(const int32_t recordId) + { + GTEST_LOG_(INFO) << "MockAppMgrService::ApplicationBackgrounded called"; + Backgrounded_ = true; + EXPECT_TRUE(Backgrounded_); + } + + virtual void ApplicationTerminated(const int32_t recordId) + { + GTEST_LOG_(INFO) << "MockAppMgrService::ApplicationTerminated called"; + Terminated_ = true; + EXPECT_TRUE(Terminated_); + } + MOCK_METHOD2(CheckPermission, int32_t(const int32_t recordId, const std::string &permission)); + + virtual void AbilityCleaned(const sptr &token) + { + GTEST_LOG_(INFO) << "MockAppMgrService::AbilityCleaned called"; + Cleaned_ = true; + EXPECT_TRUE(Cleaned_); + } + + MOCK_METHOD1(KillApplication, int(const std::string &appName)); + + virtual sptr GetAmsMgr() override + { + return nullptr; + }; + virtual void ClearUpApplicationData(const std::string &appName) override{}; + virtual int IsBackgroundRunningRestricted(const std::string &appName) override + { + return 0; + }; + virtual int GetAllRunningProcesses(std::shared_ptr &runningProcessInfo) override + { + return 0; + }; + + virtual void RegisterAppStateCallback(const sptr &callback) + { + callback_ = callback; + } + + int32_t CheckPermissionImpl([[maybe_unused]] const int32_t recordId, const std::string &data) + { + data_ = data; + return 0; + } + + void KillApplicationImpl(const std::string &data) + { + data_ = data; + } + + const std::string &GetData() const + { + return data_; + } + + void Wait() + { + sem_.Wait(); + } + + void Post() + { + sem_.Post(); + } + + void UpdateState() const + { + if (!callback_) { + return; + } + AppProcessData processData; + processData.appName = ""; + processData.pid = 1; + processData.appState = ApplicationState::APP_STATE_BEGIN; + callback_->OnAppStateChanged(processData); + } + + void Terminate(const sptr &token) const + { + if (!callback_) { + return; + } + AbilityState st = AbilityState::ABILITY_STATE_BEGIN; + callback_->OnAbilityRequestDone(token, st); + } + + void ScheduleTerminateApplication() + { + if (Appthread_ != nullptr) { + Appthread_->ScheduleTerminateApplication(); + } + } + + void ScheduleLaunchApplication(const AppLaunchData &lanchdata) + { + if (Appthread_ != nullptr) { + Appthread_->ScheduleLaunchApplication(lanchdata); + } + } + + void ScheduleForegroundApplication() + { + if (Appthread_ != nullptr) { + Appthread_->ScheduleForegroundApplication(); + } + } + + void ScheduleBackgroundApplication() + { + if (Appthread_ != nullptr) { + Appthread_->ScheduleBackgroundApplication(); + } + } + + void ScheduleShrinkMemory(const int32_t level) + { + if (Appthread_ != nullptr) { + Appthread_->ScheduleShrinkMemory(level); + } + } + + void ScheduleLowMemory() + { + if (Appthread_ != nullptr) { + Appthread_->ScheduleLowMemory(); + } + } + + void ScheduleLaunchAbility(const AbilityInfo &abilityinf, const sptr &token) + { + if (Appthread_ != nullptr) { + Appthread_->ScheduleLaunchAbility(abilityinf, token); + } + } + + void ScheduleCleanAbility(const sptr &token) + { + if (Appthread_ != nullptr) { + Appthread_->ScheduleCleanAbility(token); + } + } + + void ScheduleProfileChanged(const Profile &profile) + { + if (Appthread_ != nullptr) { + Appthread_->ScheduleProfileChanged(profile); + } + } + + void ScheduleConfigurationUpdated(const Configuration &config) + { + if (Appthread_ != nullptr) { + Appthread_->ScheduleConfigurationUpdated(config); + } + } + + sptr GetAppthread() + { + return Appthread_; + } + + bool IsAttached() + { + APP_LOGI("MockAppMgrService::IsAttached Attached_ = %{public}d", Attached_); + return Attached_; + } + + bool IsForegrounded() + { + APP_LOGI("MockAppMgrService::IsForegrounded Foregrounded_ = %{public}d", Foregrounded_); + return Foregrounded_; + } + + bool IsBackgrounded() + { + APP_LOGI("MockAppMgrService::IsBackgrounded Backgrounded_ = %{public}d", Backgrounded_); + return Backgrounded_; + } + + bool IsTerminated() + { + APP_LOGI("MockAppMgrService::IsTerminated Terminated_ = %{public}d", Terminated_); + return Terminated_; + } + + void init() + { + APP_LOGI("MockAppMgrService::init called"); + Attached_ = false; + } + + bool AddDeathRecipient(const sptr &recipient) + { + return true; + } + +private: + bool Attached_ = false; + bool Foregrounded_ = false; + bool Backgrounded_ = false; + bool Terminated_ = false; + bool Cleaned_ = false; + sptr Appthread_ = nullptr; + Semaphore sem_; + std::string data_; + sptr callback_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_KITS_APPKIT_TEST_MOCK_INCLUDE_MOCK_APP_MGR_SERVICE_H \ No newline at end of file diff --git a/kits/appkit/test/Mock/include/mock_app_thread.cpp b/kits/appkit/test/Mock/include/mock_app_thread.cpp new file mode 100644 index 000000000..81be10f29 --- /dev/null +++ b/kits/appkit/test/Mock/include/mock_app_thread.cpp @@ -0,0 +1,28 @@ +/* + * 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 "mock_app_thread.h" + +namespace OHOS { +namespace AppExecFwk { + +MockHandler::MockHandler(const std::shared_ptr &runner) : EventHandler(runner) +{} + +void MockHandler::ProcessEvent([[maybe_unused]] const InnerEvent::Pointer &event) +{} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/kits/appkit/test/Mock/include/mock_app_thread.h b/kits/appkit/test/Mock/include/mock_app_thread.h new file mode 100644 index 000000000..5494fa13f --- /dev/null +++ b/kits/appkit/test/Mock/include/mock_app_thread.h @@ -0,0 +1,38 @@ +/* + * 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_KITS_APPKIT_TEST_MOCK_APP_THREAD_H +#define FOUNDATION_APPEXECFWK_KITS_APPKIT_TEST_MOCK_APP_THREAD_H + +#include +#include "event_handler.h" +#include "refbase.h" +#include "ohos_application.h" +#include "ability_local_record.h" + +namespace OHOS { +namespace AppExecFwk { + +class MockHandler : public EventHandler { +public: + explicit MockHandler(const std::shared_ptr &runner); + ~MockHandler() + {} + void ProcessEvent(const InnerEvent::Pointer &event) override; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_KITS_APPKIT_TEST_MOCK_APP_THREAD_H \ No newline at end of file diff --git a/kits/appkit/test/Mock/include/mock_application.cpp b/kits/appkit/test/Mock/include/mock_application.cpp new file mode 100644 index 000000000..de52ba520 --- /dev/null +++ b/kits/appkit/test/Mock/include/mock_application.cpp @@ -0,0 +1,193 @@ +/* + * 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 "mock_application.h" +#include "ability.h" +#include "app_loader.h" + +const int INMOCKAPPLICATION_ONE = 9996; +const int INMOCKAPPLICATION_TWO = 9997; +const int INMOCKAPPLICATION_THREE = 9998; +#define NUMBER (10) + +namespace OHOS { +namespace AppExecFwk { + +REGISTER_APPLICATION("MockTestApplication", MockApplication) + +MockApplication::MockApplication() +{ + elementCallBack_ = std::make_shared(); + lifecycleCallBack_ = std::make_shared(); +} + +void MockApplication::OnConfigurationUpdated(const Configuration &config) +{ + GTEST_LOG_(INFO) << "MockApplication::OnConfigurationUpdated called"; + bool iscalled = true; + EXPECT_TRUE(iscalled); + if (INMOCKAPPLICATION_TWO == GetProcessInfo()->GetPid()) { + RegisterElementsCallbacks(elementCallBack_); + OHOSApplication::OnConfigurationUpdated(config); + UnregisterElementsCallbacks(elementCallBack_); + OHOSApplication::OnConfigurationUpdated(config); + } +} + +void MockApplication::OnMemoryLevel(int level) +{ + GTEST_LOG_(INFO) << "MockApplication::OnMemoryLevel called"; + bool iscalled = true; + EXPECT_TRUE(iscalled); + level_ = level; + EXPECT_EQ(level, level_); + if (INMOCKAPPLICATION_TWO == GetProcessInfo()->GetPid()) { + RegisterElementsCallbacks(elementCallBack_); + OHOSApplication::OnMemoryLevel(level); + UnregisterElementsCallbacks(elementCallBack_); + OHOSApplication::OnMemoryLevel(level); + } +} + +void MockApplication::OnForeground() +{ + GTEST_LOG_(INFO) << "MockApplication::OnForeground called"; + bool iscalled = true; + EXPECT_TRUE(iscalled); +} + +void MockApplication::OnBackground() +{ + GTEST_LOG_(INFO) << "MockApplication::OnBackground called"; + bool iscalled = true; + EXPECT_TRUE(iscalled); +} + +void MockApplication::OnStart() +{ + GTEST_LOG_(INFO) << "MockApplication::OnStart called"; + bool iscalled = true; + EXPECT_TRUE(iscalled); + int a = 1; + EXPECT_EQ(1, a); + + if (INMOCKAPPLICATION_THREE == GetProcessInfo()->GetPid()) { + EXPECT_STREQ("TestProcess", GetProcessInfo()->GetProcessName().c_str()); + EXPECT_STREQ("/hos/lib/cacheDir", GetCacheDir().c_str()); + EXPECT_STREQ("/hos/lib/cacheDir", GetCodeCacheDir().c_str()); + EXPECT_STREQ("/hos/lib/dataBaseDir", GetDatabaseDir().c_str()); + EXPECT_STREQ("/hos/lib/dataDir", GetDataDir().c_str()); + EXPECT_STREQ("/hos/lib/dataDir", GetDir("test", 1).c_str()); + EXPECT_STREQ("MockBundleName", GetBundleName().c_str()); + EXPECT_STREQ("MockTestApplication", GetApplicationInfo()->name.c_str()); + + EXPECT_STREQ("", GetBundleCodePath().c_str()); + EXPECT_STREQ("", GetBundleResourcePath().c_str()); + EXPECT_EQ(nullptr, GetContext()); + EXPECT_EQ(nullptr, GetAbilityInfo()); + EXPECT_STREQ("/hos/lib/dataDir", GetApplicationContext()->GetDir("test", 1).c_str()); + std::vector state; + EXPECT_NE(nullptr, GetAbilityManager()); + if (nullptr != GetAbilityManager()) { + GetAbilityManager()->DumpState("test", state); + } + + EXPECT_NE(nullptr, GetBundleManager()); + if (nullptr != GetBundleManager()) { + EXPECT_STREQ("ModuleTestType", GetBundleManager()->GetAppType("test").c_str()); + } + } else if (INMOCKAPPLICATION_ONE == GetProcessInfo()->GetPid()) { + RegisterAbilityLifecycleCallbacks(lifecycleCallBack_); + + std::shared_ptr ability = std::make_shared(); + PacMap pacmap; + + OHOSApplication::OnAbilityStart(ability); + OHOSApplication::OnAbilityInactive(ability); + OHOSApplication::OnAbilityBackground(ability); + OHOSApplication::OnAbilityForeground(ability); + OHOSApplication::OnAbilityActive(ability); + OHOSApplication::OnAbilityStop(ability); + OHOSApplication::OnAbilitySaveState(pacmap); + + UnregisterAbilityLifecycleCallbacks(lifecycleCallBack_); + + OHOSApplication::OnAbilityStart(ability); + OHOSApplication::OnAbilityInactive(ability); + OHOSApplication::OnAbilityBackground(ability); + OHOSApplication::OnAbilityForeground(ability); + OHOSApplication::OnAbilityActive(ability); + OHOSApplication::OnAbilityStop(ability); + OHOSApplication::OnAbilitySaveState(pacmap); + } +} + +void MockApplication::OnTerminate() +{ + GTEST_LOG_(INFO) << "MockApplication::OnTerminate called"; + bool iscalled = true; + EXPECT_TRUE(iscalled); +} + +void MockModuleElementsCallback::OnConfigurationUpdated( + const std::shared_ptr &ability, const Configuration &config) +{ + GTEST_LOG_(INFO) << "MockModuleElementsCallback::OnConfigurationUpdated called"; + EXPECT_STREQ(config.GetName().c_str(), "testConfig"); +} + +void MockModuleElementsCallback::OnMemoryLevel(int level) +{ + GTEST_LOG_(INFO) << "MockModuleElementsCallback::OnMemoryLevel called"; + EXPECT_EQ(level, NUMBER); +} + +void MockModuleLifecycleCallbacks::OnAbilityStart(const std::shared_ptr &ability) +{ + GTEST_LOG_(INFO) << "MockModuleLifecycleCallbacks::OnAbilityStart called"; +} + +void MockModuleLifecycleCallbacks::OnAbilityInactive(const std::shared_ptr &ability) +{ + GTEST_LOG_(INFO) << "MockModuleLifecycleCallbacks::OnAbilityInactive called"; +} + +void MockModuleLifecycleCallbacks::OnAbilityBackground(const std::shared_ptr &ability) +{ + GTEST_LOG_(INFO) << "MockModuleLifecycleCallbacks::OnAbilityBackground called"; +} + +void MockModuleLifecycleCallbacks::OnAbilityForeground(const std::shared_ptr &ability) +{ + GTEST_LOG_(INFO) << "MockModuleLifecycleCallbacks::OnAbilityForeground called"; +} + +void MockModuleLifecycleCallbacks::OnAbilityActive(const std::shared_ptr &ability) +{ + GTEST_LOG_(INFO) << "MockModuleLifecycleCallbacks::OnAbilityActive called"; +} + +void MockModuleLifecycleCallbacks::OnAbilityStop(const std::shared_ptr &ability) +{ + GTEST_LOG_(INFO) << "MockModuleLifecycleCallbacks::OnAbilityStop called"; +} + +void MockModuleLifecycleCallbacks::OnAbilitySaveState(const PacMap &outState) +{ + GTEST_LOG_(INFO) << "MockModuleLifecycleCallbacks::OnAbilitySaveState called"; +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/kits/appkit/test/Mock/include/mock_application.h b/kits/appkit/test/Mock/include/mock_application.h new file mode 100644 index 000000000..fe9adc3b9 --- /dev/null +++ b/kits/appkit/test/Mock/include/mock_application.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_KITS_APPKIT_TEST_MOCK_APPLICATION_H +#define FOUNDATION_APPEXECFWK_KITS_APPKIT_TEST_MOCK_APPLICATION_H + +#include +#include "ohos_application.h" + +namespace OHOS { +namespace AppExecFwk { + +class MockModuleLifecycleCallbacks : public AbilityLifecycleCallbacks { +public: + MockModuleLifecycleCallbacks() = default; + virtual ~MockModuleLifecycleCallbacks() = default; + + void OnAbilityStart(const std::shared_ptr &ability); + void OnAbilityInactive(const std::shared_ptr &ability); + void OnAbilityBackground(const std::shared_ptr &ability); + void OnAbilityForeground(const std::shared_ptr &ability); + void OnAbilityActive(const std::shared_ptr &ability); + void OnAbilityStop(const std::shared_ptr &ability); + void OnAbilitySaveState(const PacMap &outState); +}; + +class MockModuleElementsCallback : public ElementsCallback { +public: + MockModuleElementsCallback() = default; + virtual ~MockModuleElementsCallback() = default; + + virtual void OnConfigurationUpdated(const std::shared_ptr &ability, const Configuration &config); + + virtual void OnMemoryLevel(int level); +}; + +class MockApplication : public OHOSApplication { +public: + MockApplication(); + virtual ~MockApplication() = default; + + virtual void OnConfigurationUpdated(const Configuration &config); + virtual void OnMemoryLevel(int level); + virtual void OnForeground(); + virtual void OnBackground(); + virtual void OnStart(); + virtual void OnTerminate(); + +private: + std::shared_ptr elementCallBack_ = nullptr; + std::shared_ptr lifecycleCallBack_ = nullptr; + int level_ = 0; + std::shared_ptr config_ = nullptr; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_KITS_APPKIT_TEST_MOCK_APPLICATION_H \ No newline at end of file diff --git a/kits/appkit/test/Mock/include/mock_bundle_mgr_service.h b/kits/appkit/test/Mock/include/mock_bundle_mgr_service.h new file mode 100755 index 000000000..bfe1a2423 --- /dev/null +++ b/kits/appkit/test/Mock/include/mock_bundle_mgr_service.h @@ -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. + */ + +#ifndef FOUNDATION_APPEXECFWK_KITS_APPKIT_TEST_MOCK_BUNDLE_MGR_SERVICE_H +#define FOUNDATION_APPEXECFWK_KITS_APPKIT_TEST_MOCK_BUNDLE_MGR_SERVICE_H + +#include "gmock/gmock.h" +#include "semaphore_ex.h" +#include "bundle_mgr_host.h" + +namespace OHOS { +namespace AppExecFwk { +class MockBundleMgrService : public BundleMgrHost { +public: + MOCK_METHOD4(GetApplicationInfo, + bool(const std::string &appName, const ApplicationFlag flag, const int userId, ApplicationInfo &appInfo)); + virtual bool GetApplicationInfos( + const ApplicationFlag flag, const int userId, std::vector &appInfos) override + { + return false; + } + virtual bool GetBundleInfo(const std::string &bundleName, const BundleFlag flag, BundleInfo &bundleInfo) override + { + return false; + } + virtual bool GetBundleInfos(const BundleFlag flag, std::vector &bundleInfos) override + { + return false; + } + virtual int GetUidByBundleName(const std::string &bundleName, const int userId) override + { + return 0; + } + virtual bool GetBundleNameForUid(const int uid, std::string &bundleName) override + { + return false; + } + MOCK_METHOD2(GetBundleGids, bool(const std::string &bundleName, std::vector &gids)); + std::string GetAppType(const std::string &bundleName) + { + GTEST_LOG_(INFO) << "MockBundleMgrService::GetAppType called"; + return "ModuleTestType"; + } + virtual bool CheckIsSystemAppByUid(const int uid) override + { + return false; + } + MOCK_METHOD2(GetBundleInfosByMetaData, bool(const std::string &metaData, std::vector &bundleInfos)); + MOCK_METHOD2(QueryAbilityInfo, bool(const Want &want, AbilityInfo &abilityInfo)); + 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)); + MOCK_METHOD3( + GetBundleArchiveInfo, bool(const std::string &hapFilePath, const BundleFlag flag, BundleInfo &bundleInfo)); + MOCK_METHOD2(GetHapModuleInfo, bool(const std::string &hapFilePath, HapModuleInfo &hapModuleInfo)); + MOCK_METHOD2(GetHapModuleInfo, bool(const AbilityInfo &abilityInfo, HapModuleInfo &hapModuleInfo)); + MOCK_METHOD2(GetLaunchWantForBundle, bool(const std::string &bundleName, Want &want)); + MOCK_METHOD2(CheckPublicKeys, int(const std::string &firstBundleName, const std::string &secondBundleName)); + MOCK_METHOD2(CheckPermission, int(const std::string &bundleName, const std::string &permission)); + MOCK_METHOD2(GetPermissionDef, bool(const std::string &permissionName, PermissionDef &permissionDef)); + MOCK_METHOD1(GetAllPermissionGroupDefs, bool(std::vector &permissionDefs)); + MOCK_METHOD2(GetAppsGrantedPermissions, + bool(const std::vector &permissions, std::vector &appNames)); + MOCK_METHOD1(HasSystemCapability, bool(const std::string &capName)); + MOCK_METHOD1(GetSystemAvailableCapabilities, bool(std::vector &systemCaps)); + MOCK_METHOD0(IsSafeMode, bool()); + MOCK_METHOD2(CleanBundleCacheFiles, + bool(const std::string &bundleName, const sptr &cleanCacheCallback)); + MOCK_METHOD1(CleanBundleDataFiles, bool(const std::string &bundleName)); + MOCK_METHOD1(RegisterBundleStatusCallback, bool(const sptr &bundleStatusCallback)); + MOCK_METHOD1(ClearBundleStatusCallback, bool(const sptr &bundleStatusCallback)); + MOCK_METHOD0(UnregisterBundleStatusCallback, bool()); + virtual bool DumpInfos(const DumpFlag flag, const std::string &bundleName, std::string &result) override + { + return false; + } + MOCK_METHOD0(GetBundleInstaller, sptr()); + MOCK_METHOD1(GetBundleInstaller, bool(const std::string &)); + MOCK_METHOD2(SetApplicationEnabled, bool(const std::string &, bool)); + MOCK_METHOD1(IsApplicationEnabled, bool(const std::string &)); + + virtual bool CanRequestPermission( + const std::string &bundleName, const std::string &permissionName, const int userId) override + { + return true; + } + virtual bool RequestPermissionFromUser( + const std::string &bundleName, const std::string &permission, const int userId) override + { + return true; + } + void Wait() + { + sem_.Wait(); + } + + int Post() + { + sem_.Post(); + return 0; + } + + void PostVoid() + { + sem_.Post(); + } + +private: + Semaphore sem_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_KITS_APPKIT_TEST_MOCK_BUNDLE_MGR_SERVICE_H \ No newline at end of file diff --git a/kits/appkit/test/Mock/include/mock_ipc_object_stub.cpp b/kits/appkit/test/Mock/include/mock_ipc_object_stub.cpp new file mode 100644 index 000000000..417838e5c --- /dev/null +++ b/kits/appkit/test/Mock/include/mock_ipc_object_stub.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 "ipc_object_stub.h" +#include +#include "ipc_types.h" +#include "ipc_debug.h" +#include "ipc_process_skeleton.h" +#include "ipc_thread_skeleton.h" +#include "log_tags.h" +#include "ipc_skeleton.h" +#include "app_log_wrapper.h" + +#ifdef CONFIG_IPC_RPC +#include "dbinder_databus_invoker.h" +#include "dbinder_error_code.h" +#include "ISessionService.h" +#endif + +namespace OHOS { +using namespace OHOS::AppExecFwk; +using namespace OHOS::HiviewDFX; +#ifdef CONFIG_IPC_RPC +static constexpr HiLogLabel LABEL = {LOG_CORE, LOG_ID_IPC, "IPCObjectStub"}; +// Authentication information can be added only for processes with system permission. +static constexpr pid_t ALLOWED_UID = 10000; +// Only the samgr can obtain the UID and PID. +static constexpr pid_t SYSTEM_SERVER_UID = 1000; +#endif +IPCObjectStub::IPCObjectStub(std::u16string descriptor) : IRemoteObject(descriptor) +{} + +IPCObjectStub::~IPCObjectStub() +{ + APP_LOGI("IPCObjectStub destroyed"); +} + +bool IPCObjectStub::IsDeviceIdIllegal(const std::string &deviceID) +{ + if (deviceID.empty() || deviceID.length() > DEVICEID_LENGTH) { + return true; + } + return false; +} + +int32_t IPCObjectStub::GetObjectRefCount() +{ + int kRefCount = 0; + int refCount = GetSptrRefCount(); + IRemoteInvoker *invoker = IPCThreadSkeleton::GetRemoteInvoker(IRemoteObject::IF_PROT_DEFAULT); + + if (invoker != nullptr) { + kRefCount = invoker->GetObjectRefCount(this); + } + + /* the kernel has already acquire the reference + * on this object, so we need to decrement by 1. + */ + if (kRefCount > 0) { + refCount += kRefCount - 1; + } + + return refCount; +} + +int IPCObjectStub::Dump(int fd, const std::vector &args) +{ + const size_t numArgs = args.size(); + APP_LOGI("Invalid call on Stub:fd:%{public}d, args:%{public}zu", fd, numArgs); + return ERR_NONE; +} + +int IPCObjectStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + int result = ERR_NONE; + switch (code) { +#ifdef CONFIG_IPC_RPC + case DBINDER_OBITUARY_TRANSACTION: { + if (IPCSkeleton::GetCallingUid() != SYSTEM_SERVER_UID) { + APP_LOGI(LABEL, "%s: DBINDER_OBITUARY_TRANSACTION unauthenticated user ", __func__); + result = IPC_STUB_INVALID_DATA_ERR; + break; + } + if (data.ReadInt32() == IRemoteObject::DeathRecipient::NOTICE_DEATH_RECIPIENT) { + result = NoticeServiceDie(data, reply, option); + } else { + result = IPC_STUB_INVALID_DATA_ERR; + } + break; + } +#endif + default: + result = IPC_STUB_UNKNOW_TRANS_ERR; + APP_LOGI("unknown OnRemoteRequest code = %{public}u", code); + break; + } + + return result; +} + +int IPCObjectStub::OnRemoteDump(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + int result = ERR_NONE; + int fd = data.ReadFileDescriptor(); + std::vector args; + if (fd != INVALID_FD) { + if (data.ReadString16Vector(&args)) { + result = Dump(fd, args); + } + ::close(fd); + } else { + result = IPC_STUB_INVALID_DATA_ERR; + } + return result; +} + +int IPCObjectStub::SendRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + int result = ERR_NONE; + switch (code) { + case PING_TRANSACTION: { + if (!reply.WriteInt32(ERR_NONE)) { + result = IPC_STUB_WRITE_PARCEL_ERR; + } + break; + } + case INTERFACE_TRANSACTION: { + std::u16string descriptor = GetObjectDescriptor(); + if (!reply.WriteString16(descriptor)) { + APP_LOGI("write to parcel fail"); + result = IPC_STUB_WRITE_PARCEL_ERR; + } + break; + } + case SYNCHRONIZE_REFERENCE: { + int refCount = GetObjectRefCount(); + // when handle transaction the invoker would try to acquire + // the object's reference to defense the object being released + // so the actual we should decrement the temporary reference. + --refCount; + reply.WriteInt32(refCount); + break; + } + case DUMP_TRANSACTION: { + if (!IPCSkeleton::IsLocalCalling()) { + APP_LOGI("do not allow dump"); + break; + } + result = OnRemoteDump(code, data, reply, option); + break; + } +#ifdef CONFIG_IPC_RPC + case INVOKE_LISTEN_THREAD: { + if (!IPCSkeleton::IsLocalCalling() || IPCSkeleton::GetCallingUid() >= ALLOWED_UID) { + APP_LOGI("%s: INVOKE_LISTEN_THREAD unauthenticated user ", __func__); + result = IPC_STUB_INVALID_DATA_ERR; + break; + } + result = InvokerThread(code, data, reply, option); + break; + } + case GET_PROTO_INFO: { + result = ProcessProto(code, data, reply, option); + break; + } + case DBINDER_INCREFS_TRANSACTION: { + if (IPCSkeleton::IsLocalCalling()) { + APP_LOGI("%s: cannot be called in same device", __func__); + result = IPC_STUB_INVALID_DATA_ERR; + break; + } + result = IncStubRefs(data, reply); + break; + } + case DBINDER_DECREFS_TRANSACTION: { + if (IPCSkeleton::IsLocalCalling()) { + APP_LOGI("%s: cannot be called in same device", __func__); + result = IPC_STUB_INVALID_DATA_ERR; + break; + } + result = DecStubRefs(data, reply); + break; + } + case DBINDER_ADD_COMMAUTH: { + if (IPCSkeleton::IsLocalCalling() || IPCSkeleton::GetCallingUid() >= ALLOWED_UID) { + APP_LOGI("%s: DBINDER_ADD_COMMAUTH unauthenticated user ", __func__); + result = IPC_STUB_INVALID_DATA_ERR; + break; + } + result = AddAuthInfo(data, reply); + break; + } + case GET_UIDPID_INFO: { + if (!IPCSkeleton::IsLocalCalling()) { + APP_LOGI("GET_UIDPID_INFO message is not from sa manager"); + result = IPC_STUB_INVALID_DATA_ERR; + break; + } + std::string sessionName = GetDataBusName(); + if (sessionName.empty()) { + APP_LOGI("sessionName is empty"); + result = IPC_STUB_CREATE_BUS_SERVER_ERR; + break; + } + if (!reply.WriteString(sessionName)) { + APP_LOGI("write to parcel fail"); + result = IPC_STUB_INVALID_DATA_ERR; + break; + } + break; + } + case GRANT_DATABUS_NAME: { + if (!IPCSkeleton::IsLocalCalling() || getuid() != SYSTEM_SERVER_UID) { + APP_LOGI("GRANT_DATABUS_NAME message is excluded in sa manager"); + result = IPC_STUB_INVALID_DATA_ERR; + break; + } + result = GrantDataBusName(code, data, reply, option); + break; + } +#endif + default: + result = OnRemoteRequest(code, data, reply, option); + break; + } + + return result; +} + +void IPCObjectStub::OnFirstStrongRef(const void *objectId) +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + + if (current != nullptr) { + current->AttachObject(this); + } +} + +void IPCObjectStub::OnLastStrongRef(const void *objectId) +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + + if (current != nullptr) { + current->DetachObject(this); +#ifdef CONFIG_IPC_RPC + current->DetachStubRecvRefInfo(this); + current->DetachStubSendRefInfo(this); + (void)current->DetachStubRefTimes(this); + current->DetachCommAuthInfoByStub(this); + uint64_t stubIndex = current->EraseStubIndex(reinterpret_cast(this)); + current->DetachAppInfoToStubIndex(stubIndex); +#endif + } +} + +bool IPCObjectStub::AddDeathRecipient(const sptr &recipient) +{ + return true; +} + +bool IPCObjectStub::RemoveDeathRecipient(const sptr &recipient) +{ + return false; +} + +pid_t IPCObjectStub::GetCallingPid() +{ + return IPCSkeleton::GetCallingPid(); +} + +pid_t IPCObjectStub::GetCallingUid() +{ + return IPCSkeleton::GetCallingUid(); +} + +int32_t IPCObjectStub::ProcessProto(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + int result = ERR_NONE; + APP_LOGI("IPCObjectStub::ProcessProto called, type = 0, normal stub object"); + if (!reply.WriteUint32(IRemoteObject::IF_PROT_BINDER)) { + APP_LOGI("write to parcel fail"); + result = IPC_STUB_WRITE_PARCEL_ERR; + } + return result; +} + +#ifdef CONFIG_IPC_RPC +int32_t IPCObjectStub::InvokerThread(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + switch (data.ReadUint32()) { + case IRemoteObject::DATABUS_TYPE: { + if (InvokerDataBusThread(data, reply) != ERR_NONE) { + APP_LOGI("Invoker databus thread fail"); + return IPC_STUB_INVOKE_THREAD_ERR; + } + break; + } + default: { + APP_LOGI("InvokerThread Invalid Type"); + return IPC_STUB_INVALID_DATA_ERR; + } + } + + return ERR_NONE; +} + +int32_t IPCObjectStub::InvokerDataBusThread(MessageParcel &data, MessageParcel &reply) +{ + std::string deviceId = data.ReadString(); + uint32_t remotePid = data.ReadUint32(); + uint32_t remoteUid = data.ReadUint32(); + std::string remoteDeviceId = data.ReadString(); + std::string sessionName = data.ReadString(); + if (IsDeviceIdIllegal(deviceId) || IsDeviceIdIllegal(remoteDeviceId) || sessionName.empty()) { + APP_LOGI("%s: device ID is invalid or session name nil", __func__); + return IPC_STUB_INVALID_DATA_ERR; + } + + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + APP_LOGI("IPCProcessSkeleton is nullptr"); + return IPC_STUB_CURRENT_NULL_ERR; + } + if (!current->CreateSoftbusServer(sessionName)) { + APP_LOGI("%s: fail to create databus server", __func__); + return IPC_STUB_CREATE_BUS_SERVER_ERR; + } + + uint64_t stubIndex = current->AddStubByIndex(this); + if (stubIndex == 0) { + APP_LOGI("%s: add stub fail", __func__); + return IPC_STUB_INVALID_DATA_ERR; + } + if (!reply.WriteUint64(stubIndex) || !reply.WriteString(sessionName) || !reply.WriteString(deviceId)) { + APP_LOGI("%s: write to parcel fail", __func__); + return IPC_STUB_INVALID_DATA_ERR; + } + if (!current->AttachAppInfoToStubIndex(remotePid, remoteUid, remoteDeviceId, stubIndex)) { + APP_LOGI("fail to attach appinfo to stubIndex, maybe attach already"); + } + if (!current->AttachCommAuthInfo(this, remotePid, remoteUid, remoteDeviceId)) { + APP_LOGI("fail to attach comm auth info"); + } + + return ERR_NONE; +} + +int32_t IPCObjectStub::NoticeServiceDie(MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + APP_LOGI("%s: current is null", __func__); + return IPC_STUB_CURRENT_NULL_ERR; + } + + IPCObjectProxy *ipcProxy = current->QueryCallbackProxy(this); + if (ipcProxy == nullptr) { + APP_LOGI("%s: ipc proxy is null", __func__); + return IPC_STUB_INVALID_DATA_ERR; + } + + ipcProxy->SendObituary(); + + if (!current->DetachCallbackStub(this)) { + APP_LOGI("%s: fail to detach callback stub", __func__); + // do nothing, RemoveDeathRecipient can delete this too + } + + return ERR_NONE; +} + +int32_t IPCObjectStub::IncStubRefs(MessageParcel &data, MessageParcel &reply) +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + APP_LOGI("%s: current is null", __func__); + return IPC_STUB_CURRENT_NULL_ERR; + } + + std::string deviceId = IPCSkeleton::GetCallingDeviceID(); + if (deviceId.empty()) { + APP_LOGI("%s: calling error", __func__); + return IPC_STUB_INVALID_DATA_ERR; + } + if (!current->AttachStubRecvRefInfo(this, IPCSkeleton::GetCallingPid(), deviceId)) { + APP_LOGI("%s: attach stub ref info err, already in", __func__); + return ERR_NONE; + } + + if (!current->DecStubRefTimes(this)) { + this->IncStrongRef(this); + } + + return ERR_NONE; +} + +int32_t IPCObjectStub::DecStubRefs(MessageParcel &data, MessageParcel &reply) +{ + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + APP_LOGI("%s: current is null", __func__); + return IPC_STUB_CURRENT_NULL_ERR; + } + + std::string deviceId = IPCSkeleton::GetCallingDeviceID(); + current->DetachStubRefInfo(this, IPCSkeleton::GetCallingPid(), deviceId); + return ERR_NONE; +} + +int32_t IPCObjectStub::AddAuthInfo(MessageParcel &data, MessageParcel &reply) +{ + uint32_t remotePid = data.ReadUint32(); + uint32_t remoteUid = data.ReadUint32(); + std::string remoteDeviceId = data.ReadString(); + if (IsDeviceIdIllegal(remoteDeviceId)) { + APP_LOGI("%s: remote deviceId is null", __func__); + return IPC_STUB_INVALID_DATA_ERR; + } + + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + if (current == nullptr) { + APP_LOGI("%s: current is null", __func__); + return IPC_STUB_CURRENT_NULL_ERR; + } + + if (!current->AttachCommAuthInfo(this, remotePid, remoteUid, remoteDeviceId)) { + APP_LOGI("fail to attach comm auth info fail"); + return IPC_STUB_INVALID_DATA_ERR; + } + return ERR_NONE; +} + +std::string IPCObjectStub::GetDataBusName() +{ + sptr object = IPCProcessSkeleton::GetCurrent()->GetSAMgrObject(); + if (object == nullptr) { + APP_LOGI("get object is null"); + return std::string(""); + } + + IPCObjectProxy *samgr = reinterpret_cast(object.GetRefPtr()); + return samgr->GetDataBusName(); +} + +int32_t IPCObjectStub::GrantDataBusName(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + int pid = IPCSkeleton::GetCallingPid(); + int uid = IPCSkeleton::GetCallingUid(); + std::string sessionName = CreateDatabusName(uid, pid); + if (sessionName.empty()) { + APP_LOGI("pid/uid is invalid, pid = {public}%d, uid = {public}%d", pid, uid); + return IPC_STUB_INVALID_DATA_ERR; + } + if (!reply.WriteUint32(IRemoteObject::IF_PROT_DATABUS) || !reply.WriteString(sessionName)) { + APP_LOGI("write to parcel fail"); + return IPC_STUB_INVALID_DATA_ERR; + } + + return ERR_NONE; +} + +std::string IPCObjectStub::CreateDatabusName(int uid, int pid) +{ + std::shared_ptr softbusManager = ISessionService::GetInstance(); + if (softbusManager == nullptr) { + APP_LOGI("fail to get softbus service"); + return ""; + } + + std::string sessionName = "DBinder" + std::to_string(uid) + std::string("_") + std::to_string(pid); + if (softbusManager->GrantPermission(uid, pid, sessionName) != ERR_NONE) { + APP_LOGI("fail to Grant Permission softbus name"); + return ""; + } + + return sessionName; +} +#endif +} // namespace OHOS diff --git a/kits/appkit/test/Mock/include/sys_mgr_client_mock.cpp b/kits/appkit/test/Mock/include/sys_mgr_client_mock.cpp new file mode 100644 index 000000000..7df593084 --- /dev/null +++ b/kits/appkit/test/Mock/include/sys_mgr_client_mock.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 +#include "sys_mgr_client.h" +#include "hilog_wrapper.h" +#include "if_system_ability_manager.h" +#include "iservice_registry.h" +#include "ipc_skeleton.h" +#include "string_ex.h" + +namespace OHOS { +namespace AppExecFwk { + +sptr SysMrgClient::GetSystemAbility(const int32_t systemAbilityId) +{ + if (servicesMap_[systemAbilityId] == nullptr) { + OHOS::sptr abilityManager = + SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (abilityManager == nullptr) { + HILOG_ERROR("%s:fail to get Registry", __func__); + return nullptr; + } + OHOS::sptr object = abilityManager->GetSystemAbility(systemAbilityId); + servicesMap_[systemAbilityId] = object; + } + + return servicesMap_[systemAbilityId]; +} + +void SysMrgClient::RegisterSystemAbility(const int32_t systemAbilityId, sptr broker) +{ + servicesMap_[systemAbilityId] = broker; +} + +void SysMrgClient::UnregisterSystemAbility(const int32_t systemAbilityId) +{ + servicesMap_[systemAbilityId] = nullptr; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/kits/appkit/test/moduletest/appexecfwk_appkit_native_app_module_test_first.cpp b/kits/appkit/test/moduletest/appexecfwk_appkit_native_app_module_test_first.cpp new file mode 100644 index 000000000..d1ee4a6c9 --- /dev/null +++ b/kits/appkit/test/moduletest/appexecfwk_appkit_native_app_module_test_first.cpp @@ -0,0 +1,536 @@ +/* + * 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 "main_thread.h" +#include "sys_mgr_client.h" +#include "system_ability_definition.h" +#include "mock_app_mgr_service.h" +#include "mock_app_thread.h" +#include "mock_ability_token.h" +#include "mock_ability_mgr_service.h" +#include "mock_bundle_mgr_service.h" + +namespace OHOS { +namespace AppExecFwk { +using namespace testing::ext; +using namespace OHOS::AppExecFwk; +using namespace OHOS; +using namespace OHOS::AAFwk; + +class AppkitNativeModuleTestFirst : public testing::Test { +public: + AppkitNativeModuleTestFirst() : AppMgrObject_(nullptr), mockAppMgr(nullptr), mockHandler_(nullptr), runner_(nullptr) + {} + ~AppkitNativeModuleTestFirst() + {} + OHOS::sptr AppMgrObject_ = nullptr; + MockAppMgrService *mockAppMgr = nullptr; + std::shared_ptr mockHandler_ = nullptr; + std::shared_ptr runner_ = nullptr; + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void AppkitNativeModuleTestFirst::SetUpTestCase(void) +{} + +void AppkitNativeModuleTestFirst::TearDownTestCase(void) +{} + +void AppkitNativeModuleTestFirst::SetUp(void) +{ + GTEST_LOG_(INFO) << "AppkitNativeModuleTestFirst SetUp"; + AppMgrObject_ = new (std::nothrow) MockAppMgrService(); + mockAppMgr = iface_cast(AppMgrObject_); + + runner_ = EventRunner::Create("AppkitNativeModuleTestMockHandlerFirst"); + mockHandler_ = std::make_shared(runner_); + + auto task = [abilityThread = this]() { MainThread::Start(); }; + mockHandler_->PostTask(task); +} + +void AppkitNativeModuleTestFirst::TearDown(void) +{ + GTEST_LOG_(INFO) << "AppkitNativeModuleTestFirst TearDown"; + AppLaunchData lanchdate; + ApplicationInfo appinf; + ProcessInfo processinf("TestProcess", 9999); + appinf.name = "MockTestApplication"; + appinf.moduleSourceDirs.push_back("/hos/lib/libabilitydemo_native.z.so"); + lanchdate.SetApplicationInfo(appinf); + lanchdate.SetProcessInfo(processinf); + mockAppMgr->ScheduleLaunchApplication(lanchdate); + + usleep(200); + + mockAppMgr->ScheduleTerminateApplication(); +} + +/** + * @tc.number: App_Start_0100 + * @tc.name: Start Appfwk + * @tc.desc: Mock appmgr and register it into the systemmanager. + * Start the Appfwk and the Appfwk attach the AppMgr. + */ +HWTEST_F(AppkitNativeModuleTestFirst, App_Start_0100, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "App_Start_0100 start"; + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility(APP_MGR_SERVICE_ID, AppMgrObject_); + runner_->Run(); + usleep(200); + mockAppMgr->ScheduleTerminateApplication(); + usleep(200); + runner_->Stop(); + OHOS::DelayedSingleton::GetInstance()->UnregisterSystemAbility(APP_MGR_SERVICE_ID); + usleep(200); + GTEST_LOG_(INFO) << "App_Start_0100 end"; +} + +/** + * @tc.number: App_Start_0200 + * @tc.name: Start Appfwk + * @tc.desc: Didn't register Mock appmgr into the systemmanager. + * Start the Appfwk and the Appfwk attach the AppMgr failed. + */ +HWTEST_F(AppkitNativeModuleTestFirst, App_Start_0200, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "App_Start_0200 start"; + runner_->Run(); + usleep(200); + EXPECT_EQ(false, mockAppMgr->IsAttached()); + runner_->Stop(); + GTEST_LOG_(INFO) << "App_Start_0200 end"; +} + +/** + * @tc.number: App_ApplicationLifeCycle_0100 + * @tc.name: Application lifecycle switch + * @tc.desc: Mock appmgr and register it into the systemmanager. + * The Appfwk has started successfully. + * Verifying when the correct App lifecycle flows, whether the corresponding + * callback function will be called. + * (StartAppfwk->LaunchApp->Foreground->Background->Terminate) + */ +HWTEST_F(AppkitNativeModuleTestFirst, App_ApplicationLifeCycle_0100, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_0100 start"; + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility(APP_MGR_SERVICE_ID, AppMgrObject_); + runner_->Run(); + usleep(200); + + AppLaunchData lanchdate; + ApplicationInfo appinf; + ProcessInfo processinf("TestProcess", 9999); + appinf.name = "MockTestApplication"; + appinf.moduleSourceDirs.push_back("/hos/lib/libabilitydemo_native.z.so"); + lanchdate.SetApplicationInfo(appinf); + lanchdate.SetProcessInfo(processinf); + mockAppMgr->ScheduleLaunchApplication(lanchdate); + + usleep(200); + + mockAppMgr->ScheduleForegroundApplication(); + + usleep(200); + + mockAppMgr->ScheduleBackgroundApplication(); + + usleep(200); + + mockAppMgr->ScheduleTerminateApplication(); + + usleep(200); + + runner_->Stop(); + OHOS::DelayedSingleton::GetInstance()->UnregisterSystemAbility(APP_MGR_SERVICE_ID); + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_0100 end"; +} + +/** + * @tc.number: App_ApplicationLifeCycle_0200 + * @tc.name: Application lifecycle switch + * @tc.desc: Mock appmgr and register it into the systemmanager. The Appfwk has started successfully. + * Verifying when the wrong App lifecycle flows, whether the corresponding callback function will not + * be called. (StartAppfwk->Foreground) + */ +HWTEST_F(AppkitNativeModuleTestFirst, App_ApplicationLifeCycle_0200, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_0200 start"; + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility(APP_MGR_SERVICE_ID, AppMgrObject_); + runner_->Run(); + usleep(200); + + mockAppMgr->ScheduleForegroundApplication(); + + usleep(200); + + runner_->Stop(); + OHOS::DelayedSingleton::GetInstance()->UnregisterSystemAbility(APP_MGR_SERVICE_ID); + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_0200 end"; +} + +/** + * @tc.number: App_ApplicationLifeCycle_0300 + * @tc.name: Application lifecycle switch + * @tc.desc: Mock appmgr and register it into the systemmanager. The Appfwk has started successfully. + * Verifying when the wrong App lifecycle flows, whether the corresponding callback function will not + * be called. (StartAppfwk->Background) + */ +HWTEST_F(AppkitNativeModuleTestFirst, App_ApplicationLifeCycle_0300, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_0300 start"; + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility(APP_MGR_SERVICE_ID, AppMgrObject_); + runner_->Run(); + usleep(200); + + mockAppMgr->ScheduleBackgroundApplication(); + + usleep(200); + + runner_->Stop(); + OHOS::DelayedSingleton::GetInstance()->UnregisterSystemAbility(APP_MGR_SERVICE_ID); + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_0300 end"; +} + +/** + * @tc.number: App_ApplicationLifeCycle_0400 + * @tc.name: Application lifecycle switch + * @tc.desc: Mock appmgr and register it into the systemmanager. The Appfwk has started successfully. + * Verifying when the wrong App lifecycle flows, whether the corresponding callback function will not + * be called. (StartAppfwk->Terminate) + */ +HWTEST_F(AppkitNativeModuleTestFirst, App_ApplicationLifeCycle_0400, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_0400 start"; + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility(APP_MGR_SERVICE_ID, AppMgrObject_); + runner_->Run(); + usleep(200); + + mockAppMgr->ScheduleTerminateApplication(); + + usleep(200); + + runner_->Stop(); + OHOS::DelayedSingleton::GetInstance()->UnregisterSystemAbility(APP_MGR_SERVICE_ID); + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_0400 end"; +} + +/** + * @tc.number: App_ApplicationLifeCycle_0500 + * @tc.name: Application lifecycle switch + * @tc.desc: Mock appmgr and register it into the systemmanager. The Appfwk has started successfully. + * Verifying when the wrong App lifecycle flows, whether the corresponding callback function will not + * be called. (StartAppfwk->LaunchApp->Foreground) + */ +HWTEST_F(AppkitNativeModuleTestFirst, App_ApplicationLifeCycle_0500, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_0500 start"; + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility(APP_MGR_SERVICE_ID, AppMgrObject_); + runner_->Run(); + usleep(200); + + AppLaunchData lanchdate; + ApplicationInfo appinf; + ProcessInfo processinf("TestProcess", 9999); + appinf.name = "MockTestApplication"; + appinf.moduleSourceDirs.push_back("/hos/lib/libabilitydemo_native.z.so"); + lanchdate.SetApplicationInfo(appinf); + lanchdate.SetProcessInfo(processinf); + mockAppMgr->ScheduleLaunchApplication(lanchdate); + + usleep(200); + + mockAppMgr->ScheduleBackgroundApplication(); + + usleep(200); + + runner_->Stop(); + OHOS::DelayedSingleton::GetInstance()->UnregisterSystemAbility(APP_MGR_SERVICE_ID); + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_0500 end"; +} + +/** + * @tc.number: App_ApplicationLifeCycle_0600 + * @tc.name: Application lifecycle switch + * @tc.desc: Mock appmgr and register it into the systemmanager. The Appfwk has started successfully. + * Verifying when the wrong App lifecycle flows, whether the corresponding callback function will not + * be called. (StartAppfwk->LaunchApp->Terminate) + */ +HWTEST_F(AppkitNativeModuleTestFirst, App_ApplicationLifeCycle_0600, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_0600 start"; + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility(APP_MGR_SERVICE_ID, AppMgrObject_); + runner_->Run(); + usleep(200); + + AppLaunchData lanchdate; + ApplicationInfo appinf; + ProcessInfo processinf("TestProcess", 9999); + appinf.name = "MockTestApplication"; + appinf.moduleSourceDirs.push_back("/hos/lib/libabilitydemo_native.z.so"); + lanchdate.SetApplicationInfo(appinf); + lanchdate.SetProcessInfo(processinf); + mockAppMgr->ScheduleLaunchApplication(lanchdate); + + usleep(200); + + mockAppMgr->ScheduleTerminateApplication(); + + usleep(200); + + runner_->Stop(); + OHOS::DelayedSingleton::GetInstance()->UnregisterSystemAbility(APP_MGR_SERVICE_ID); + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_0600 end"; +} + +/** + * @tc.number: App_ApplicationLifeCycle_0700 + * @tc.name: Application lifecycle switch + * @tc.desc: Mock appmgr and register it into the systemmanager. The Appfwk has started successfully. + * Verifying when the wrong App lifecycle flows, whether the corresponding callback function will not + * be called. (StartAppfwk->LaunchApp->LaunchApp) + */ +HWTEST_F(AppkitNativeModuleTestFirst, App_ApplicationLifeCycle_0700, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_0700 start"; + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility(APP_MGR_SERVICE_ID, AppMgrObject_); + runner_->Run(); + usleep(200); + + AppLaunchData lanchdate; + ApplicationInfo appinf; + ProcessInfo processinf("TestProcess", 9999); + appinf.name = "MockTestApplication"; + appinf.moduleSourceDirs.push_back("/hos/lib/libabilitydemo_native.z.so"); + lanchdate.SetApplicationInfo(appinf); + lanchdate.SetProcessInfo(processinf); + mockAppMgr->ScheduleLaunchApplication(lanchdate); + + usleep(200); + + mockAppMgr->ScheduleLaunchApplication(lanchdate); + + usleep(200); + + runner_->Stop(); + OHOS::DelayedSingleton::GetInstance()->UnregisterSystemAbility(APP_MGR_SERVICE_ID); + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_0700 end"; +} + +/** + * @tc.number: App_ApplicationLifeCycle_0800 + * @tc.name: Application lifecycle switch + * @tc.desc: Mock appmgr and register it into the systemmanager. The Appfwk has started successfully. + * Verifying when the wrong App lifecycle flows, whether the corresponding callback function will not + * be called. (StartAppfwk->LaunchApp->Foreground->Terminate) + */ +HWTEST_F(AppkitNativeModuleTestFirst, App_ApplicationLifeCycle_0800, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_0800 start"; + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility(APP_MGR_SERVICE_ID, AppMgrObject_); + runner_->Run(); + usleep(200); + + AppLaunchData lanchdate; + ApplicationInfo appinf; + ProcessInfo processinf("TestProcess", 9999); + appinf.name = "MockTestApplication"; + appinf.moduleSourceDirs.push_back("/hos/lib/libabilitydemo_native.z.so"); + lanchdate.SetApplicationInfo(appinf); + lanchdate.SetProcessInfo(processinf); + mockAppMgr->ScheduleLaunchApplication(lanchdate); + + usleep(200); + + mockAppMgr->ScheduleForegroundApplication(); + + usleep(200); + + mockAppMgr->ScheduleTerminateApplication(); + + usleep(200); + + runner_->Stop(); + OHOS::DelayedSingleton::GetInstance()->UnregisterSystemAbility(APP_MGR_SERVICE_ID); + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_0800 end"; +} + +/** + * @tc.number: App_ApplicationLifeCycle_0900 + * @tc.name: Application lifecycle switch + * @tc.desc: Mock appmgr and register it into the systemmanager. The Appfwk has started successfully. + * Verifying when the wrong App lifecycle flows, whether the corresponding callback function will not + * be called. (StartAppfwk->LaunchApp->Foreground->LaunchApp) + */ +HWTEST_F(AppkitNativeModuleTestFirst, App_ApplicationLifeCycle_0900, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_0900 start"; + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility(APP_MGR_SERVICE_ID, AppMgrObject_); + runner_->Run(); + usleep(200); + + AppLaunchData lanchdate; + ApplicationInfo appinf; + ProcessInfo processinf("TestProcess", 9999); + appinf.name = "MockTestApplication"; + appinf.moduleSourceDirs.push_back("/hos/lib/libabilitydemo_native.z.so"); + lanchdate.SetApplicationInfo(appinf); + lanchdate.SetProcessInfo(processinf); + mockAppMgr->ScheduleLaunchApplication(lanchdate); + + usleep(200); + + mockAppMgr->ScheduleForegroundApplication(); + + usleep(200); + + mockAppMgr->ScheduleLaunchApplication(lanchdate); + + usleep(200); + + runner_->Stop(); + OHOS::DelayedSingleton::GetInstance()->UnregisterSystemAbility(APP_MGR_SERVICE_ID); + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_0900 end"; +} + +/** + * @tc.number: App_ApplicationLifeCycle_1000 + * @tc.name: Application lifecycle switch + * @tc.desc: Mock appmgr and register it into the systemmanager. The Appfwk has started successfully. + * Verifying when the wrong App lifecycle flows, whether the corresponding callback function will not + * be called. (StartAppfwk->LaunchApp->Foreground->LaunchApp) + */ +HWTEST_F(AppkitNativeModuleTestFirst, App_ApplicationLifeCycle_1000, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_1000 start"; + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility(APP_MGR_SERVICE_ID, AppMgrObject_); + runner_->Run(); + usleep(200); + + AppLaunchData lanchdate; + ApplicationInfo appinf; + ProcessInfo processinf("TestProcess", 9999); + appinf.name = "MockTestApplication"; + appinf.moduleSourceDirs.push_back("/hos/lib/libabilitydemo_native.z.so"); + lanchdate.SetApplicationInfo(appinf); + lanchdate.SetProcessInfo(processinf); + mockAppMgr->ScheduleLaunchApplication(lanchdate); + + usleep(200); + + mockAppMgr->ScheduleForegroundApplication(); + + usleep(200); + + mockAppMgr->ScheduleForegroundApplication(); + + usleep(200); + + runner_->Stop(); + OHOS::DelayedSingleton::GetInstance()->UnregisterSystemAbility(APP_MGR_SERVICE_ID); + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_1000 end"; +} + +/** + * @tc.number: App_ApplicationLifeCycle_1100 + * @tc.name: Application lifecycle switch + * @tc.desc: Mock appmgr and register it into the systemmanager. The Appfwk has started successfully. + * Verifying when the wrong App lifecycle flows, whether the corresponding callback function will not + * be called. (StartAppfwk->LaunchApp->Foreground->Background->LaunchApp) + */ +HWTEST_F(AppkitNativeModuleTestFirst, App_ApplicationLifeCycle_1100, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_1100 start"; + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility(APP_MGR_SERVICE_ID, AppMgrObject_); + runner_->Run(); + usleep(200); + + AppLaunchData lanchdate; + ApplicationInfo appinf; + ProcessInfo processinf("TestProcess", 9999); + appinf.name = "MockTestApplication"; + appinf.moduleSourceDirs.push_back("/hos/lib/libabilitydemo_native.z.so"); + lanchdate.SetApplicationInfo(appinf); + lanchdate.SetProcessInfo(processinf); + mockAppMgr->ScheduleLaunchApplication(lanchdate); + + usleep(200); + + mockAppMgr->ScheduleForegroundApplication(); + + usleep(200); + + mockAppMgr->ScheduleBackgroundApplication(); + + usleep(200); + + mockAppMgr->ScheduleLaunchApplication(lanchdate); + + usleep(200); + + runner_->Stop(); + OHOS::DelayedSingleton::GetInstance()->UnregisterSystemAbility(APP_MGR_SERVICE_ID); + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_1100 end"; +} + +/** + * @tc.number: App_ApplicationLifeCycle_1200 + * @tc.name: Application lifecycle switch + * @tc.desc: Mock appmgr and register it into the systemmanager. The Appfwk has started successfully. + * Verifying when the wrong App lifecycle flows, whether the corresponding callback function will not + * be called. (StartAppfwk->LaunchApp->Foreground->Background->Foreground) + */ +HWTEST_F(AppkitNativeModuleTestFirst, App_ApplicationLifeCycle_1200, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_1200 start"; + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility(APP_MGR_SERVICE_ID, AppMgrObject_); + runner_->Run(); + usleep(200); + + AppLaunchData lanchdate; + ApplicationInfo appinf; + ProcessInfo processinf("TestProcess", 9999); + appinf.name = "MockTestApplication"; + appinf.moduleSourceDirs.push_back("/hos/lib/libabilitydemo_native.z.so"); + lanchdate.SetApplicationInfo(appinf); + lanchdate.SetProcessInfo(processinf); + mockAppMgr->ScheduleLaunchApplication(lanchdate); + + usleep(200); + + mockAppMgr->ScheduleForegroundApplication(); + + usleep(200); + + mockAppMgr->ScheduleBackgroundApplication(); + + usleep(200); + + mockAppMgr->ScheduleForegroundApplication(); + + usleep(200); + + runner_->Stop(); + OHOS::DelayedSingleton::GetInstance()->UnregisterSystemAbility(APP_MGR_SERVICE_ID); + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_1200 end"; + + mockAppMgr->ScheduleBackgroundApplication(); +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/kits/appkit/test/moduletest/appexecfwk_appkit_native_app_module_test_fourth.cpp b/kits/appkit/test/moduletest/appexecfwk_appkit_native_app_module_test_fourth.cpp new file mode 100644 index 000000000..d41d3d77a --- /dev/null +++ b/kits/appkit/test/moduletest/appexecfwk_appkit_native_app_module_test_fourth.cpp @@ -0,0 +1,353 @@ +/* + * 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 "main_thread.h" +#include "sys_mgr_client.h" +#include "system_ability_definition.h" +#include "mock_app_mgr_service.h" +#include "mock_app_thread.h" +#include "mock_ability_token.h" +#include "mock_ability_mgr_service.h" +#include "mock_bundle_mgr_service.h" + +namespace OHOS { +namespace AppExecFwk { +using namespace testing::ext; +using namespace OHOS::AppExecFwk; +using namespace OHOS; +using namespace OHOS::AAFwk; + +class AppkitNativeModuleTestThird : public testing::Test { +public: + AppkitNativeModuleTestThird() : AppMgrObject_(nullptr), mockAppMgr(nullptr), mockHandler_(nullptr), runner_(nullptr) + {} + ~AppkitNativeModuleTestThird() + {} + OHOS::sptr AppMgrObject_ = nullptr; + MockAppMgrService *mockAppMgr = nullptr; + std::shared_ptr mockHandler_ = nullptr; + std::shared_ptr runner_ = nullptr; + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void AppkitNativeModuleTestThird::SetUpTestCase(void) +{} + +void AppkitNativeModuleTestThird::TearDownTestCase(void) +{} + +void AppkitNativeModuleTestThird::SetUp(void) +{ + GTEST_LOG_(INFO) << "AppkitNativeModuleTestThird SetUp"; + AppMgrObject_ = new (std::nothrow) MockAppMgrService(); + mockAppMgr = iface_cast(AppMgrObject_); + + runner_ = EventRunner::Create("AppkitNativeModuleTestMockHandlerSecond"); + mockHandler_ = std::make_shared(runner_); + + auto task = [abilityThread = this]() { MainThread::Start(); }; + mockHandler_->PostTask(task); +} + +void AppkitNativeModuleTestThird::TearDown(void) +{ + GTEST_LOG_(INFO) << "AppkitNativeModuleTestThird TearDown"; + AppLaunchData lanchdate; + ApplicationInfo appinf; + ProcessInfo processinf("TestProcess", 9999); + appinf.name = "MockTestApplication"; + appinf.moduleSourceDirs.push_back("/hos/lib/libabilitydemo_native.z.so"); + lanchdate.SetApplicationInfo(appinf); + lanchdate.SetProcessInfo(processinf); + mockAppMgr->ScheduleLaunchApplication(lanchdate); + + usleep(50); + + mockAppMgr->ScheduleTerminateApplication(); +} + +/** + * @tc.number: App_CleanAbility_0100 + * @tc.name: App CleanAbility + * @tc.desc: Mock appmgr and register it into the systemmanager. + * The Appfwk has started successfully. + * The application has been launched successfully. + * The ability has been launched successfully. + * Clean the ability which has been launched before. + */ +HWTEST_F(AppkitNativeModuleTestThird, App_CleanAbility_0100, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "App_CleanAbility_0100 start"; + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility(APP_MGR_SERVICE_ID, AppMgrObject_); + runner_->Run(); + usleep(50); + + AppLaunchData lanchdate; + ApplicationInfo appinf; + ProcessInfo processinf("TestProcess", 9999); + appinf.name = "MockTestApplication"; + appinf.moduleSourceDirs.push_back("/hos/lib/libabilitydemo_native.z.so"); + lanchdate.SetApplicationInfo(appinf); + lanchdate.SetProcessInfo(processinf); + mockAppMgr->ScheduleLaunchApplication(lanchdate); + + usleep(50); + + AbilityInfo abilityinf; + sptr token = new (std::nothrow) MockAbilityToken(); + mockAppMgr->ScheduleLaunchAbility(abilityinf, token); + + usleep(50); + + mockAppMgr->ScheduleCleanAbility(token); + + usleep(50); + + runner_->Stop(); + OHOS::DelayedSingleton::GetInstance()->UnregisterSystemAbility(APP_MGR_SERVICE_ID); + GTEST_LOG_(INFO) << "App_CleanAbility_0100 end"; +} + +/** + * @tc.number: App_CleanAbility_0200 + * @tc.name: App CleanAbility + * @tc.desc: Mock appmgr and register it into the systemmanager. + * The Appfwk has started successfully. + * The application has been launched successfully. + * The application has not been launched successfully. + * Clean the ability before launch the application. + */ +HWTEST_F(AppkitNativeModuleTestThird, App_CleanAbility_0200, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "App_CleanAbility_0200 start"; + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility(APP_MGR_SERVICE_ID, AppMgrObject_); + runner_->Run(); + usleep(50); + + sptr token = new (std::nothrow) MockAbilityToken(); + mockAppMgr->ScheduleCleanAbility(token); + + usleep(50); + + runner_->Stop(); + OHOS::DelayedSingleton::GetInstance()->UnregisterSystemAbility(APP_MGR_SERVICE_ID); + GTEST_LOG_(INFO) << "App_CleanAbility_0200 end"; +} + +/** + * @tc.number: App_CleanAbility_0300 + * @tc.name: App CleanAbility + * @tc.desc: Mock appmgr and register it into the systemmanager. + * The Appfwk has started successfully. + * The application has been launched successfully. + * The ability has not been launched successfully. + * Clean the ability before launch the ability. + */ +HWTEST_F(AppkitNativeModuleTestThird, App_CleanAbility_0300, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "App_CleanAbility_0300 start"; + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility(APP_MGR_SERVICE_ID, AppMgrObject_); + runner_->Run(); + usleep(50); + + AppLaunchData lanchdate; + ApplicationInfo appinf; + ProcessInfo processinf("TestProcess", 9999); + appinf.name = "MockTestApplication"; + appinf.moduleSourceDirs.push_back("/hos/lib/libabilitydemo_native.z.so"); + lanchdate.SetApplicationInfo(appinf); + lanchdate.SetProcessInfo(processinf); + mockAppMgr->ScheduleLaunchApplication(lanchdate); + + usleep(50); + + sptr token = new (std::nothrow) MockAbilityToken(); + mockAppMgr->ScheduleCleanAbility(token); + + usleep(50); + + runner_->Stop(); + OHOS::DelayedSingleton::GetInstance()->UnregisterSystemAbility(APP_MGR_SERVICE_ID); + GTEST_LOG_(INFO) << "App_CleanAbility_0300 end"; +} + +/** + * @tc.number: App_CleanAbility_0400 + * @tc.name: App CleanAbility + * @tc.desc: Mock appmgr and register it into the systemmanager. + * The Appfwk has started successfully. + * The application has been launched successfully. + * The ability has been launched successfully. + * Clean the ability with a null token. + */ +HWTEST_F(AppkitNativeModuleTestThird, App_CleanAbility_0400, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "App_CleanAbility_0400 start"; + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility(APP_MGR_SERVICE_ID, AppMgrObject_); + runner_->Run(); + usleep(50); + + AppLaunchData lanchdate; + ApplicationInfo appinf; + ProcessInfo processinf("TestProcess", 9999); + appinf.name = "MockTestApplication"; + appinf.moduleSourceDirs.push_back("/hos/lib/libabilitydemo_native.z.so"); + lanchdate.SetApplicationInfo(appinf); + lanchdate.SetProcessInfo(processinf); + mockAppMgr->ScheduleLaunchApplication(lanchdate); + + usleep(50); + + AbilityInfo abilityinf; + sptr token = new (std::nothrow) MockAbilityToken(); + mockAppMgr->ScheduleLaunchAbility(abilityinf, token); + + usleep(50); + + mockAppMgr->ScheduleCleanAbility(nullptr); + + usleep(50); + + runner_->Stop(); + OHOS::DelayedSingleton::GetInstance()->UnregisterSystemAbility(APP_MGR_SERVICE_ID); + GTEST_LOG_(INFO) << "App_CleanAbility_0400 end"; +} + +/** + * @tc.number: App_CleanAbility_0500 + * @tc.name: App CleanAbility + * @tc.desc: Mock appmgr and register it into the systemmanager. + * The Appfwk has started successfully. + * The application has been launched successfully. + * The ability has been launched successfully. + * Clean the ability with a wrong token. + */ +HWTEST_F(AppkitNativeModuleTestThird, App_CleanAbility_0500, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "App_CleanAbility_0500 start"; + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility(APP_MGR_SERVICE_ID, AppMgrObject_); + runner_->Run(); + usleep(50); + + AppLaunchData lanchdate; + ApplicationInfo appinf; + ProcessInfo processinf("TestProcess", 9999); + appinf.name = "MockTestApplication"; + appinf.moduleSourceDirs.push_back("/hos/lib/libabilitydemo_native.z.so"); + lanchdate.SetApplicationInfo(appinf); + lanchdate.SetProcessInfo(processinf); + mockAppMgr->ScheduleLaunchApplication(lanchdate); + + usleep(50); + + AbilityInfo abilityinf; + sptr token = new (std::nothrow) MockAbilityToken(); + mockAppMgr->ScheduleLaunchAbility(abilityinf, token); + + usleep(50); + sptr tokenOhter = new (std::nothrow) MockAbilityToken(); + mockAppMgr->ScheduleCleanAbility(tokenOhter); + + usleep(50); + + runner_->Stop(); + OHOS::DelayedSingleton::GetInstance()->UnregisterSystemAbility(APP_MGR_SERVICE_ID); + GTEST_LOG_(INFO) << "App_CleanAbility_0500 end"; +} + +/** + * @tc.number: App_ElementsCallbacks_0100 + * @tc.name: Application ElementsCallbacks + * @tc.desc: Mock application Mock appmgr and register it into the systemmanager. + * The Appfwk has started successfully. + * The Appfwk has started successfully. + * Verifying whether ElementsCallbacks registration, unregister, and its observer mechanism are valid. + */ +HWTEST_F(AppkitNativeModuleTestThird, App_ElementsCallbacks_0100, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "App_ElementsCallbacks_0100 start"; + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility(APP_MGR_SERVICE_ID, AppMgrObject_); + runner_->Run(); + usleep(50); + + AppLaunchData lanchdate; + ApplicationInfo appinf; + ProcessInfo processinf("TestProcess", 9997); + appinf.name = "MockTestApplication"; + appinf.moduleSourceDirs.push_back("/hos/lib/libabilitydemo_native.z.so"); + lanchdate.SetApplicationInfo(appinf); + lanchdate.SetProcessInfo(processinf); + mockAppMgr->ScheduleLaunchApplication(lanchdate); + + usleep(50); + + mockAppMgr->ScheduleShrinkMemory(10); + + usleep(50); + OHOS::AppExecFwk::Configuration config("testConfig"); + + mockAppMgr->ScheduleConfigurationUpdated(config); + + usleep(50); + + mockAppMgr->ScheduleTerminateApplication(); + + usleep(50); + + runner_->Stop(); + OHOS::DelayedSingleton::GetInstance()->UnregisterSystemAbility(APP_MGR_SERVICE_ID); + GTEST_LOG_(INFO) << "App_ElementsCallbacks_0100 end"; +} + +/** + * @tc.number: App_AbilityLifecycleCallbacks_0100 + * @tc.name: Application AbilityLifecycleCallbacks + * @tc.desc: Mock ability + * Mock application + * Mock appmgr and register it into the systemmanager. + * The Appfwk has started successfully. + * The application has been launched successfully. + * The ability has been launched successfully. + * Verifying whether AbilityLifecycleCallbacks registration, unregister, and its observer mechanism are + valid. + */ +HWTEST_F(AppkitNativeModuleTestThird, App_AbilityLifecycleCallbacks_0100, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "App_AbilityLifecycleCallbacks_0100 start"; + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility(APP_MGR_SERVICE_ID, AppMgrObject_); + runner_->Run(); + usleep(50); + + AppLaunchData lanchdate; + ApplicationInfo appinf; + ProcessInfo processinf("TestProcess", 9996); + appinf.name = "MockTestApplication"; + appinf.moduleSourceDirs.push_back("/hos/lib/libabilitydemo_native.z.so"); + lanchdate.SetApplicationInfo(appinf); + lanchdate.SetProcessInfo(processinf); + mockAppMgr->ScheduleLaunchApplication(lanchdate); + + usleep(50); + + runner_->Stop(); + OHOS::DelayedSingleton::GetInstance()->UnregisterSystemAbility(APP_MGR_SERVICE_ID); + GTEST_LOG_(INFO) << "App_AbilityLifecycleCallbacks_0100 end"; +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/kits/appkit/test/moduletest/appexecfwk_appkit_native_app_module_test_second.cpp b/kits/appkit/test/moduletest/appexecfwk_appkit_native_app_module_test_second.cpp new file mode 100644 index 000000000..e42c61c8e --- /dev/null +++ b/kits/appkit/test/moduletest/appexecfwk_appkit_native_app_module_test_second.cpp @@ -0,0 +1,282 @@ +/* + * 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 "main_thread.h" +#include "sys_mgr_client.h" +#include "system_ability_definition.h" +#include "mock_app_mgr_service.h" +#include "mock_app_thread.h" +#include "mock_ability_token.h" +#include "mock_ability_mgr_service.h" +#include "mock_bundle_mgr_service.h" + +namespace OHOS { +namespace AppExecFwk { +using namespace testing::ext; +using namespace OHOS::AppExecFwk; +using namespace OHOS; +using namespace OHOS::AAFwk; + +class AppkitNativeModuleTestSecond : public testing::Test { +public: + AppkitNativeModuleTestSecond() + : AppMgrObject_(nullptr), mockAppMgr(nullptr), mockHandler_(nullptr), runner_(nullptr) + {} + ~AppkitNativeModuleTestSecond() + {} + OHOS::sptr AppMgrObject_ = nullptr; + MockAppMgrService *mockAppMgr = nullptr; + std::shared_ptr mockHandler_ = nullptr; + std::shared_ptr runner_ = nullptr; + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void AppkitNativeModuleTestSecond::SetUpTestCase(void) +{} + +void AppkitNativeModuleTestSecond::TearDownTestCase(void) +{} + +void AppkitNativeModuleTestSecond::SetUp(void) +{ + GTEST_LOG_(INFO) << "AppkitNativeModuleTestSecond SetUp"; + AppMgrObject_ = new (std::nothrow) MockAppMgrService(); + mockAppMgr = iface_cast(AppMgrObject_); + + runner_ = EventRunner::Create("AppkitNativeModuleTestMockHandlerSecond"); + mockHandler_ = std::make_shared(runner_); + + auto task = [abilityThread = this]() { MainThread::Start(); }; + mockHandler_->PostTask(task); +} + +void AppkitNativeModuleTestSecond::TearDown(void) +{ + GTEST_LOG_(INFO) << "AppkitNativeModuleTestSecond TearDown"; + AppLaunchData lanchdate; + ApplicationInfo appinf; + ProcessInfo processinf("TestProcess", 9999); + appinf.name = "MockTestApplication"; + appinf.moduleSourceDirs.push_back("/hos/lib/libabilitydemo_native.z.so"); + lanchdate.SetApplicationInfo(appinf); + lanchdate.SetProcessInfo(processinf); + mockAppMgr->ScheduleLaunchApplication(lanchdate); + + usleep(50); + + mockAppMgr->ScheduleTerminateApplication(); +} + +/** + * @tc.number: App_ApplicationLifeCycle_1300 + * @tc.name: Application lifecycle switch + * @tc.desc: Mock appmgr and register it into the systemmanager. The Appfwk has started successfully. + * Verifying when the wrong App lifecycle flows, whether the corresponding callback function will not + * be called. (StartAppfwk->LaunchApp->Foreground->Background->Background) + */ +HWTEST_F(AppkitNativeModuleTestSecond, App_ApplicationLifeCycle_1300, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_1300 start"; + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility(APP_MGR_SERVICE_ID, AppMgrObject_); + runner_->Run(); + usleep(50); + + AppLaunchData lanchdate; + ApplicationInfo appinf; + ProcessInfo processinf("TestProcess", 9999); + appinf.name = "MockTestApplication"; + appinf.moduleSourceDirs.push_back("/hos/lib/libabilitydemo_native.z.so"); + lanchdate.SetApplicationInfo(appinf); + lanchdate.SetProcessInfo(processinf); + mockAppMgr->ScheduleLaunchApplication(lanchdate); + + usleep(50); + + mockAppMgr->ScheduleForegroundApplication(); + + usleep(50); + + mockAppMgr->ScheduleBackgroundApplication(); + + usleep(50); + + mockAppMgr->ScheduleBackgroundApplication(); + + usleep(50); + + runner_->Stop(); + OHOS::DelayedSingleton::GetInstance()->UnregisterSystemAbility(APP_MGR_SERVICE_ID); + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_1300 end"; +} + +/** + * @tc.number: App_ApplicationLifeCycle_1400 + * @tc.name: Application lifecycle switch + * @tc.desc: Mock appmgr and register it into the systemmanager. The Appfwk has started successfully. + * Verifying when launch the application with a null appInfo.name, whether the corresponding callback + * function will not be called. + */ +HWTEST_F(AppkitNativeModuleTestSecond, App_ApplicationLifeCycle_1400, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_1400 start"; + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility(APP_MGR_SERVICE_ID, AppMgrObject_); + runner_->Run(); + usleep(50); + + AppLaunchData lanchdate; + ApplicationInfo appinf; + ProcessInfo processinf("TestProcess", 9999); + appinf.name = "MockTestApplication"; + appinf.moduleSourceDirs.push_back("/hos/lib/libabilitydemo_native.z.so"); + lanchdate.SetApplicationInfo(appinf); + lanchdate.SetProcessInfo(processinf); + mockAppMgr->ScheduleLaunchApplication(lanchdate); + + usleep(50); + + runner_->Stop(); + OHOS::DelayedSingleton::GetInstance()->UnregisterSystemAbility(APP_MGR_SERVICE_ID); + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_1400 end"; +} + +/** + * @tc.number: App_ApplicationLifeCycle_1500 + * @tc.name: Application lifecycle switch + * @tc.desc: Mock appmgr and register it into the systemmanager. The Appfwk has started successfully. + * Verifying when launch the application with a null processInfo.ProcessName, whether the corresponding + * callback function will not be called. + */ +HWTEST_F(AppkitNativeModuleTestSecond, App_ApplicationLifeCycle_1500, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_1500 start"; + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility(APP_MGR_SERVICE_ID, AppMgrObject_); + runner_->Run(); + usleep(50); + + AppLaunchData lanchdate; + ApplicationInfo appinf; + ProcessInfo processinf("TestProcess", 9999); + appinf.name = "MockTestApplication"; + appinf.moduleSourceDirs.push_back("/hos/lib/libabilitydemo_native.z.so"); + lanchdate.SetApplicationInfo(appinf); + lanchdate.SetProcessInfo(processinf); + mockAppMgr->ScheduleLaunchApplication(lanchdate); + + usleep(50); + + runner_->Stop(); + OHOS::DelayedSingleton::GetInstance()->UnregisterSystemAbility(APP_MGR_SERVICE_ID); + GTEST_LOG_(INFO) << "App_ApplicationLifeCycle_1500 end"; +} + +/** + * @tc.number: App_LaunchAblity_0100 + * @tc.name: App LaunchAblity + * @tc.desc: Mock appmgr and register it into the systemmanager. + * The Appfwk has started successfully. + * The application has been launched successfully. + * Launch the ability for the application. + */ +HWTEST_F(AppkitNativeModuleTestSecond, App_LaunchAblity_0100, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "App_LaunchAblity_0100 start"; + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility(APP_MGR_SERVICE_ID, AppMgrObject_); + runner_->Run(); + usleep(50); + + AppLaunchData lanchdate; + ApplicationInfo appinf; + ProcessInfo processinf("TestProcess", 9999); + appinf.name = "MockTestApplication"; + appinf.moduleSourceDirs.push_back("/hos/lib/libabilitydemo_native.z.so"); + lanchdate.SetApplicationInfo(appinf); + lanchdate.SetProcessInfo(processinf); + mockAppMgr->ScheduleLaunchApplication(lanchdate); + + usleep(50); + + AbilityInfo abilityinf; + sptr token = new (std::nothrow) MockAbilityToken(); + mockAppMgr->ScheduleLaunchAbility(abilityinf, token); + + runner_->Stop(); + OHOS::DelayedSingleton::GetInstance()->UnregisterSystemAbility(APP_MGR_SERVICE_ID); + GTEST_LOG_(INFO) << "App_LaunchAblity_0100 end"; +} + +/** + * @tc.number: App_LaunchAblity_0200 + * @tc.name: App LaunchAblity + * @tc.desc: Mock appmgr and register it into the systemmanager. + * The Appfwk has started successfully. + * The application has not been launched successfully. + * Launch the ability for the application, before the application has not been launched. + */ +HWTEST_F(AppkitNativeModuleTestSecond, App_LaunchAblity_0200, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "App_LaunchAblity_0200 start"; + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility(APP_MGR_SERVICE_ID, AppMgrObject_); + runner_->Run(); + usleep(50); + + AbilityInfo abilityinf; + sptr token = new (std::nothrow) MockAbilityToken(); + mockAppMgr->ScheduleLaunchAbility(abilityinf, token); + + runner_->Stop(); + OHOS::DelayedSingleton::GetInstance()->UnregisterSystemAbility(APP_MGR_SERVICE_ID); + GTEST_LOG_(INFO) << "App_LaunchAblity_0200 end"; +} + +/** + * @tc.number: App_LaunchAblity_0300 + * @tc.name: App LaunchAblity + * @tc.desc: Mock appmgr and register it into the systemmanager. + * The Appfwk has started successfully. + * The application has been launched successfully. + * The tocken should be null. + * Launch the ability for the application with a null token. + */ +HWTEST_F(AppkitNativeModuleTestSecond, App_LaunchAblity_0300, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "App_LaunchAblity_0300 start"; + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility(APP_MGR_SERVICE_ID, AppMgrObject_); + runner_->Run(); + usleep(50); + + AppLaunchData lanchdate; + ApplicationInfo appinf; + ProcessInfo processinf("TestProcess", 9999); + appinf.name = "MockTestApplication"; + appinf.moduleSourceDirs.push_back("/hos/lib/libabilitydemo_native.z.so"); + lanchdate.SetApplicationInfo(appinf); + lanchdate.SetProcessInfo(processinf); + mockAppMgr->ScheduleLaunchApplication(lanchdate); + + usleep(50); + + AbilityInfo abilityinf; + mockAppMgr->ScheduleLaunchAbility(abilityinf, nullptr); + + runner_->Stop(); + OHOS::DelayedSingleton::GetInstance()->UnregisterSystemAbility(APP_MGR_SERVICE_ID); + GTEST_LOG_(INFO) << "App_LaunchAblity_0300 end"; +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/kits/appkit/test/moduletest/appexecfwk_appkit_native_app_module_test_third.cpp b/kits/appkit/test/moduletest/appexecfwk_appkit_native_app_module_test_third.cpp new file mode 100644 index 000000000..4e21ad58c --- /dev/null +++ b/kits/appkit/test/moduletest/appexecfwk_appkit_native_app_module_test_third.cpp @@ -0,0 +1,122 @@ +/* + * 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 "main_thread.h" +#include "sys_mgr_client.h" +#include "system_ability_definition.h" +#include "mock_app_mgr_service.h" +#include "mock_app_thread.h" +#include "mock_ability_token.h" +#include "mock_ability_mgr_service.h" +#include "mock_bundle_mgr_service.h" + +namespace OHOS { +namespace AppExecFwk { +using namespace testing::ext; +using namespace OHOS::AppExecFwk; +using namespace OHOS; +using namespace OHOS::AAFwk; + +class AppkitNativeModuleTestThird : public testing::Test { +public: + AppkitNativeModuleTestThird() : AppMgrObject_(nullptr), mockAppMgr(nullptr), mockHandler_(nullptr), runner_(nullptr) + {} + ~AppkitNativeModuleTestThird() + {} + OHOS::sptr AppMgrObject_ = nullptr; + MockAppMgrService *mockAppMgr = nullptr; + std::shared_ptr mockHandler_ = nullptr; + std::shared_ptr runner_ = nullptr; + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void AppkitNativeModuleTestThird::SetUpTestCase(void) +{} + +void AppkitNativeModuleTestThird::TearDownTestCase(void) +{} + +void AppkitNativeModuleTestThird::SetUp(void) +{ + GTEST_LOG_(INFO) << "AppkitNativeModuleTestThird SetUp"; + AppMgrObject_ = new (std::nothrow) MockAppMgrService(); + mockAppMgr = iface_cast(AppMgrObject_); + + runner_ = EventRunner::Create("AppkitNativeModuleTestMockHandlerSecond"); + mockHandler_ = std::make_shared(runner_); + + auto task = [abilityThread = this]() { MainThread::Start(); }; + mockHandler_->PostTask(task); +} + +void AppkitNativeModuleTestThird::TearDown(void) +{ + GTEST_LOG_(INFO) << "AppkitNativeModuleTestThird TearDown"; + AppLaunchData lanchdate; + ApplicationInfo appinf; + ProcessInfo processinf("TestProcess", 9999); + appinf.name = "MockTestApplication"; + appinf.moduleSourceDirs.push_back("/hos/lib/libabilitydemo_native.z.so"); + lanchdate.SetApplicationInfo(appinf); + lanchdate.SetProcessInfo(processinf); + mockAppMgr->ScheduleLaunchApplication(lanchdate); + + usleep(50); + + mockAppMgr->ScheduleTerminateApplication(); +} + +/** + * @tc.number: App_Context_ApplicationContext_0100 + * @tc.name: Application Context + * @tc.desc: Mock appmgr and register it into the systemmanager. + * The Appfwk has started successfully. + * The application has been launched successfully. + * Verifying the interface about getting context infos when the OnStart function of application is called. + */ +HWTEST_F(AppkitNativeModuleTestThird, App_Context_ApplicationContext_0100, Function | MediumTest | Level2) +{ + GTEST_LOG_(INFO) << "App_Context_ApplicationContext_0100 start"; + OHOS::DelayedSingleton::GetInstance()->RegisterSystemAbility(APP_MGR_SERVICE_ID, AppMgrObject_); + runner_->Run(); + usleep(50); + + AppLaunchData lanchdate; + ApplicationInfo appinf; + ProcessInfo processinf("TestProcess", 9998); + appinf.name = "MockTestApplication"; + appinf.cacheDir = "/hos/lib/cacheDir"; + appinf.dataBaseDir = "/hos/lib/dataBaseDir"; + appinf.dataDir = "/hos/lib/dataDir"; + appinf.bundleName = "MockBundleName"; + appinf.moduleSourceDirs.push_back("/hos/lib/libabilitydemo_native.z.so"); + lanchdate.SetApplicationInfo(appinf); + lanchdate.SetProcessInfo(processinf); + mockAppMgr->ScheduleLaunchApplication(lanchdate); + + usleep(50); + + runner_->Stop(); + OHOS::DelayedSingleton::GetInstance()->UnregisterSystemAbility(APP_MGR_SERVICE_ID); + + usleep(50); + GTEST_LOG_(INFO) << "App_Context_ApplicationContext_0100 end"; +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/libs/libeventhandler/BUILD.gn b/libs/libeventhandler/BUILD.gn new file mode 100644 index 000000000..998c9297e --- /dev/null +++ b/libs/libeventhandler/BUILD.gn @@ -0,0 +1,30 @@ +# 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("libeventhandler_config") { + include_dirs = [ + "${appexecfwk_path}/interfaces/innerkits/libeventhandler/include", + "//utils/native/base/include", + "src", + "//base/hiviewdfx/interfaces/innerkits/libhilog/include", + ] +} + +group("libeventhandler_target") { + deps = [ + "${appexecfwk_path}/interfaces/innerkits/libeventhandler:libeventhandler", + ] +} diff --git a/libs/libeventhandler/lib_event_handler_sources.gni b/libs/libeventhandler/lib_event_handler_sources.gni new file mode 100644 index 000000000..761687118 --- /dev/null +++ b/libs/libeventhandler/lib_event_handler_sources.gni @@ -0,0 +1,27 @@ +# 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") + +lib_event_handler_sources = [ + "${libs_path}/libeventhandler/src/epoll_io_waiter.cpp", + "${libs_path}/libeventhandler/src/event_handler.cpp", + "${libs_path}/libeventhandler/src/event_queue.cpp", + "${libs_path}/libeventhandler/src/event_runner.cpp", + "${libs_path}/libeventhandler/src/file_descriptor_listener.cpp", + "${libs_path}/libeventhandler/src/inner_event.cpp", + "${libs_path}/libeventhandler/src/native_implement_eventhandler.cpp", + "${libs_path}/libeventhandler/src/none_io_waiter.cpp", +] + +event_handler_log_domain_defines = [ "LOG_DOMAIN=0xD001130" ] diff --git a/libs/libeventhandler/src/epoll_io_waiter.cpp b/libs/libeventhandler/src/epoll_io_waiter.cpp new file mode 100644 index 000000000..7b83f3a68 --- /dev/null +++ b/libs/libeventhandler/src/epoll_io_waiter.cpp @@ -0,0 +1,259 @@ +/* + * 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 "epoll_io_waiter.h" + +#include + +#include +#include +#include + +#include "event_handler_utils.h" +#include "file_descriptor_listener.h" + +DEFINE_HILOG_LABEL("EpollIoWaiter"); + +namespace OHOS { +namespace AppExecFwk { +namespace { +const size_t MAX_EPOLL_EVENTS_SIZE = 8; + +inline int32_t EpollCtrl(int32_t epollFd, int32_t operation, int32_t fileDescriptor, uint32_t epollEvents) +{ + struct epoll_event epollEvent = { + .events = epollEvents, + .data = {.fd = fileDescriptor}, + }; + + return epoll_ctl(epollFd, operation, fileDescriptor, &epollEvent); +} +} // unnamed namespace + +EpollIoWaiter::~EpollIoWaiter() +{ + // Close all valid file descriptors. + if (epollFd_ >= 0) { + close(epollFd_); + epollFd_ = -1; + } + + if (awakenFd_ >= 0) { + close(awakenFd_); + awakenFd_ = -1; + } +} + +bool EpollIoWaiter::Init() +{ + if (epollFd_ >= 0) { + HILOGE("Init: Already initialized"); + return true; + } + + int32_t epollFd = -1; + int32_t awakenFd = -1; + + do { + epollFd = epoll_create(MAX_EPOLL_EVENTS_SIZE); + if (epollFd < 0) { + HILOGE("Init: Failed to create epoll, %{public}s", GetLastErr()); + break; + } + + awakenFd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); + if (awakenFd < 0) { + HILOGE("Init: Failed to create event fd, %{public}s", GetLastErr()); + break; + } + + // Add readable file descriptor of pipe, used to wake up blocked thread. + if (EpollCtrl(epollFd, EPOLL_CTL_ADD, awakenFd, EPOLLIN | EPOLLET) < 0) { + HILOGE("Init: Failed to add awaken file descriptor into epoll, %{public}s", GetLastErr()); + break; + } + + // Prepare epoll successfully. + epollFd_ = epollFd; + awakenFd_ = awakenFd; + + return true; + } while (0); + + // If any error happened, close all valid file descriptors. + if (epollFd >= 0) { + close(epollFd); + epollFd = -1; + } + + if (awakenFd >= 0) { + close(awakenFd); + awakenFd = -1; + } + + return false; +} + +bool EpollIoWaiter::WaitFor(std::unique_lock &lock, int64_t nanoseconds) +{ + if (epollFd_ < 0) { + HILOGE("WaitFor: MUST initialized before waiting"); + return false; + } + + // Increasment of waiting count MUST be done before unlock. + ++waitingCount_; + lock.unlock(); + + // Block on epoll_wait outside of the lock. + struct epoll_event epollEvents[MAX_EPOLL_EVENTS_SIZE]; + int32_t retVal = epoll_wait(epollFd_, epollEvents, MAX_EPOLL_EVENTS_SIZE, NanosecondsToTimeout(nanoseconds)); + + // Decrease waiting count after block at once. + --waitingCount_; + + bool result = true; + if (retVal < 0) { + HILOGE("WaitFor: Failed to wait epoll, %{public}s", GetLastErr()); + result = false; + } else { + for (int32_t i = 0; i < retVal; ++i) { + if (epollEvents[i].data.fd == awakenFd_) { + // Drain awaken pipe, if woken up by it. + DrainAwakenPipe(); + continue; + } + + // Transform epoll events into file descriptor listener events. + uint32_t events = 0; + if ((epollEvents[i].events & EPOLLIN) != 0) { + events |= FILE_DESCRIPTOR_INPUT_EVENT; + } + + if ((epollEvents[i].events & EPOLLOUT) != 0) { + events |= FILE_DESCRIPTOR_OUTPUT_EVENT; + } + + if ((epollEvents[i].events & (EPOLLHUP)) != 0) { + events |= FILE_DESCRIPTOR_SHUTDOWN_EVENT; + } + + if ((epollEvents[i].events & (EPOLLERR)) != 0) { + events |= FILE_DESCRIPTOR_EXCEPTION_EVENT; + } + + if (callback_) { + callback_(epollEvents[i].data.fd, events); + } + } + } + + lock.lock(); + return result; +} + +void EpollIoWaiter::NotifyOne() +{ + // Epoll only support wake up all waiting thread. + NotifyAll(); +} + +void EpollIoWaiter::NotifyAll() +{ + if (awakenFd_ < 0) { + HILOGE("NotifyAll: MUST initialized before notifying"); + return; + } + + // Not waiting, so nothing to do. + if (waitingCount_.load() == 0) { + return; + } + + static const uint64_t increment = 1; + ssize_t retVal = write(awakenFd_, &increment, sizeof(increment)); + if (retVal < 0) { + HILOGE("NotifyAll: Failed to write data into awaken pipe, %{public}s", GetLastErr()); + } +} + +bool EpollIoWaiter::SupportListeningFileDescriptor() const +{ + return true; +} + +bool EpollIoWaiter::AddFileDescriptor(int32_t fileDescriptor, uint32_t events) +{ + if ((fileDescriptor < 0) || ((events & FILE_DESCRIPTOR_EVENTS_MASK) == 0)) { + HILOGE("AddFileDescriptor(%{public}d, %{public}u): Invalid parameter", fileDescriptor, events); + return false; + } + + if (epollFd_ < 0) { + HILOGE("AddFileDescriptor: MUST initialized before adding fds"); + return false; + } + + // Transform file descriptor listener events into epoll events. + uint32_t epollEvents = 0; + if ((events & FILE_DESCRIPTOR_INPUT_EVENT) != 0) { + epollEvents |= (EPOLLIN | EPOLLET); + } + + if ((events & FILE_DESCRIPTOR_OUTPUT_EVENT) != 0) { + epollEvents |= (EPOLLOUT | EPOLLET); + } + + if (EpollCtrl(epollFd_, EPOLL_CTL_ADD, fileDescriptor, epollEvents) < 0) { + HILOGE("AddFileDescriptor: Failed to add file descriptor into epoll, %{public}s", GetLastErr()); + return false; + } + + return true; +} + +void EpollIoWaiter::RemoveFileDescriptor(int32_t fileDescriptor) +{ + if (fileDescriptor < 0) { + HILOGE("RemoveFileDescriptor: Invalid param while removing fd, fd = %{public}d", fileDescriptor); + return; + } + + if (epollFd_ < 0) { + HILOGE("RemoveFileDescriptor: MUST initialized before removing fds"); + return; + } + + if (EpollCtrl(epollFd_, EPOLL_CTL_DEL, fileDescriptor, 0) < 0) { + HILOGE("RemoveFileDescriptor: Failed to remove file descriptor from epoll, %{public}s", GetLastErr()); + return; + } +} + +void EpollIoWaiter::DrainAwakenPipe() const +{ + uint64_t value = 0; + ssize_t retVal = read(awakenFd_, &value, sizeof(value)); + if (retVal < 0) { + HILOGE("DrainAwakenPipe: Failed to read data from awaken pipe, %{public}s", GetLastErr()); + } +} + +void EpollIoWaiter::SetFileDescriptorEventCallback(const IoWaiter::FileDescriptorEventCallback &callback) +{ + callback_ = callback; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/libs/libeventhandler/src/epoll_io_waiter.h b/libs/libeventhandler/src/epoll_io_waiter.h new file mode 100644 index 000000000..7f274bab4 --- /dev/null +++ b/libs/libeventhandler/src/epoll_io_waiter.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_LIBS_LIBEVENTHANDLER_SRC_EPOLL_IO_WAITER_H +#define FOUNDATION_APPEXECFWK_LIBS_LIBEVENTHANDLER_SRC_EPOLL_IO_WAITER_H + +#include +#include + +#include "nocopyable.h" +#include "io_waiter.h" + +namespace OHOS { +namespace AppExecFwk { +// Use epoll to listen file descriptor. +class EpollIoWaiter final : public IoWaiter { +public: + EpollIoWaiter() = default; + ~EpollIoWaiter() final; + DISALLOW_COPY_AND_MOVE(EpollIoWaiter); + + /** + * Initialize epoll. + * + * @return True if succeeded. + */ + bool Init(); + + bool WaitFor(std::unique_lock &lock, int64_t nanoseconds) final; + + void NotifyOne() final; + void NotifyAll() final; + + bool SupportListeningFileDescriptor() const final; + + bool AddFileDescriptor(int32_t fileDescriptor, uint32_t events) final; + void RemoveFileDescriptor(int32_t fileDescriptor) final; + + void SetFileDescriptorEventCallback(const FileDescriptorEventCallback &callback) final; + +private: + void DrainAwakenPipe() const; + + // File descriptor for epoll. + int32_t epollFd_{-1}; + // File descriptor used to wake up epoll. + int32_t awakenFd_{-1}; + + FileDescriptorEventCallback callback_; + std::atomic waitingCount_{0}; +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // #ifndef FOUNDATION_APPEXECFWK_LIBS_LIBEVENTHANDLER_SRC_EPOLL_IO_WAITER_H diff --git a/libs/libeventhandler/src/event_handler.cpp b/libs/libeventhandler/src/event_handler.cpp new file mode 100644 index 000000000..df18ce567 --- /dev/null +++ b/libs/libeventhandler/src/event_handler.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 "event_handler.h" + +#include "event_handler_utils.h" +#include "thread_local_data.h" + +DEFINE_HILOG_LABEL("EventHandler"); + +namespace OHOS { +namespace AppExecFwk { + +static constexpr int DATETIME_STRING_LENGTH = 80; + +ThreadLocalData> EventHandler::currentEventHandler; + +std::shared_ptr EventHandler::Current() +{ + const std::weak_ptr &wp = currentEventHandler; + return wp.lock(); +} + +EventHandler::EventHandler(const std::shared_ptr &runner) : eventRunner_(runner) +{} + +EventHandler::~EventHandler() +{ + if (eventRunner_) { + /* + * This handler is finishing, need to remove all events belong to it. + * But events only have weak pointer of this handler, + * now weak pointer is invalid, so these events become orphans. + */ + eventRunner_->GetEventQueue()->RemoveOrphan(); + } +} + +bool EventHandler::SendEvent(InnerEvent::Pointer &event, int64_t delayTime, Priority priority) +{ + if (!event) { + HILOGE("SendEvent: Could not send an invalid event"); + return false; + } + + if (!eventRunner_) { + HILOGE("SendEvent: MUST Set event runner before sending events"); + return false; + } + + InnerEvent::TimePoint now = InnerEvent::Clock::now(); + event->SetSendTime(now); + + if (delayTime > 0) { + event->SetHandleTime(now + std::chrono::milliseconds(delayTime)); + } else { + event->SetHandleTime(now); + } + + event->SetOwner(shared_from_this()); + eventRunner_->GetEventQueue()->Insert(event, priority); + return true; +} + +bool EventHandler::SendTimingEvent(InnerEvent::Pointer &event, int64_t taskTime, Priority priority) +{ + InnerEvent::TimePoint nowSys = InnerEvent::Clock::now(); + auto epoch = nowSys.time_since_epoch(); + long nowSysTime = std::chrono::duration_cast(epoch).count(); + int64_t delayTime = taskTime - nowSysTime; + if (delayTime < 0) { + HILOGE("SendTimingEvent: SendTime is before now systime, change to 0 delaytime Event"); + return SendEvent(event, 0, priority); + } + + return SendEvent(event, delayTime, priority); +} + +bool EventHandler::SendSyncEvent(InnerEvent::Pointer &event, Priority priority) +{ + if ((!event) || (priority == Priority::IDLE)) { + HILOGE("SendSyncEvent: Could not send an invalid event or idle event"); + return false; + } + + if ((!eventRunner_) || (!eventRunner_->IsRunning())) { + HILOGE("SendSyncEvent: MUST Set a running event runner before sending sync events"); + return false; + } + + // If send a sync event in same event runner, distribute here. + if (eventRunner_ == EventRunner::Current()) { + DistributeEvent(event); + return true; + } + // Create waiter, used to block. + auto waiter = event->CreateWaiter(); + // Send this event as normal one. + if (!SendEvent(event, 0, priority)) { + return false; + } + // Wait until event is processed(recycled). + waiter->Wait(); + + return true; +} + +void EventHandler::RemoveAllEvents() +{ + if (!eventRunner_) { + HILOGE("RemoveAllEvents: MUST Set event runner before removing all events"); + return; + } + + eventRunner_->GetEventQueue()->Remove(shared_from_this()); +} + +void EventHandler::RemoveEvent(uint32_t innerEventId) +{ + if (!eventRunner_) { + HILOGE("RemoveEvent: MUST Set event runner before removing events by id"); + return; + } + + eventRunner_->GetEventQueue()->Remove(shared_from_this(), innerEventId); +} + +void EventHandler::RemoveEvent(uint32_t innerEventId, int64_t param) +{ + if (!eventRunner_) { + HILOGE("RemoveEvent: MUST Set event runner before removing events by id and param"); + return; + } + + eventRunner_->GetEventQueue()->Remove(shared_from_this(), innerEventId, param); +} + +void EventHandler::RemoveTask(const std::string &name) +{ + if (!eventRunner_) { + HILOGE("RemoveTask: MUST Set event runner before removing events by task name"); + return; + } + + eventRunner_->GetEventQueue()->Remove(shared_from_this(), name); +} + +ErrCode EventHandler::AddFileDescriptorListener( + int32_t fileDescriptor, uint32_t events, const std::shared_ptr &listener) +{ + if ((fileDescriptor < 0) || ((events & FILE_DESCRIPTOR_EVENTS_MASK) == 0) || (!listener)) { + HILOGE("AddFileDescriptorListener(%{public}d, %{public}u, %{public}s): Invalid parameter", + fileDescriptor, + events, + listener ? "valid" : "null"); + return EVENT_HANDLER_ERR_INVALID_PARAM; + } + + if (!eventRunner_) { + HILOGE("AddFileDescriptorListener: MUST Set event runner before adding fd listener"); + return EVENT_HANDLER_ERR_NO_EVENT_RUNNER; + } + + listener->SetOwner(shared_from_this()); + return eventRunner_->GetEventQueue()->AddFileDescriptorListener(fileDescriptor, events, listener); +} + +void EventHandler::RemoveAllFileDescriptorListeners() +{ + if (!eventRunner_) { + HILOGE("RemoveAllFileDescriptorListeners: MUST Set event runner before removing all fd listener"); + return; + } + + eventRunner_->GetEventQueue()->RemoveFileDescriptorListener(shared_from_this()); +} + +void EventHandler::RemoveFileDescriptorListener(int32_t fileDescriptor) +{ + if (fileDescriptor < 0) { + HILOGE("RemoveFileDescriptorListener(%{public}d): Invalid parameter", fileDescriptor); + return; + } + + if (!eventRunner_) { + HILOGE("RemoveFileDescriptorListener: MUST Set event runner before removing fd listener by fd"); + return; + } + + eventRunner_->GetEventQueue()->RemoveFileDescriptorListener(fileDescriptor); +} + +void EventHandler::SetEventRunner(const std::shared_ptr &runner) +{ + if (eventRunner_ == runner) { + return; + } + + if (eventRunner_) { + HILOGW("SetEventRunner: It is not recommended to change the event runner dynamically"); + + // Remove all events and listeners from old event runner. + RemoveAllEvents(); + RemoveAllFileDescriptorListeners(); + } + + // Switch event runner. + eventRunner_ = runner; + return; +} + +void EventHandler::DistributeEvent(const InnerEvent::Pointer &event) +{ + if (!event) { + HILOGE("DistributeEvent: Could not distribute an invalid event"); + return; + } + + // Save old event handler. + std::weak_ptr oldHandler = currentEventHandler; + // Save current event handler into thread local data. + currentEventHandler = shared_from_this(); + if (event->HasTask()) { + // Call task callback directly if contains a task. + (event->GetTaskCallback())(); + } else { + // Otherwise let developers to handle it. + ProcessEvent(event); + } + // Restore current event handler. + if (oldHandler.expired()) { + currentEventHandler = nullptr; + } else { + currentEventHandler = oldHandler; + } +} + +void EventHandler::Dump(Dumper &dumper) +{ + struct tm curTime = {0}; + + auto tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + localtime_r(&tt, &curTime); + + char sysTime[DATETIME_STRING_LENGTH]; + std::strftime(sysTime, sizeof(char) * DATETIME_STRING_LENGTH, "%Y%m%d %I:%M %p", &curTime); + std::string message = + dumper.GetTag() + " EventHandler dump begain curTime:" + std::string(sysTime) + LINE_SEPARATOR; + dumper.Dump(message); + + if (eventRunner_ == nullptr) { + dumper.Dump(dumper.GetTag() + " event runner uninitialized!" + LINE_SEPARATOR); + } else { + eventRunner_->Dump(dumper); + } +} + +bool EventHandler::HasInnerEvent(uint32_t innerEventId) +{ + if (!eventRunner_) { + HILOGE("event runner uninitialized!"); + return false; + } + return eventRunner_->GetEventQueue()->HasInnerEvent(shared_from_this(), innerEventId); +} + +bool EventHandler::HasInnerEvent(int64_t param) +{ + if (!eventRunner_) { + HILOGE("event runner uninitialized!"); + return false; + } + return eventRunner_->GetEventQueue()->HasInnerEvent(shared_from_this(), param); +} + +std::string EventHandler::GetEventName(const InnerEvent::Pointer &event) +{ + std::string eventName; + if (!event) { + return eventName; + } + + if (event->HasTask()) { + eventName = event->GetTaskName(); + } else { + eventName = std::to_string(event->GetInnerEventId()); + } + return eventName; +} + +bool EventHandler::IsIdle() +{ + return eventRunner_->GetEventQueue()->IsIdle(); +} + +void EventHandler::ProcessEvent(const InnerEvent::Pointer &) +{} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/libs/libeventhandler/src/event_handler_utils.h b/libs/libeventhandler/src/event_handler_utils.h new file mode 100644 index 000000000..df06ec814 --- /dev/null +++ b/libs/libeventhandler/src/event_handler_utils.h @@ -0,0 +1,72 @@ +/* + * 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_LIBS_LIBEVENTHANDLER_SRC_EVENT_HANDLER_UTILS_H +#define FOUNDATION_APPEXECFWK_LIBS_LIBEVENTHANDLER_SRC_EVENT_HANDLER_UTILS_H + +#include +#include +#include +#include + +#include "hilog/log.h" +#include "inner_event.h" + +#define DEFINE_HILOG_LABEL(name) static constexpr OHOS::HiviewDFX::HiLogLabel LOG_LABEL = {LOG_CORE, LOG_DOMAIN, name} + +#define HILOGE(...) OHOS::HiviewDFX::HiLog::Error(LOG_LABEL, ##__VA_ARGS__) +#define HILOGW(...) OHOS::HiviewDFX::HiLog::Warn(LOG_LABEL, ##__VA_ARGS__) +#define HILOGI(...) OHOS::HiviewDFX::HiLog::Info(LOG_LABEL, ##__VA_ARGS__) +#define HILOGD(...) OHOS::HiviewDFX::HiLog::Debug(LOG_LABEL, ##__VA_ARGS__) + +namespace OHOS { +namespace AppExecFwk { +inline const int64_t NANOSECONDS_PER_ONE_MILLISECOND = 1000000; +inline const int64_t NANOSECONDS_PER_ONE_SECOND = 1000000000; +inline const int32_t INFINITE_TIMEOUT = -1; + +// Help to convert time point into delay time from now. +static inline int64_t TimePointToTimeOut(const InnerEvent::TimePoint &when) +{ + if (when <= InnerEvent::Clock::now()) { + return 0; + } + + auto duration = when - InnerEvent::Clock::now(); + return std::chrono::duration_cast(duration).count(); +} + +static inline int32_t NanosecondsToTimeout(int64_t nanoseconds) +{ + if (nanoseconds < 0) { + return INFINITE_TIMEOUT; + } + + int64_t milliseconds = nanoseconds / NANOSECONDS_PER_ONE_MILLISECOND; + if ((nanoseconds % NANOSECONDS_PER_ONE_MILLISECOND) > 0) { + milliseconds += 1; + } + + return (milliseconds > INT32_MAX) ? INT32_MAX : static_cast(milliseconds); +} + +static inline char *GetLastErr() +{ + return strerror(errno); +} +} // namespace AppExecFwk +} // namespace OHOS + +#endif // #ifndef FOUNDATION_APPEXECFWK_LIBS_LIBEVENTHANDLER_SRC_EVENT_HANDLER_UTILS_H diff --git a/libs/libeventhandler/src/event_inner_runner.h b/libs/libeventhandler/src/event_inner_runner.h new file mode 100644 index 000000000..d0d2bd732 --- /dev/null +++ b/libs/libeventhandler/src/event_inner_runner.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_LIBS_LIBEVENTHANDLER_SRC_EVENT_INNER_RUNNER_H +#define FOUNDATION_APPEXECFWK_LIBS_LIBEVENTHANDLER_SRC_EVENT_INNER_RUNNER_H + +#include "event_handler_utils.h" +#include "event_queue.h" +#include "event_runner.h" +#include "nocopyable.h" +#include "thread_local_data.h" + +namespace OHOS { +namespace AppExecFwk { +class EventInnerRunner { +public: + explicit EventInnerRunner(const std::shared_ptr &runner); + virtual ~EventInnerRunner() = default; + DISALLOW_COPY_AND_MOVE(EventInnerRunner); + + static std::shared_ptr GetCurrentEventRunner(); + + virtual void Run() = 0; + virtual void Stop() = 0; + + const std::shared_ptr &GetEventQueue() const + { + return queue_; + } + + void SetLogger(const std::shared_ptr &logger) + { + logger_ = logger; + } + + const std::string &GetThreadName() + { + return threadName_; + } + + const std::thread::id &GetThreadId() + { + return threadId_; + } + +protected: + std::shared_ptr queue_; + std::weak_ptr owner_; + std::shared_ptr logger_; + static ThreadLocalData> currentEventRunner; + std::string threadName_; + std::thread::id threadId_; +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // #ifndef FOUNDATION_APPEXECFWK_LIBS_LIBEVENTHANDLER_SRC_EVENT_INNER_RUNNER_H diff --git a/libs/libeventhandler/src/event_queue.cpp b/libs/libeventhandler/src/event_queue.cpp new file mode 100644 index 000000000..dc1fc3d95 --- /dev/null +++ b/libs/libeventhandler/src/event_queue.cpp @@ -0,0 +1,551 @@ +/* + * 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 "event_queue.h" + +#include + +#include "epoll_io_waiter.h" +#include "event_handler.h" +#include "event_handler_utils.h" +#include "none_io_waiter.h" + +DEFINE_HILOG_LABEL("EventQueue"); + +namespace OHOS { +namespace AppExecFwk { +namespace { +// Help to insert events into the event queue sorted by handle time. +inline void InsertEventsLocked(std::list &events, InnerEvent::Pointer &event) +{ + auto f = [](const InnerEvent::Pointer &first, const InnerEvent::Pointer &second) { + if (!first || !second) { + return false; + } + return first->GetHandleTime() < second->GetHandleTime(); + }; + auto it = std::upper_bound(events.begin(), events.end(), event, f); + events.insert(it, std::move(event)); +} + +// Help to remove file descriptor listeners. +template +void RemoveFileDescriptorListenerLocked(std::map> &listeners, + const std::shared_ptr &ioWaiter, const T &filter) +{ + if (!ioWaiter) { + return; + } + for (auto it = listeners.begin(); it != listeners.end(); ) { + if (filter(it->second)) { + ioWaiter->RemoveFileDescriptor(it->first); + it = listeners.erase(it); + } else { + ++it; + } + } +} + +// Help to check whether there is a valid event in list and update wake up time. +inline bool CheckEventInListLocked(const std::list &events, const InnerEvent::TimePoint &now, + InnerEvent::TimePoint &nextWakeUpTime) +{ + if (!events.empty()) { + const auto &handleTime = events.front()->GetHandleTime(); + if (handleTime < nextWakeUpTime) { + nextWakeUpTime = handleTime; + return handleTime <= now; + } + } + + return false; +} + +inline InnerEvent::Pointer PopFrontEventFromListLocked(std::list &events) +{ + InnerEvent::Pointer event = std::move(events.front()); + events.pop_front(); + return event; +} +} // unnamed namespace + +EventQueue::EventQueue() : ioWaiter_(std::make_shared()) +{} + +EventQueue::EventQueue(const std::shared_ptr &ioWaiter) + : ioWaiter_(ioWaiter ? ioWaiter : std::make_shared()) +{ + if (ioWaiter_->SupportListeningFileDescriptor()) { + // Set callback to handle events from file descriptors. + ioWaiter_->SetFileDescriptorEventCallback( + std::bind(&EventQueue::HandleFileDescriptorEvent, this, std::placeholders::_1, std::placeholders::_2)); + } +} + +void EventQueue::Insert(InnerEvent::Pointer &event, Priority priority) +{ + if (!event) { + HILOGE("Insert: Could not insert an invalid event"); + return; + } + + std::lock_guard lock(queueLock_); + bool needNotify = false; + switch (priority) { + case Priority::IMMEDIATE: + case Priority::HIGH: + case Priority::LOW: { + needNotify = (event->GetHandleTime() < wakeUpTime_); + InsertEventsLocked(subEventQueues_[static_cast(priority)].queue, event); + break; + } + case Priority::IDLE: { + // Never wake up thread if insert an idle event. + InsertEventsLocked(idleEvents_, event); + break; + } + default: + break; + } + + if (needNotify) { + ioWaiter_->NotifyOne(); + } +} + +void EventQueue::RemoveOrphan() +{ + // Remove all events which lost its owner. + auto filter = [](const InnerEvent::Pointer &p) { return !p->GetOwner(); }; + + Remove(filter); + + // Remove all listeners which lost its owner. + auto listenerFilter = [](const std::shared_ptr &listener) { + if (!listener) { + return true; + } + return !listener->GetOwner(); + }; + + std::lock_guard lock(queueLock_); + RemoveFileDescriptorListenerLocked(listeners_, ioWaiter_, listenerFilter); +} + +void EventQueue::Remove(const std::shared_ptr &owner) +{ + if (!owner) { + HILOGE("Remove: Invalid owner"); + return; + } + + auto filter = [&owner](const InnerEvent::Pointer &p) { return (p->GetOwner() == owner); }; + + Remove(filter); +} + +void EventQueue::Remove(const std::shared_ptr &owner, uint32_t innerEventId) +{ + if (!owner) { + HILOGE("Remove: Invalid owner"); + return; + } + + auto filter = [&owner, innerEventId](const InnerEvent::Pointer &p) { + return (!p->HasTask()) && (p->GetOwner() == owner) && (p->GetInnerEventId() == innerEventId); + }; + + Remove(filter); +} + +void EventQueue::Remove(const std::shared_ptr &owner, uint32_t innerEventId, int64_t param) +{ + if (!owner) { + HILOGE("Remove: Invalid owner"); + return; + } + + auto filter = [&owner, innerEventId, param](const InnerEvent::Pointer &p) { + return (!p->HasTask()) && (p->GetOwner() == owner) && (p->GetInnerEventId() == innerEventId) && + (p->GetParam() == param); + }; + + Remove(filter); +} + +void EventQueue::Remove(const std::shared_ptr &owner, const std::string &name) +{ + if ((!owner) || (name.empty())) { + HILOGE("Remove: Invalid owner or task name"); + return; + } + + auto filter = [&owner, &name](const InnerEvent::Pointer &p) { + return (p->HasTask()) && (p->GetOwner() == owner) && (p->GetTaskName() == name); + }; + + Remove(filter); +} + +void EventQueue::Remove(const RemoveFilter &filter) +{ + std::lock_guard lock(queueLock_); + for (uint32_t i = 0; i < SUB_EVENT_QUEUE_NUM; ++i) { + subEventQueues_[i].queue.remove_if(filter); + } + idleEvents_.remove_if(filter); +} + +bool EventQueue::HasInnerEvent(const std::shared_ptr &owner, uint32_t innerEventId) +{ + if (!owner) { + HILOGE("HasInnerEvent: Invalid owner"); + return false; + } + auto filter = [&owner, innerEventId](const InnerEvent::Pointer &p) { + return (!p->HasTask()) && (p->GetOwner() == owner) && (p->GetInnerEventId() == innerEventId); + }; + return HasInnerEvent(filter); +} + +bool EventQueue::HasInnerEvent(const std::shared_ptr &owner, int64_t param) +{ + if (!owner) { + HILOGE("HasInnerEvent: Invalid owner"); + return false; + } + auto filter = [&owner, param](const InnerEvent::Pointer &p) { + return (!p->HasTask()) && (p->GetOwner() == owner) && (p->GetParam() == param); + }; + return HasInnerEvent(filter); +} + +bool EventQueue::HasInnerEvent(const HasFilter &filter) +{ + std::lock_guard lock(queueLock_); + for (uint32_t i = 0; i < SUB_EVENT_QUEUE_NUM; ++i) { + std::list::iterator iter = + std::find_if(subEventQueues_[i].queue.begin(), subEventQueues_[i].queue.end(), filter); + if (iter != subEventQueues_[i].queue.end()) { + return true; + } + } + std::list::iterator iter = std::find_if(idleEvents_.begin(), idleEvents_.end(), filter); + return iter != idleEvents_.end(); +} + +InnerEvent::Pointer EventQueue::PickEventLocked(const InnerEvent::TimePoint &now, InnerEvent::TimePoint &nextWakeUpTime) +{ + uint32_t priorityIndex = SUB_EVENT_QUEUE_NUM; + for (uint32_t i = 0; i < SUB_EVENT_QUEUE_NUM; ++i) { + // Check whether any event need to be distributed. + if (!CheckEventInListLocked(subEventQueues_[i].queue, now, nextWakeUpTime)) { + continue; + } + + // Check whether any event in higher priority need to be distributed. + if (priorityIndex < SUB_EVENT_QUEUE_NUM) { + SubEventQueue &subQueue = subEventQueues_[priorityIndex]; + // Check whether enough events in higher priority queue are handled continuously. + if (subQueue.handledEventsCount < subQueue.maxHandledEventsCount) { + subQueue.handledEventsCount++; + break; + } + } + + // Try to pick event from this queue. + priorityIndex = i; + } + + if (priorityIndex >= SUB_EVENT_QUEUE_NUM) { + // If not found any event to distribute, return nullptr. + return InnerEvent::Pointer(nullptr, nullptr); + } + + // Reset handled event count for sub event queues in higher priority. + for (uint32_t i = 0; i < priorityIndex; ++i) { + subEventQueues_[i].handledEventsCount = 0; + } + + return PopFrontEventFromListLocked(subEventQueues_[priorityIndex].queue); +} + +InnerEvent::Pointer EventQueue::GetExpiredEventLocked(InnerEvent::TimePoint &nextExpiredTime) +{ + auto now = InnerEvent::Clock::now(); + wakeUpTime_ = InnerEvent::TimePoint::max(); + // Find an event which could be distributed right now. + InnerEvent::Pointer event = PickEventLocked(now, wakeUpTime_); + if (event) { + // Exit idle mode, if found an event to distribute. + isIdle_ = false; + return event; + } + + // If found nothing, enter idle mode and make a time stamp. + if (!isIdle_) { + isIdle_ = true; + } + idleTimeStamp_ = now; + + if (!idleEvents_.empty()) { + const auto &idleEvent = idleEvents_.front(); + + if (wakeUpTime_ > idleEvent->GetHandleTime()) { + wakeUpTime_ = idleEvent->GetHandleTime(); + } + + // Return the idle event that has been sent before time stamp and reaches its handle time. + if ((idleEvent->GetSendTime() <= idleTimeStamp_) && (idleEvent->GetHandleTime() <= now)) { + return PopFrontEventFromListLocked(idleEvents_); + } + } + + // Update wake up time. + nextExpiredTime = wakeUpTime_; + return InnerEvent::Pointer(nullptr, nullptr); +} + +InnerEvent::Pointer EventQueue::GetEvent() +{ + std::unique_lock lock(queueLock_); + while (!finished_) { + InnerEvent::TimePoint nextWakeUpTime = InnerEvent::TimePoint::max(); + InnerEvent::Pointer event = GetExpiredEventLocked(nextWakeUpTime); + if (event) { + return event; + } + WaitUntilLocked(nextWakeUpTime, lock); + } + + HILOGD("GetEvent: Break out"); + return InnerEvent::Pointer(nullptr, nullptr); +} + +InnerEvent::Pointer EventQueue::GetExpiredEvent(InnerEvent::TimePoint &nextExpiredTime) +{ + std::unique_lock lock(queueLock_); + return GetExpiredEventLocked(nextExpiredTime); +} + +ErrCode EventQueue::AddFileDescriptorListener( + int32_t fileDescriptor, uint32_t events, const std::shared_ptr &listener) +{ + if ((fileDescriptor < 0) || ((events & FILE_DESCRIPTOR_EVENTS_MASK) == 0) || (!listener)) { + HILOGE("AddFileDescriptorListener(%{public}d, %{public}u, %{public}s): Invalid parameter", + fileDescriptor, + events, + listener ? "valid" : "null"); + return EVENT_HANDLER_ERR_INVALID_PARAM; + } + + std::lock_guard lock(queueLock_); + auto it = listeners_.find(fileDescriptor); + if (it != listeners_.end()) { + HILOGE("AddFileDescriptorListener: File descriptor %{public}d is already in listening", fileDescriptor); + return EVENT_HANDLER_ERR_FD_ALREADY; + } + + if (!EnsureIoWaiterSupportListerningFileDescriptorLocked()) { + return EVENT_HANDLER_ERR_FD_NOT_SUPPORT; + } + + if (!ioWaiter_->AddFileDescriptor(fileDescriptor, events)) { + HILOGE("AddFileDescriptorListener: Failed to add file descriptor into IO waiter"); + return EVENT_HANDLER_ERR_FD_FAILED; + } + + listeners_.emplace(fileDescriptor, listener); + return ERR_OK; +} + +void EventQueue::RemoveFileDescriptorListener(const std::shared_ptr &owner) +{ + if (!owner) { + HILOGE("RemoveFileDescriptorListener: Invalid owner"); + return; + } + + auto listenerFilter = [&owner](const std::shared_ptr &listener) { + if (!listener) { + return false; + } + return listener->GetOwner() == owner; + }; + + std::lock_guard lock(queueLock_); + RemoveFileDescriptorListenerLocked(listeners_, ioWaiter_, listenerFilter); +} + +void EventQueue::RemoveFileDescriptorListener(int32_t fileDescriptor) +{ + if (fileDescriptor < 0) { + HILOGE("RemoveFileDescriptorListener(%{public}d): Invalid file descriptor", fileDescriptor); + return; + } + + std::lock_guard lock(queueLock_); + if (listeners_.erase(fileDescriptor) > 0) { + ioWaiter_->RemoveFileDescriptor(fileDescriptor); + } +} + +void EventQueue::Prepare() +{ + std::lock_guard lock(queueLock_); + finished_ = false; +} + +void EventQueue::Finish() +{ + std::lock_guard lock(queueLock_); + finished_ = true; + ioWaiter_->NotifyAll(); +} + +void EventQueue::WaitUntilLocked(const InnerEvent::TimePoint &when, std::unique_lock &lock) +{ + // Get a temp reference of IO waiter, otherwise it maybe released while waiting. + auto ioWaiterHolder = ioWaiter_; + if (!ioWaiterHolder->WaitFor(lock, TimePointToTimeOut(when))) { + HILOGE("WaitUntilLocked: Failed to call wait, reset IO waiter"); + ioWaiter_ = std::make_shared(); + listeners_.clear(); + } +} + +void EventQueue::HandleFileDescriptorEvent(int32_t fileDescriptor, uint32_t events) +{ + std::shared_ptr listener; + + { + std::lock_guard lock(queueLock_); + auto it = listeners_.find(fileDescriptor); + if (it == listeners_.end()) { + HILOGW("HandleFileDescriptorEvent: Can not found listener, maybe it is removed"); + return; + } + + // Hold instance of listener. + listener = it->second; + if (!listener) { + return; + } + } + + auto handler = listener->GetOwner(); + if (!handler) { + HILOGW("HandleFileDescriptorEvent: Owner of listener is released"); + return; + } + + std::weak_ptr wp = listener; + auto f = [fileDescriptor, events, wp]() { + auto listener = wp.lock(); + if (!listener) { + HILOGW("HandleFileDescriptorEvent-Lambda: Listener is released"); + return; + } + + if ((events & FILE_DESCRIPTOR_INPUT_EVENT) != 0) { + listener->OnReadable(fileDescriptor); + } + + if ((events & FILE_DESCRIPTOR_OUTPUT_EVENT) != 0) { + listener->OnWritable(fileDescriptor); + } + + if ((events & FILE_DESCRIPTOR_SHUTDOWN_EVENT) != 0) { + listener->OnShutdown(fileDescriptor); + } + + if ((events & FILE_DESCRIPTOR_EXCEPTION_EVENT) != 0) { + listener->OnException(fileDescriptor); + } + }; + + // Post a high priority task to handle file descriptor events. + handler->PostHighPriorityTask(f); +} + +bool EventQueue::EnsureIoWaiterSupportListerningFileDescriptorLocked() +{ + if (ioWaiter_->SupportListeningFileDescriptor()) { + return true; + } + + auto newIoWaiter = std::make_shared(); + if (!newIoWaiter->Init()) { + HILOGE("EnsureIoWaiterSupportListerningFileDescriptorLocked: Failed to initialize epoll"); + return false; + } + + // Set callback to handle events from file descriptors. + newIoWaiter->SetFileDescriptorEventCallback( + std::bind(&EventQueue::HandleFileDescriptorEvent, this, std::placeholders::_1, std::placeholders::_2)); + + ioWaiter_->NotifyAll(); + ioWaiter_ = newIoWaiter; + return true; +} + +void EventQueue::Dump(Dumper &dumper) +{ + std::lock_guard lock(queueLock_); + std::string priority[] = {"Immediate", "High", "Low"}; + uint32_t total = 0; + for (uint32_t i = 0; i < SUB_EVENT_QUEUE_NUM; ++i) { + uint32_t n = 0; + dumper.Dump(dumper.GetTag() + " " + priority[i] + " priority event queue information:" + LINE_SEPARATOR); + for (auto it = subEventQueues_[i].queue.begin(); it != subEventQueues_[i].queue.end(); ++it) { + ++n; + dumper.Dump(dumper.GetTag() + " No." + std::to_string(n) + " : " + (*it)->Dump()); + ++total; + } + dumper.Dump( + dumper.GetTag() + " Total size of " + priority[i] + " events : " + std::to_string(n) + LINE_SEPARATOR); + } + + dumper.Dump(dumper.GetTag() + " Idle priority event queue information:" + LINE_SEPARATOR); + int n = 0; + for (auto it = idleEvents_.begin(); it != idleEvents_.end(); ++it) { + ++n; + dumper.Dump(dumper.GetTag() + " No." + std::to_string(n) + " : " + (*it)->Dump()); + ++total; + } + dumper.Dump(dumper.GetTag() + " Total size of Idle events : " + std::to_string(n) + LINE_SEPARATOR); + + dumper.Dump(dumper.GetTag() + " Total event size : " + std::to_string(total) + LINE_SEPARATOR); +} + +bool EventQueue::IsIdle() +{ + return isIdle_; +} + +bool EventQueue::IsQueueEmpty() +{ + std::lock_guard lock(queueLock_); + for (uint32_t i = 0; i < SUB_EVENT_QUEUE_NUM; ++i) { + uint32_t queueSize = subEventQueues_[i].queue.size(); + if (queueSize != 0) { + return false; + } + } + + return idleEvents_.size() == 0; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/libs/libeventhandler/src/event_runner.cpp b/libs/libeventhandler/src/event_runner.cpp new file mode 100644 index 000000000..1c635df8c --- /dev/null +++ b/libs/libeventhandler/src/event_runner.cpp @@ -0,0 +1,551 @@ +/* + * 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 "event_runner.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "event_handler.h" +#include "event_handler_utils.h" +#include "event_inner_runner.h" +#include "thread_local_data.h" +#include "singleton.h" + +DEFINE_HILOG_LABEL("EventRunner"); + +namespace OHOS { +namespace AppExecFwk { +namespace { +// Invoke system call to set name of current thread. +inline void SystemCallSetThreadName(const std::string &name) +{ + if (prctl(PR_SET_NAME, name.c_str()) < 0) { + HILOGW("SystemCallSetThreadName: Failed to set thread name, %{public}s", GetLastErr()); + } +} + +// Help to calculate hash code of object. +template +inline size_t CalculateHashCode(const T &obj) +{ + std::hash calculateHashCode; + return calculateHashCode(obj); +} + +// Thread collector is used to reclaim thread that needs to finish running. +class ThreadCollector : public DelayedRefSingleton { + DECLARE_DELAYED_REF_SINGLETON(ThreadCollector); + +public: + DISALLOW_COPY_AND_MOVE(ThreadCollector); + + using ExitFunction = std::function; + + void ReclaimCurrentThread() + { + // Get id of current thread. + auto threadId = std::this_thread::get_id(); + HILOGD("Reclaim: Thread id: %{public}zu", CalculateHashCode(threadId)); + + { + // Add thread id to list and notify to reclaim. + std::lock_guard lock(collectorLock_); + if (destroying_) { + HILOGI("Reclaim: Thread collector is destroying"); + return; + } + + reclaims_.emplace_back(threadId); + if (isWaiting_) { + condition_.notify_one(); + } + } + + if (threadLock_.try_lock()) { + if ((!thread_) && (needCreateThread_)) { + // Start daemon thread to collect finished threads, if not exist. + thread_ = std::make_unique(&ThreadCollector::Run, this); + } + threadLock_.unlock(); + } + } + + bool Deposit(std::unique_ptr &thread, const ExitFunction &threadExit) + { + if ((!thread) || (!thread->joinable()) || (!threadExit)) { + auto threadState = thread ? (thread->joinable() ? "active" : "finished") : "null"; + HILOGE("Deposit(%{public}s, %{public}s): Invalid parameter", threadState, threadExit ? "valid" : "null"); + return false; + } + + auto threadId = thread->get_id(); + HILOGD("Deposit: New thread id: %{public}zu", CalculateHashCode(threadId)); + // Save these information into map. + std::lock_guard lock(collectorLock_); + if (destroying_) { + HILOGW("Deposit: Collector thread is destroying"); + return false; + } + // Save thread object and its exit callback. + depositMap_.emplace(threadId, + ThreadExitInfo { + .thread = std::move(thread), + .threadExit = threadExit, + }); + return true; + } + +private: + DEFINE_HILOG_LABEL("ThreadCollector"); + + struct ThreadExitInfo { + std::unique_ptr thread; + ExitFunction threadExit; + }; + + inline void ReclaimAll() + { + std::unique_lock lock(collectorLock_); + // All thread deposited need to stop one by one. + while (!depositMap_.empty()) { + DoReclaimLocked(lock, depositMap_.begin()); + } + } + + void Stop() + { + { + // Stop the collect thread, while destruction of collector. + std::lock_guard lock(collectorLock_); + destroying_ = true; + if (isWaiting_) { + condition_.notify_all(); + } + } + + { + std::lock_guard lock(threadLock_); + if ((thread_) && (thread_->joinable())) { + // Wait utils collect thread finished, if exists. + thread_->join(); + } + needCreateThread_ = false; + } + + ReclaimAll(); + } + + void DoReclaimLocked(std::unique_lock &lock, + std::unordered_map::iterator it, bool needCallExit = true) + { + if (it == depositMap_.end()) { + return; + } + + // Remove thread information from map. + auto threadId = it->first; + auto exitInfo = std::move(it->second); + (void)depositMap_.erase(it); + + // Unlock, because stopping thread maybe spend lot of time, it should be out of the lock. + lock.unlock(); + + size_t hashThreadId = CalculateHashCode(threadId); + HILOGD("DoReclaim: Thread id: %{public}zu", hashThreadId); + if (needCallExit) { + // Call exit callback to stop loop in thread. + exitInfo.threadExit(); + } + // Wait until thread finished. + exitInfo.thread->join(); + HILOGD("DoReclaim: Done, thread id: %{public}zu", hashThreadId); + + // Lock again. + lock.lock(); + } + + void Run() + { + HILOGD("Run: Collector thread is started"); + + std::unique_lock lock(collectorLock_); + while (!destroying_) { + // Reclaim threads in list one by one. + while (!reclaims_.empty()) { + auto threadId = reclaims_.back(); + reclaims_.pop_back(); + DoReclaimLocked(lock, depositMap_.find(threadId), false); + } + + // Maybe stop running while doing reclaim, so check before waiting. + if (destroying_) { + break; + } + + isWaiting_ = true; + condition_.wait(lock); + isWaiting_ = false; + } + + HILOGD("Run: Collector thread is stopped"); + } + + std::mutex collectorLock_; + std::condition_variable condition_; + bool isWaiting_ {false}; + bool destroying_ {false}; + std::vector reclaims_; + std::unordered_map depositMap_; + + std::mutex threadLock_; + // Thread for collector + std::unique_ptr thread_; + bool needCreateThread_ {true}; + + // Avatar of thread collector, used to stop collector at the specified opportunity. + class Avatar { + public: + DISALLOW_COPY_AND_MOVE(Avatar); + + Avatar() = default; + ~Avatar() + { + if (avatarEnabled_) { + GetInstance().avatarDestructed_ = true; + GetInstance().Stop(); + } + } + + inline void Disable() const + { + avatarEnabled_ = false; + } + }; + + // Mark whether avatar is destructed. + volatile bool avatarDestructed_ {false}; + // Mark whether avatar is enabled. + static volatile bool avatarEnabled_; + static Avatar avatar_; +}; + +ThreadCollector::ThreadCollector() : + collectorLock_(), condition_(), reclaims_(), depositMap_(), threadLock_(), thread_(nullptr) +{ + // Thread collector is created, so enable avatar. + avatarEnabled_ = true; +} + +ThreadCollector::~ThreadCollector() +{ + // If avatar is not destructed, stop collector by itself. + if (!avatarDestructed_) { + avatar_.Disable(); + Stop(); + } +} + +class EventRunnerImpl final : public EventInnerRunner { +public: + explicit EventRunnerImpl(const std::shared_ptr &runner) : EventInnerRunner(runner) + { + queue_ = std::make_shared(); + } + + ~EventRunnerImpl() final = default; + DISALLOW_COPY_AND_MOVE(EventRunnerImpl); + + static void ThreadMain(const std::weak_ptr &wp) + { + std::shared_ptr inner = wp.lock(); + if (inner) { + HILOGD("ThreadMain: Start running for thread '%{public}s'", inner->threadName_.c_str()); + + // Call system call to modify thread name. + SystemCallSetThreadName(inner->threadName_); + + // Enter event loop. + inner->Run(); + + HILOGD("ThreadMain: Stopped running for thread '%{public}s'", inner->threadName_.c_str()); + } else { + HILOGW("ThreadMain: EventRunner has been released just after its creation"); + } + + // Reclaim current thread. + ThreadCollector::GetInstance().ReclaimCurrentThread(); + } + + void Run() final + { + // Prepare to start event loop. + queue_->Prepare(); + + // Make sure instance of 'EventRunner' exists. + if (owner_.expired()) { + return; + } + + threadId_ = std::this_thread::get_id(); + + // Save old event runner. + std::weak_ptr oldRunner = currentEventRunner; + // Set current event runner into thread local data. + currentEventRunner = owner_; + + // Start event looper. + for (auto event = queue_->GetEvent(); event; event = queue_->GetEvent()) { + std::shared_ptr handler = event->GetOwner(); + // Make sure owner of the event exists. + if (handler) { + std::shared_ptr logging = logger_; + std::stringstream address; + address << handler.get(); + if (logging != nullptr) { + if (!event->HasTask()) { + logging->Log("Dispatching to handler event id = " + std::to_string(event->GetInnerEventId())); + } else { + logging->Log("Dispatching to handler event task name = " + event->GetTaskName()); + } + } + + handler->DistributeEvent(event); + + if (logging != nullptr) { + logging->Log("Finished to handler(0x" + address.str() + ")"); + } + } + // Release event manually, otherwise event will be released until next event coming. + event.reset(); + } + + // Restore current event runner. + currentEventRunner = oldRunner; + } + + void Stop() final + { + queue_->Finish(); + } + + inline bool Attach(std::unique_ptr &thread) + { + auto exitThread = [queue = queue_]() { queue->Finish(); }; + + return ThreadCollector::GetInstance().Deposit(thread, exitThread); + } + + inline void SetThreadName(const std::string &threadName) + { + static std::atomic idGenerator(1); + + if (threadName.empty()) { + // Generate a default name + threadName_ = "event_runner#"; + threadName_ += std::to_string(idGenerator++); + } else { + threadName_ = threadName; + } + } + +private: + DEFINE_HILOG_LABEL("EventRunnerImpl"); +}; +} // unnamed namespace + +EventInnerRunner::EventInnerRunner(const std::shared_ptr &runner) : + queue_(nullptr), owner_(runner), logger_(nullptr), threadName_(""), threadId_() +{} + +std::shared_ptr EventInnerRunner::GetCurrentEventRunner() +{ + const std::weak_ptr &wp = currentEventRunner; + return wp.lock(); +} + +ThreadLocalData> EventInnerRunner::currentEventRunner; + +namespace { + +volatile bool ThreadCollector::avatarEnabled_ = false; + +/* + * All event runners are relied on 'currentEventRunner', so make sure destruction of 'currentEventRunner' + * should after all event runners finished. All event runners finished in destruction of 'ThreadCollector::Avatar', + * so instance of 'ThreadCollector::Avatar' MUST defined after 'currentEventRunner'. + */ +ThreadCollector::Avatar ThreadCollector::avatar_; + +} // unnamed namespace + +std::shared_ptr EventRunner::mainRunner_; + +std::shared_ptr EventRunner::Create(bool inNewThread) +{ + if (inNewThread) { + return Create(std::string()); + } + + // Constructor of 'EventRunner' is private, could not use 'std::make_shared' to construct it. + std::shared_ptr sp(new EventRunner(false)); + auto innerRunner = std::make_shared(sp); + sp->innerRunner_ = innerRunner; + sp->queue_ = innerRunner->GetEventQueue(); + + return sp; +} + +std::shared_ptr EventRunner::Create(const std::string &threadName) +{ + // Constructor of 'EventRunner' is private, could not use 'std::make_shared' to construct it. + std::shared_ptr sp(new EventRunner(true)); + auto innerRunner = std::make_shared(sp); + sp->innerRunner_ = innerRunner; + sp->queue_ = innerRunner->GetEventQueue(); + + // Start new thread + innerRunner->SetThreadName(threadName); + auto thread = + std::make_unique(EventRunnerImpl::ThreadMain, std::weak_ptr(innerRunner)); + if (!innerRunner->Attach(thread)) { + HILOGW("Create: Failed to attach thread, maybe process is exiting"); + innerRunner->Stop(); + thread->join(); + } + + return sp; +} + +std::shared_ptr EventRunner::Current() +{ + auto runner = EventInnerRunner::GetCurrentEventRunner(); + if (runner) { + return runner; + } + return nullptr; +} + +EventRunner::EventRunner(bool deposit) : deposit_(deposit) +{} + +EventRunner::~EventRunner() +{ + if (deposit_) { + innerRunner_->Stop(); + } +} + +ErrCode EventRunner::Run() +{ + if (deposit_) { + HILOGE("Run: Do not call, if event runner is deposited"); + return EVENT_HANDLER_ERR_RUNNER_NO_PERMIT; + } + + // Avoid more than one thread to start this runner. + if (running_.exchange(true)) { + HILOGW("Run: Already running"); + return EVENT_HANDLER_ERR_RUNNER_ALREADY; + } + + // Entry event loop. + innerRunner_->Run(); + + running_.store(false); + return ERR_OK; +} + +ErrCode EventRunner::Stop() +{ + if (deposit_) { + HILOGE("Stop: Do not call, if event runner is deposited"); + return EVENT_HANDLER_ERR_RUNNER_NO_PERMIT; + } + + if (running_.load()) { + innerRunner_->Stop(); + } else { + HILOGW("Stop: Already stopped"); + } + + return ERR_OK; +} + +void EventRunner::Dump(Dumper &dumper) +{ + if (!IsRunning()) { + dumper.Dump(dumper.GetTag() + " Event runner is not running" + LINE_SEPARATOR); + return; + } + + if (queue_ == nullptr) { + dumper.Dump(dumper.GetTag() + " Queue is nullLINE_SEPARATOR" + LINE_SEPARATOR); + return; + } + + dumper.Dump(dumper.GetTag() + " Event runner (" + "Thread name = " + innerRunner_->GetThreadName() + + ", Thread ID = " + std::to_string(GetThreadId()) + ") is running" + LINE_SEPARATOR); + + queue_->Dump(dumper); +} + +void EventRunner::SetLogger(const std::shared_ptr &logger) +{ + innerRunner_->SetLogger(logger); +} + +std::shared_ptr EventRunner::GetCurrentEventQueue() +{ + auto runner = EventRunner::Current(); + if (!runner) { + return nullptr; + } + return runner->queue_; +} + +uint64_t EventRunner::GetThreadId() +{ + std::thread::id tid = innerRunner_->GetThreadId(); + std::stringstream buf; + buf << tid; + std::string stid = buf.str(); + return std::stoull(stid); +} + +bool EventRunner::IsCurrentRunnerThread() +{ + return std::this_thread::get_id() == innerRunner_->GetThreadId(); +} + +std::shared_ptr EventRunner::GetMainEventRunner() +{ + if (!mainRunner_) { + mainRunner_ = Create(false); + if (!mainRunner_) { + HILOGE("mainRunner_ create fail"); + } + } + + return mainRunner_; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/libs/libeventhandler/src/file_descriptor_listener.cpp b/libs/libeventhandler/src/file_descriptor_listener.cpp new file mode 100644 index 000000000..8be473c92 --- /dev/null +++ b/libs/libeventhandler/src/file_descriptor_listener.cpp @@ -0,0 +1,32 @@ +/* + * 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 "file_descriptor_listener.h" + +namespace OHOS { +namespace AppExecFwk { +void FileDescriptorListener::OnReadable(int32_t) +{} + +void FileDescriptorListener::OnWritable(int32_t) +{} + +void FileDescriptorListener::OnShutdown(int32_t) +{} + +void FileDescriptorListener::OnException(int32_t) +{} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/libs/libeventhandler/src/inner_event.cpp b/libs/libeventhandler/src/inner_event.cpp new file mode 100644 index 000000000..2237701e0 --- /dev/null +++ b/libs/libeventhandler/src/inner_event.cpp @@ -0,0 +1,249 @@ +/* + * 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 "inner_event.h" + +#include +#include +#include + +#include "event_handler_utils.h" +#include "singleton.h" + +DEFINE_HILOG_LABEL("InnerEvent"); + +namespace OHOS { +namespace AppExecFwk { +namespace { +class WaiterImp final : public InnerEvent::Waiter { +public: + WaiterImp(){}; + ~WaiterImp() override{}; + DISALLOW_COPY_AND_MOVE(WaiterImp); + + void Wait() final + { + std::unique_lock lock(mutex_); + while (!finished_) { + ++waitingCount_; + condition_.wait(lock); + --waitingCount_; + } + } + + void Notify() final + { + std::lock_guard lock(mutex_); + finished_ = true; + if (waitingCount_ > 0) { + condition_.notify_all(); + } + } + +private: + std::mutex mutex_; + std::condition_variable condition_; + uint32_t waitingCount_ {0}; + bool finished_ {false}; +}; +} // unnamed namespace + +// Implementation for event pool. +class InnerEventPool : public DelayedRefSingleton { + DECLARE_DELAYED_REF_SINGLETON(InnerEventPool); + +public: + DISALLOW_COPY_AND_MOVE(InnerEventPool); + + InnerEvent::Pointer Get() + { + size_t newPeakUsingCount = 0; + + { + // Check whether pool is empty. + std::lock_guard lock(poolLock_); + ++usingCount_; + if (!events_.empty()) { + auto event = std::move(events_.back()); + events_.pop_back(); + return InnerEvent::Pointer(event.release(), Drop); + } + + // Update peak using events count. + if (usingCount_ >= nextPeakUsingCount_) { + if (UINT32_MAX - nextPeakUsingCount_ > MAX_BUFFER_POOL_SIZE) { + nextPeakUsingCount_ += MAX_BUFFER_POOL_SIZE; + } else { + nextPeakUsingCount_ = UINT32_MAX; + } + + newPeakUsingCount = usingCount_; + } + } + + // Print the new peak using count of inner events + if (newPeakUsingCount > 0) { + HILOGD("Peak using count of inner events is up to %{public}zu", newPeakUsingCount); + } + + // Allocate new memory, while pool is empty. + return InnerEvent::Pointer(new InnerEvent, Drop); + } + +private: + static void Drop(InnerEvent *event) + { + if (event == nullptr) { + return; + } + + auto destructor = [](InnerEvent *event) { + if (event != nullptr) { + delete event; + } + }; + + // Clear content of the event + event->ClearEvent(); + // Put event into event buffer pool + GetInstance().Put(InnerEvent::Pointer(event, destructor)); + } + + void Put(InnerEvent::Pointer &&event) + { + // Check whether pool is full. + std::lock_guard lock(poolLock_); + --usingCount_; + if (events_.size() < MAX_BUFFER_POOL_SIZE) { + events_.push_back(std::move(event)); + } + } + + static const size_t MAX_BUFFER_POOL_SIZE = 64; + + std::mutex poolLock_; + std::vector events_; + + // Used to statistical peak value of count of using inner events. + size_t usingCount_ {0}; + size_t nextPeakUsingCount_ {MAX_BUFFER_POOL_SIZE}; +}; + +InnerEventPool::InnerEventPool() : poolLock_(), events_() +{ + // Reserve enough memory + std::lock_guard lock(poolLock_); + events_.reserve(MAX_BUFFER_POOL_SIZE); +} + +InnerEventPool::~InnerEventPool() +{ + // Release all memory in the poll + std::lock_guard lock(poolLock_); + events_.clear(); +} + +InnerEvent::Pointer InnerEvent::Get() +{ + auto event = InnerEventPool::GetInstance().Get(); + return event; +} + +InnerEvent::Pointer InnerEvent::Get(uint32_t innerEventId, int64_t param) +{ + auto event = InnerEventPool::GetInstance().Get(); + event->innerEventId_ = innerEventId; + event->param_ = param; + return event; +} + +InnerEvent::Pointer InnerEvent::Get(const Callback &callback, const std::string &name) +{ + // Returns nullptr while callback is invalid. + if (!callback) { + HILOGW("Failed to create inner event with an invalid callback"); + return InnerEvent::Pointer(nullptr, nullptr); + } + + auto event = InnerEventPool::GetInstance().Get(); + event->taskCallback_ = callback; + event->taskName_ = name; + return event; +} + +void InnerEvent::ClearEvent() +{ + // Wake up all waiting threads. + if (waiter_) { + waiter_->Notify(); + waiter_.reset(); + } + + if (HasTask()) { + // Clear members for task + taskCallback_ = nullptr; + taskName_.clear(); + } else { + // Clear members for event + if (smartPtrDtor_) { + smartPtrDtor_(smartPtr_); + smartPtrDtor_ = nullptr; + smartPtr_ = nullptr; + smartPtrTypeId_ = 0; + } + } + // Clear owner + owner_.reset(); +} + +void InnerEvent::WarnSmartPtrCastMismatch() +{ + HILOGE("Type of the shared_ptr, weak_ptr or unique_ptr mismatched"); +} + +const std::shared_ptr &InnerEvent::CreateWaiter() +{ + waiter_ = std::make_shared(); + return waiter_; +} + +bool InnerEvent::HasWaiter() const +{ + return (waiter_ != nullptr); +} + +std::string InnerEvent::Dump() +{ + std::string content; + + content.append("Event { "); + if (!owner_.expired()) { + if (HasTask()) { + content.append("task name = " + taskName_); + } else { + content.append("id = " + std::to_string(innerEventId_)); + } + if (param_ != 0) { + content.append(", param = " + std::to_string(param_)); + } + } else { + content = "No handler"; + } + content.append(" }" + LINE_SEPARATOR); + + return content; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/libs/libeventhandler/src/io_waiter.h b/libs/libeventhandler/src/io_waiter.h new file mode 100644 index 000000000..b732f95f3 --- /dev/null +++ b/libs/libeventhandler/src/io_waiter.h @@ -0,0 +1,89 @@ +/* + * 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_LIBS_LIBEVENTHANDLER_SRC_IO_WAITER_H +#define FOUNDATION_APPEXECFWK_LIBS_LIBEVENTHANDLER_SRC_IO_WAITER_H + +#include +#include +#include +#include + +#include "nocopyable.h" + +namespace OHOS { +namespace AppExecFwk { +// Interface of IO waiter +class IoWaiter { +public: + using FileDescriptorEventCallback = std::function; + + IoWaiter() = default; + virtual ~IoWaiter() = default; + DISALLOW_COPY_AND_MOVE(IoWaiter); + + /** + * Wait until IO event coming or timed out. + * + * @param lock An unique lock which must be locked by the current thread. + * @param nanoseconds Nanoseconds for time out, negative value indicate waiting forever. + * @return True if succeeded. + */ + virtual bool WaitFor(std::unique_lock &lock, int64_t nanoseconds) = 0; + + /** + * Unblocks one of the waiting threads. + */ + virtual void NotifyOne() = 0; + + /** + * Unblocks all of the waiting threads. + */ + virtual void NotifyAll() = 0; + + /** + * Check whether this waiter support listening file descriptor. + * + * @return True if supported. + */ + virtual bool SupportListeningFileDescriptor() const = 0; + + /** + * Add file descriptor. + * + * @param fileDescriptor File descriptor which need to listen. + * @param events Events from file descriptor, such as input, output. + * @return True if succeeded. + */ + virtual bool AddFileDescriptor(int32_t fileDescriptor, uint32_t events) = 0; + + /** + * Remove file descriptor. + * + * @param fileDescriptor File descriptor which need to remove. + */ + virtual void RemoveFileDescriptor(int32_t fileDescriptor) = 0; + + /** + * Set callback to handle events from file descriptors, such as readable, writable and so on. + * + * @param callback Callback function to handle events from file descriptors. + */ + virtual void SetFileDescriptorEventCallback(const FileDescriptorEventCallback &callback) = 0; +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // #ifndef FOUNDATION_APPEXECFWK_LIBS_LIBEVENTHANDLER_SRC_IO_WAITER_H diff --git a/libs/libeventhandler/src/native_implement_eventhandler.cpp b/libs/libeventhandler/src/native_implement_eventhandler.cpp new file mode 100644 index 000000000..f95734309 --- /dev/null +++ b/libs/libeventhandler/src/native_implement_eventhandler.cpp @@ -0,0 +1,159 @@ +/* + * 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 "native_implement_eventhandler.h" +#include "event_runner.h" +#include "file_descriptor_listener.h" + +struct FileDescriptorCallbacks { + const FileFDCallback readableCallback_; + const FileFDCallback writableCallback_; + const FileFDCallback shutdownCallback_; + const FileFDCallback exceptionCallback_; +}; + +class NativeFileDescriptorListener : public OHOS::AppExecFwk::FileDescriptorListener { +public: + explicit NativeFileDescriptorListener(const struct FileDescriptorCallbacks *fileDescriptorCallbacks) + { + if (fileDescriptorCallbacks->readableCallback_ != nullptr) { + onReadableCallback_ = fileDescriptorCallbacks->readableCallback_; + } + if (fileDescriptorCallbacks->writableCallback_ != nullptr) { + onWritableCallback_ = fileDescriptorCallbacks->writableCallback_; + } + if (fileDescriptorCallbacks->shutdownCallback_ != nullptr) { + onShutdownCallback_ = fileDescriptorCallbacks->shutdownCallback_; + } + if (fileDescriptorCallbacks->exceptionCallback_ != nullptr) { + onExceptionCallback_ = fileDescriptorCallbacks->exceptionCallback_; + } + } + + ~NativeFileDescriptorListener() + {} + + /** + * Called while file descriptor is readable. + * + * @param fileDescriptor File descriptor which is readable. + */ + void OnReadable(int32_t filedescriptor) + { + if (onReadableCallback_ != nullptr) { + onReadableCallback_(filedescriptor); + } + } + + /** + * Called while file descriptor is writable. + * + * @param fileDescriptor File descriptor which is writable. + */ + void OnWritable(int32_t filedescriptor) + { + if (onWritableCallback_ != nullptr) { + onWritableCallback_(filedescriptor); + } + } + + /** + * Called while shutting down this file descriptor. + * + * @param fileDescriptor File descriptor which is shutting down. + */ + void OnShutdown(int32_t filedescriptor) + { + if (onShutdownCallback_ != nullptr) { + onShutdownCallback_(filedescriptor); + } + } + + /** + * Called while error happened on this file descriptor. + * + * @param fileDescriptor Error happened on this file descriptor. + */ + void OnException(int32_t filedescriptor) + { + if (onExceptionCallback_ != nullptr) { + onExceptionCallback_(filedescriptor); + } + } + + NativeFileDescriptorListener(const NativeFileDescriptorListener &) = delete; + NativeFileDescriptorListener &operator=(const NativeFileDescriptorListener &) = delete; + NativeFileDescriptorListener(NativeFileDescriptorListener &&) = delete; + NativeFileDescriptorListener &operator=(NativeFileDescriptorListener &&) = delete; + +private: + FileFDCallback onReadableCallback_ = nullptr; + FileFDCallback onWritableCallback_ = nullptr; + FileFDCallback onShutdownCallback_ = nullptr; + FileFDCallback onExceptionCallback_ = nullptr; +}; + +EventRunnerNativeImplement::EventRunnerNativeImplement(bool current) +{ + if (current) { + eventRunner_ = EventRunner::Current(); + } else { + eventRunner_ = EventRunner::Create(false); + } +} + +EventRunnerNativeImplement::~EventRunnerNativeImplement() +{ + eventRunner_ = nullptr; +} + +const EventRunnerNativeImplement *EventRunnerNativeImplement::GetEventRunnerNativeObj() +{ + return new EventRunnerNativeImplement(true); +} + +const EventRunnerNativeImplement *EventRunnerNativeImplement::CreateEventRunnerNativeObj() +{ + return new EventRunnerNativeImplement(false); +} + +ErrCode EventRunnerNativeImplement::RunEventRunnerNativeObj() const +{ + if (eventRunner_ != nullptr) { + return eventRunner_->Run(); + } + return OHOS::AppExecFwk::EVENT_HANDLER_ERR_NO_EVENT_RUNNER; +} + +ErrCode EventRunnerNativeImplement::StopEventRunnerNativeObj() const +{ + if (eventRunner_ != nullptr) { + return eventRunner_->Stop(); + } + return OHOS::AppExecFwk::EVENT_HANDLER_ERR_NO_EVENT_RUNNER; +} + +ErrCode EventRunnerNativeImplement::AddFileDescriptorListener( + int32_t fileDescriptor, uint32_t events, const FileDescriptorCallbacks *fdCallbacks) const +{ + auto nativeFileDescriptorListener = std::make_shared(fdCallbacks); + return eventRunner_->GetEventQueue()->AddFileDescriptorListener( + fileDescriptor, events, nativeFileDescriptorListener); +} + +void EventRunnerNativeImplement::RemoveFileDescriptorListener(int32_t fileDescriptor) const +{ + eventRunner_->GetEventQueue()->RemoveFileDescriptorListener(fileDescriptor); +} \ No newline at end of file diff --git a/libs/libeventhandler/src/none_io_waiter.cpp b/libs/libeventhandler/src/none_io_waiter.cpp new file mode 100644 index 000000000..65e911e38 --- /dev/null +++ b/libs/libeventhandler/src/none_io_waiter.cpp @@ -0,0 +1,90 @@ +/* + * 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 "none_io_waiter.h" + +#include + +#include "event_handler_utils.h" + +DEFINE_HILOG_LABEL("NoneIoWaiter"); + +namespace OHOS { +namespace AppExecFwk { +namespace { +const int32_t HOURS_PER_DAY = 24; +const int32_t DAYS_PER_YEAR = 365; +const int32_t HOURS_PER_YEAR = HOURS_PER_DAY * DAYS_PER_YEAR; +} // unnamed namespace + +// Nothing to do, but used to fix a codex warning. +NoneIoWaiter::~NoneIoWaiter() +{} + +bool NoneIoWaiter::WaitFor(std::unique_lock &lock, int64_t nanoseconds) +{ + ++waitingCount_; + if (nanoseconds < 0) { + condition_.wait(lock); + } else { + /* + * Fix a problem in some versions of STL. + * Parameter 'nanoseconds' is too large to cause overflow by adding 'now'. + * So limit it to no more than one year. + */ + static const auto oneYear = std::chrono::hours(HOURS_PER_YEAR); + auto duration = std::chrono::nanoseconds(nanoseconds); + (void)condition_.wait_for(lock, (duration > oneYear) ? oneYear : duration); + } + --waitingCount_; + return true; +} + +void NoneIoWaiter::NotifyOne() +{ + if (waitingCount_ > 0) { + condition_.notify_one(); + } +} + +void NoneIoWaiter::NotifyAll() +{ + if (waitingCount_ > 0) { + condition_.notify_all(); + } +} + +bool NoneIoWaiter::SupportListeningFileDescriptor() const +{ + return false; +} + +bool NoneIoWaiter::AddFileDescriptor(int32_t, uint32_t) +{ + HILOGW("AddFileDescriptor: Function is not supported !!!"); + return false; +} + +void NoneIoWaiter::RemoveFileDescriptor(int32_t) +{ + HILOGW("RemoveFileDescriptor: Function is not supported !!!"); +} + +void NoneIoWaiter::SetFileDescriptorEventCallback(const IoWaiter::FileDescriptorEventCallback &) +{ + HILOGW("SetFileDescriptorEventCallback: Function is not supported !!!"); +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/libs/libeventhandler/src/none_io_waiter.h b/libs/libeventhandler/src/none_io_waiter.h new file mode 100644 index 000000000..b54276a7b --- /dev/null +++ b/libs/libeventhandler/src/none_io_waiter.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_LIBS_LIBEVENTHANDLER_SRC_NONE_IO_WAITER_H +#define FOUNDATION_APPEXECFWK_LIBS_LIBEVENTHANDLER_SRC_NONE_IO_WAITER_H + +#include +#include + +#include "io_waiter.h" +#include "nocopyable.h" + +namespace OHOS { +namespace AppExecFwk { +// Io waiter which does not support listening file descriptor. +class NoneIoWaiter final : public IoWaiter { +public: + NoneIoWaiter() = default; + ~NoneIoWaiter() final; + DISALLOW_COPY_AND_MOVE(NoneIoWaiter); + + bool WaitFor(std::unique_lock &lock, int64_t nanoseconds) final; + + void NotifyOne() final; + void NotifyAll() final; + + bool SupportListeningFileDescriptor() const final; + + bool AddFileDescriptor(int32_t fileDescriptor, uint32_t events) final; + void RemoveFileDescriptor(int32_t fileDescriptor) final; + + void SetFileDescriptorEventCallback(const FileDescriptorEventCallback &callback) final; + +private: + std::condition_variable condition_; + uint32_t waitingCount_{0}; +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // #ifndef FOUNDATION_APPEXECFWK_LIBS_LIBEVENTHANDLER_SRC_NONE_IO_WAITER_H diff --git a/libs/libeventhandler/src/thread_local_data.h b/libs/libeventhandler/src/thread_local_data.h new file mode 100644 index 000000000..1fd69b8d1 --- /dev/null +++ b/libs/libeventhandler/src/thread_local_data.h @@ -0,0 +1,93 @@ +/* + * 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_LIBS_LIBEVENTHANDLER_SRC_THREAD_LOCAL_DATA_H +#define FOUNDATION_APPEXECFWK_LIBS_LIBEVENTHANDLER_SRC_THREAD_LOCAL_DATA_H + +#include +#include +#include + +#include "nocopyable.h" + +namespace OHOS { +namespace AppExecFwk { +/* + * Tool class, used to save thread local data. + */ +template +class ThreadLocalData { +public: + ThreadLocalData() = default; + ~ThreadLocalData() = default; + DISALLOW_COPY_AND_MOVE(ThreadLocalData); + + /* + * Override type conversion method. + */ + inline operator T() const + { + return Current(); + } + + /* + * Override operator equal to save data. + */ + inline const ThreadLocalData &operator=(const T &data) + { + Save(data); + return *this; + } + + /* + * Override operator equal to nullptr, which can used to discard the saved data. + */ + inline const ThreadLocalData &operator=(std::nullptr_t) + { + Discard(); + return *this; + } + +private: + inline T Current() const + { + std::lock_guard lock(mapLock_); + auto it = dataMap_.find(std::this_thread::get_id()); + if (it == dataMap_.end()) { + return T(); + } else { + return it->second; + } + } + + inline void Save(const T &data) + { + std::lock_guard lock(mapLock_); + dataMap_[std::this_thread::get_id()] = data; + } + + inline void Discard() + { + std::lock_guard lock(mapLock_); + (void)dataMap_.erase(std::this_thread::get_id()); + } + + mutable std::mutex mapLock_; + std::unordered_map dataMap_; +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // #ifndef FOUNDATION_APPEXECFWK_LIBS_LIBEVENTHANDLER_SRC_THREAD_LOCAL_DATA_H diff --git a/libs/libeventhandler/test/BUILD.gn b/libs/libeventhandler/test/BUILD.gn new file mode 100644 index 000000000..fd01bf7a7 --- /dev/null +++ b/libs/libeventhandler/test/BUILD.gn @@ -0,0 +1,77 @@ +# 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") +import( + "//foundation/appexecfwk/standard/libs/libeventhandler/lib_event_handler_sources.gni") + +config("libeventhandler_test_private_config") { + defines = event_handler_log_domain_defines + + configs = [ "${libs_path}/libeventhandler:libeventhandler_config" ] +} + +module_output_path = "appexecfwk_standard/libeventhandler" + +ohos_unittest("LibEventHandlerEventQueueTest") { + module_out_path = module_output_path + + sources = lib_event_handler_sources + + sources += [ "unittest/lib_event_handler_event_queue_test.cpp" ] + + configs = [ ":libeventhandler_test_private_config" ] + + deps = [ "//third_party/googletest:gtest_main" ] + + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] +} + +ohos_unittest("LibEventHandlerEventTest") { + module_out_path = module_output_path + + sources = lib_event_handler_sources + + sources += [ "unittest/lib_event_handler_event_test.cpp" ] + + configs = [ ":libeventhandler_test_private_config" ] + + deps = [ "//third_party/googletest:gtest_main" ] + + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] +} + +ohos_unittest("LibEventHandlerEventRunnerTest") { + module_out_path = module_output_path + + sources = lib_event_handler_sources + + sources += [ "unittest/lib_event_handler_event_runner_test.cpp" ] + + configs = [ ":libeventhandler_test_private_config" ] + + deps = [ "//third_party/googletest:gtest_main" ] + + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] +} + +group("unittest") { + testonly = true + + deps = [ + ":LibEventHandlerEventQueueTest", + ":LibEventHandlerEventRunnerTest", + ":LibEventHandlerEventTest", + ] +} diff --git a/libs/libeventhandler/test/unittest/lib_event_handler_event_queue_test.cpp b/libs/libeventhandler/test/unittest/lib_event_handler_event_queue_test.cpp new file mode 100644 index 000000000..e6fa28305 --- /dev/null +++ b/libs/libeventhandler/test/unittest/lib_event_handler_event_queue_test.cpp @@ -0,0 +1,1712 @@ +/* + * 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 "event_handler.h" +#include "event_queue.h" +#include "event_runner.h" +#include "inner_event.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; + +namespace { +const size_t MAX_PRIORITY_NUM = 4; +const size_t MAX_HIGH_PRIORITY_COUNT = 5; +const uint32_t NUM = 2; +const uint32_t HIGH_PRIORITY_COUNT = 12; +const uint32_t LOW_PRIORITY_COUNT = 2; +const uint32_t IMMEDIATE_PRIORITY_COUNT = 72; +const int64_t DELAY_TIME = 100; +const int64_t REMOVE_DELAY_TIME = 10; +const int64_t HAS_DELAY_TIME = 10; +const int64_t REMOVE_WAIT_TIME = 20000; +const uint32_t REMOVE_EVENT_ID = 0; +const uint32_t HAS_EVENT_ID = 100; +const int64_t HAS_EVENT_PARAM = 1000; +const uint32_t INSERT_DELAY = 10; +bool isDump = false; + +std::atomic eventRan(false); +} // namespace + +class DumpTest : public Dumper { +public: + /** + * Processes the content of a specified string. + * @param message the content of a specified string. + */ + void Dump(const std::string &message) + { + isDump = true; + GTEST_LOG_(INFO) << message; + } + + /** + * Obtains the tag information. + * which is a prefix added to each string before the string content is processed. + * @return the tag information. + */ + std::string GetTag() + { + return "DumpTest"; + } +}; + +/** + * Init FileDescriptor. + * + * @param fds[] pipe need. + * @return Returns fileDescriptor we get. + */ +static int32_t InitFileDescriptor(int32_t fds[]) +{ + auto result = pipe(fds); + EXPECT_GE(result, 0); + + int32_t fileDescriptor = fds[0]; + return fileDescriptor; +} + +/** + * get event from queue and compare. + * + * @param eventId of the event we want to get. + * @param queue we get event from this queue. + */ +static void GetEventAndCompare(uint32_t eventId, EventQueue &queue) +{ + auto event = queue.GetEvent(); + EXPECT_NE(nullptr, event); + if (event != nullptr) { + auto id = event->GetInnerEventId(); + EXPECT_EQ(eventId, id); + } +} + +/** + * set event handler time delay. + * + * @param delayTime of the event handle time. + */ +static void DelayTest(uint8_t delayTime) +{ + const uint8_t longDelta = 20; + const uint8_t shortDelta = 5; + uint32_t eventId = 0; + uint8_t maxDelta = shortDelta; + if (delayTime > 0) { + maxDelta = longDelta; + } + + EventQueue queue; + queue.Prepare(); + auto event = InnerEvent::Get(eventId); + auto now = InnerEvent::Clock::now(); + // delay event handle time delayTime ms + auto handleTime = now + std::chrono::milliseconds(static_cast(delayTime)); + event->SetSendTime(now); + event->SetHandleTime(handleTime); + queue.Insert(event); + event = queue.GetEvent(); + // block until get event from queue after delay time + now = InnerEvent::Clock::now(); + EXPECT_GE(now, handleTime); + // check if delay time is within acceptable error + auto errorTime = handleTime + std::chrono::milliseconds(static_cast(maxDelta)); + EXPECT_LE(now, errorTime); + EXPECT_NE(event, nullptr); + if (event != nullptr) { + auto id = event->GetInnerEventId(); + EXPECT_EQ(eventId, id); + } +} + +/** + * Insert event and get event from queue. + * + * @param priorities[] prioritiesof event. + * @param priorityCount count of event we insert. + */ +static void InsertPriorityTest(const EventQueue::Priority priorities[], size_t priorityCount) +{ + std::list eventIds; + auto now = InnerEvent::Clock::now(); + EventQueue queue; + queue.Prepare(); + uint32_t eventId = 0; + + // insert event into queue from IDLE priority to IMMEDIATE priority + for (size_t i = 0; i < priorityCount; ++i) { + eventIds.push_back(eventId); + auto event = InnerEvent::Get(eventId); + event->SetSendTime(now); + event->SetHandleTime(now); + queue.Insert(event, priorities[i]); + ++eventId; + } + + // get event from queue and check eventId + for (size_t i = 0; i < priorityCount; ++i) { + auto event = queue.GetEvent(); + EXPECT_NE(nullptr, event); + if (event == nullptr) { + break; + } + + if (priorities[0] == EventQueue::Priority::IDLE) { + auto storeId = eventIds.back(); + auto id = event->GetInnerEventId(); + EXPECT_EQ(storeId, id); + eventIds.pop_back(); + } else { + auto storeId = eventIds.front(); + auto id = event->GetInnerEventId(); + EXPECT_EQ(storeId, id); + eventIds.pop_front(); + } + } +} + +/** + * Break event queue. + * + * @param queue we get break. + * @param eventId eventId of event we insert. + */ +static void BreakQueueTest(EventQueue &queue, uint32_t eventId) +{ + auto event = queue.GetEvent(); + EXPECT_NE(nullptr, event); + if (event != nullptr) { + auto id = event->GetInnerEventId(); + EXPECT_EQ(eventId, id); + queue.Finish(); + queue.Insert(event); + event = queue.GetEvent(); + EXPECT_EQ(nullptr, event); + } +} + +/** + * Insert event into queue and get event. + * + * @param queue we get event from this queue. + * @param event event we insert into queue. + */ +static void InsertAndGet(EventQueue &queue, InnerEvent::Pointer &event) +{ + // insert event before prepare queue + queue.Insert(event); + event = queue.GetEvent(); + EXPECT_EQ(nullptr, event); + if (event != nullptr) { + // If event is not nullptr, the queue must be empty, so need to insert it again. + queue.Insert(event); + } +} + +/** + * Insert event and get event from queue. + * + * @param queue we insert event into this queue. + * @param length length of events. + */ +static void InsertPriorityEvent(EventQueue &queue, size_t length) +{ + // insert two low priority events + for (uint32_t eventId = 0; eventId < NUM; eventId++) { + auto event = InnerEvent::Get(eventId); + auto now = InnerEvent::Clock::now(); + event->SetSendTime(now); + event->SetHandleTime(now); + queue.Insert(event, EventQueue::Priority::LOW); + } + + // avoid time accuracy problem + usleep(INSERT_DELAY); + + // insert MAX_HIGH_PRIORITY_COUNT high priority events + for (uint32_t eventId = NUM; eventId < NUM * length + NUM; eventId++) { + auto event = InnerEvent::Get(eventId); + auto now = InnerEvent::Clock::now(); + event->SetSendTime(now); + event->SetHandleTime(now); + queue.Insert(event, EventQueue::Priority::HIGH); + } +} + +/** + * Insert all priority event and get event from queue. + * + * @param queue we insert event into this queue. + */ +static void InsertAllPriorityEvent(EventQueue &queue) +{ + // insert low priority events + for (uint32_t eventId = 0; eventId < LOW_PRIORITY_COUNT; eventId++) { + auto event = InnerEvent::Get(eventId); + auto now = InnerEvent::Clock::now(); + event->SetSendTime(now); + event->SetHandleTime(now); + queue.Insert(event, EventQueue::Priority::LOW); + } + + // avoid time accuracy problem + usleep(INSERT_DELAY); + + // insert high priority events + for (uint32_t eventId = LOW_PRIORITY_COUNT; eventId < HIGH_PRIORITY_COUNT; eventId++) { + auto event = InnerEvent::Get(eventId); + auto now = InnerEvent::Clock::now(); + event->SetSendTime(now); + event->SetHandleTime(now); + queue.Insert(event, EventQueue::Priority::HIGH); + } + + // avoid time accuracy problem + usleep(INSERT_DELAY); + + // insert immediate priority events + for (uint32_t eventId = HIGH_PRIORITY_COUNT; eventId < IMMEDIATE_PRIORITY_COUNT; eventId++) { + auto event = InnerEvent::Get(eventId); + auto now = InnerEvent::Clock::now(); + event->SetSendTime(now); + event->SetHandleTime(now); + queue.Insert(event, EventQueue::Priority::IMMEDIATE); + } +} + +class LibEventHandlerEventQueueTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void LibEventHandlerEventQueueTest::SetUpTestCase(void) +{} + +void LibEventHandlerEventQueueTest::TearDownTestCase(void) +{} + +void LibEventHandlerEventQueueTest::SetUp(void) +{ + /** + * @tc.setup: reset the eventRan value. + */ + eventRan.store(false); +} + +void LibEventHandlerEventQueueTest::TearDown(void) +{} + +class MyEventHandler : public EventHandler { +public: + explicit MyEventHandler(const std::shared_ptr &runner) : EventHandler(runner) + {} + ~MyEventHandler() + {} + + void ProcessEvent(const InnerEvent::Pointer &) override + { + eventRan.store(true); + } + + MyEventHandler(const MyEventHandler &) = delete; + MyEventHandler &operator=(const MyEventHandler &) = delete; + MyEventHandler(MyEventHandler &&) = delete; + MyEventHandler &operator=(MyEventHandler &&) = delete; +}; + +class MyFileDescriptorListener : public FileDescriptorListener { +public: + MyFileDescriptorListener() + {} + ~MyFileDescriptorListener() + {} + + /* @param int32_t fileDescriptor */ + void OnReadable(int32_t) + {} + + /* @param int32_t fileDescriptor */ + void OnWritable(int32_t) + {} + + /* @param int32_t fileDescriptor */ + void OnException(int32_t) + {} + + MyFileDescriptorListener(const MyFileDescriptorListener &) = delete; + MyFileDescriptorListener &operator=(const MyFileDescriptorListener &) = delete; + MyFileDescriptorListener(MyFileDescriptorListener &&) = delete; + MyFileDescriptorListener &operator=(MyFileDescriptorListener &&) = delete; +}; + +/* + * @tc.name: WakeAndBreak001 + * @tc.desc: check events inserted in queue when Prepare() and + * Finish() are called in right order + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, WakeAndBreak001, TestSize.Level1) +{ + /** + * @tc.setup: get event and queue. + */ + EventQueue queue; + uint32_t eventId = 0; + auto event = InnerEvent::Get(eventId); + + /** + * @tc.steps: step1. prepare queue and inserted in queue when Prepare() and Finish() are called in right order. + * @tc.expected: step1. event and event id is valid when Prepare() and Finish() are called in right order. + */ + queue.Prepare(); + queue.Insert(event); + BreakQueueTest(queue, eventId); +} + +/* + * @tc.name: WakeAndBreak002 + * @tc.desc: check events inserted in queue when queue is prepared + * and broken in wrong order + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, WakeAndBreak002, TestSize.Level1) +{ + /** + * @tc.setup: get event and queue. + */ + EventQueue queue; + uint32_t eventId = 0; + auto event = InnerEvent::Get(eventId); + + /** + * @tc.steps: step1. prepare queue and inserted in queue when Prepare() and Finish() are called in wrong order. + * @tc.expected: step1. event and event id is invalid when Prepare() and Finish() are called in wrong order. + */ + InsertAndGet(queue, event); + queue.Prepare(); + BreakQueueTest(queue, eventId); +} + +/* + * @tc.name: WakeAndBreak003 + * @tc.desc: check events inserted in queue when queue is broken + * and prepared in wrong order + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, WakeAndBreak003, TestSize.Level1) +{ + /** + * @tc.setup: get event and queue. + */ + EventQueue queue; + uint32_t eventId = 0; + auto event = InnerEvent::Get(eventId); + + InsertAndGet(queue, event); + + /** + * @tc.steps: step1. get and check event Finish() is called in wrong order. + * @tc.expected: step1. event is null. + */ + queue.Finish(); + event = queue.GetEvent(); + EXPECT_EQ(nullptr, event); + if (event != nullptr) { + // If event is not nullptr, the queue must be empty, so need to insert it again. + queue.Insert(event); + } + + /** + * @tc.steps: step2. prepare queue and get event from queue when Prepare() is called in right order. + * @tc.expected: step2. event and event id is invalid . + */ + queue.Prepare(); + GetEventAndCompare(eventId, queue); +} + +/* + * @tc.name: WakeAndBreak004 + * @tc.desc: check events inserted in queue and get event by function GetExpiredEvent + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, WakeAndBreak004, TestSize.Level1) +{ + /** + * @tc.setup: get event and queue. + */ + EventQueue myQueue; + uint32_t eventId = 0; + auto event = InnerEvent::Get(eventId); + InsertAndGet(myQueue, event); + + /** + * @tc.steps: step1. get and check event Finish() is called in wrong order. + * @tc.expected: step1. event is null. + */ + myQueue.Finish(); + event = myQueue.GetEvent(); + EXPECT_EQ(nullptr, event); + if (event != nullptr) { + // If event is not nullptr, the queue must be empty, so need to insert it again. + myQueue.Insert(event); + } + + /** + * @tc.steps: step2. prepare queue and get event from queue when Prepare() is called in right order. + * @tc.expected: step2. event and event id is invalid . + */ + myQueue.Prepare(); + InnerEvent::TimePoint nextWakeUpTime = InnerEvent::TimePoint::max(); + auto resultEvent = myQueue.GetExpiredEvent(nextWakeUpTime); + EXPECT_NE(nullptr, resultEvent); + EXPECT_EQ(eventId, resultEvent->GetInnerEventId()); +} + +/* + * @tc.name: InsertEvent001 + * @tc.desc: insert() event of different priorities into Queue, + * from IDLE to IMMEDIATE. + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, InsertEvent001, TestSize.Level1) +{ + /** + * @tc.setup: init priority array, insert event with the order int the array. + */ + const EventQueue::Priority priorities[MAX_PRIORITY_NUM] = { + EventQueue::Priority::IDLE, + EventQueue::Priority::LOW, + EventQueue::Priority::HIGH, + EventQueue::Priority::IMMEDIATE, + }; + + /** + * @tc.steps: step1. insert and get event, check whether the order of the event + * we get from queue is the same as we expect. + * @tc.expected: step1. the order is the same as we expect. + */ + InsertPriorityTest(priorities, MAX_PRIORITY_NUM); +} + +/* + * @tc.name: InsertEvent002 + * @tc.desc: insert() event of different priorities into Queue, + * from IMMEDIATE to IDLE + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, InsertEvent002, TestSize.Level1) +{ + /** + * @tc.setup: init priority array, insert event with the order int the array. + */ + const EventQueue::Priority priorities[MAX_PRIORITY_NUM] = { + EventQueue::Priority::IMMEDIATE, + EventQueue::Priority::HIGH, + EventQueue::Priority::LOW, + EventQueue::Priority::IDLE, + }; + + /** + * @tc.steps: step1. insert and get event, check whether the order of the event + * we get from queue is the same as we expect. + * @tc.expected: step1. the order is the same as we expect. + */ + InsertPriorityTest(priorities, MAX_PRIORITY_NUM); +} + +/* + * @tc.name: InsertEvent003 + * @tc.desc: insert nullptr event and normal event into queue, + * then get event from queue + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, InsertEvent003, TestSize.Level1) +{ + /** + * @tc.setup: prepare queue. and insert event into queue, insert event with the order int the array. + */ + uint32_t eventId = 0; + EventQueue queue; + queue.Prepare(); + + /** + * @tc.steps: step1. insert nullptr event and insert normal event into queue, and get event from queue, check + * whether the event we get from queue is valid as we expect. + * @tc.expected: step1. the event we get after we insert normal event into queue is valid. + */ + auto event = InnerEvent::Pointer(nullptr, nullptr); + queue.Insert(event); + event = InnerEvent::Get(eventId); + queue.Insert(event); + GetEventAndCompare(eventId, queue); +} + +/* + * @tc.name: InsertEvent004 + * @tc.desc: avoid starvation in queue when insert event of + * different priorities into Queue + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, InsertEvent004, TestSize.Level1) +{ + /** + * @tc.setup: prepare queue. + */ + const uint32_t num = 3; + EventQueue queue; + queue.Prepare(); + + /** + * @tc.steps: step1. first insert MAX_HIGH_PRIORITY_COUNT high priority events, then insert two low priority events. + */ + for (uint32_t eventId = 0; eventId < MAX_HIGH_PRIORITY_COUNT + 1; eventId++) { + auto event = InnerEvent::Get(eventId); + auto now = InnerEvent::Clock::now(); + event->SetSendTime(now); + event->SetHandleTime(now); + queue.Insert(event, EventQueue::Priority::HIGH); + } + + for (uint32_t eventId = MAX_HIGH_PRIORITY_COUNT + 1; eventId < MAX_HIGH_PRIORITY_COUNT + num; eventId++) { + auto event = InnerEvent::Get(eventId); + auto now = InnerEvent::Clock::now(); + event->SetSendTime(now); + event->SetHandleTime(now); + queue.Insert(event, EventQueue::Priority::LOW); + } + + /** + * @tc.steps: step2. get event from queue one by one, and check whether the event id we get from queue is the + * same as we expect. + * @tc.expected: step2. event id we get from queue is the same as we expect. + */ + for (uint32_t eventId = 0; eventId < MAX_HIGH_PRIORITY_COUNT + num; eventId++) { + GetEventAndCompare(eventId, queue); + } +} + +/* + * @tc.name: InsertEvent005 + * @tc.desc: avoid starvation in queue when insert event of different priorities into Queue. + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, InsertEvent005, TestSize.Level1) +{ + /** + * @tc.setup: prepare queue. + */ + EventQueue queue; + queue.Prepare(); + + /** + * @tc.steps: step1. first insert two low priority events, insert MAX_HIGH_PRIORITY_COUNT high priority events. + */ + InsertPriorityEvent(queue, MAX_HIGH_PRIORITY_COUNT); + + /** + * @tc.steps: step2. get MAX_HIGH_PRIORITY_COUNT events from queue, and compare the event id. + * @tc.expected: step2. event we get is high priority events. + */ + for (uint32_t eventId = 2; eventId < MAX_HIGH_PRIORITY_COUNT + NUM; eventId++) { + GetEventAndCompare(eventId, queue); + } + + /** + * @tc.steps: step3. get one event from queue, and compare the event id . + * @tc.expected: step3. event we get is low priority events. + */ + uint32_t lowEventId = 0; + GetEventAndCompare(lowEventId, queue); + + /** + * @tc.steps: step4. get MAX_HIGH_PRIORITY_COUNT events from queue, and compare the event id . + * @tc.expected: step4. event we get is high priority events. + */ + for (uint32_t eventId = MAX_HIGH_PRIORITY_COUNT + NUM; eventId < NUM * MAX_HIGH_PRIORITY_COUNT + NUM; eventId++) { + GetEventAndCompare(eventId, queue); + } + + /** + * @tc.steps: step5. get one event from queue, and compare the event id . + * @tc.expected: step5. event we get is low priority events. + */ + lowEventId = 1; + GetEventAndCompare(lowEventId, queue); +} + +/* + * @tc.name: InsertEvent006 + * @tc.desc: avoid starvation in queue when insert event of different priorities into queue. + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, InsertEvent006, TestSize.Level1) +{ + /** + * @tc.setup: prepare queue. + */ + const uint32_t count = 5; + const uint32_t highEventCount = 6; + EventQueue queue; + queue.Prepare(); + + /** + * @tc.steps: step1. insert events from low priority to immediate priority into queue. + */ + InsertAllPriorityEvent(queue); + + uint32_t highCount = 1; + uint32_t highEventId = 0; + uint32_t lowCount = 0; + uint32_t immediateCount = 1; + + /** + * @tc.steps: step2. get events from queue, and compare the event id . + * @tc.expected: step2. first we get five immediate priority events , then get one high priority event, every five + * high priority events, we will get one low priority event. + */ + for (uint32_t eventId = 0; eventId < IMMEDIATE_PRIORITY_COUNT - HIGH_PRIORITY_COUNT; eventId++) { + if (immediateCount % count == 0) { + GetEventAndCompare(HIGH_PRIORITY_COUNT + eventId, queue); + immediateCount++; + if (highCount % highEventCount == 0) { + GetEventAndCompare(lowCount, queue); + lowCount++; + highCount++; + } else { + GetEventAndCompare(LOW_PRIORITY_COUNT + highEventId, queue); + highCount++; + highEventId++; + } + } else { + GetEventAndCompare(HIGH_PRIORITY_COUNT + eventId, queue); + immediateCount++; + } + } +} + +/* + * @tc.name: InsertEvent007 + * @tc.desc: delay event handle time, get event after delaytime + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, InsertEvent007, TestSize.Level1) +{ + const uint8_t delayTime = 100; + /** + * @tc.steps: step1. insert event into queue and set handle time delay 100ms from now, then get event from queue. + * @tc.expected: step1. the delay time we get event from queue is about 100ms with tolerable error. + */ + DelayTest(delayTime); +} + +/* + * @tc.name: InsertEvent008 + * @tc.desc: delayTime = 0, send event and get event from queue + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, InsertEvent008, TestSize.Level1) +{ + const uint8_t delayTime = 0; + /** + * @tc.steps: step1. insert event into queue and set handle time delay 0ms from now, then get event from queue. + * @tc.expected: step1. the delay time we get event from queue is about 0ms with tolerable error. + */ + DelayTest(delayTime); +} + +/* + * @tc.name: RemoveEvent001 + * @tc.desc: remove all the events which belong to one handler + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, RemoveEvent001, TestSize.Level1) +{ + /** + * @tc.setup: init handler and runner. + */ + auto runner = EventRunner::Create(true); + auto handler = std::make_shared(runner); + std::atomic taskCalled(false); + auto f = [&taskCalled]() { taskCalled.store(true); }; + + /** + * @tc.steps: step1. post a task with delay time, then remove this task ,check whether the task is executed + * after delay time passed. + * @tc.expected: step1. the task is not executed after delay time. + */ + if (handler->PostTask(f, REMOVE_DELAY_TIME, EventQueue::Priority::LOW)) { + handler->RemoveAllEvents(); + usleep(REMOVE_WAIT_TIME); + auto called = taskCalled.load(); + EXPECT_FALSE(called); + } +} + +/* + * @tc.name: RemoveEvent002 + * @tc.desc: remove all the events which belong to one handler with same id + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, RemoveEvent002, TestSize.Level1) +{ + /** + * @tc.setup: init handler and runner. + */ + auto runner = EventRunner::Create(true); + auto handler = std::make_shared(runner); + auto event = InnerEvent::Get(REMOVE_EVENT_ID); + + /** + * @tc.steps: step1. send an event with delay time, then remove this event with event id, + * then check whether the task is executed after delay time. + * @tc.expected: step1. the task is not executed after delay time. + */ + handler->SendEvent(event, REMOVE_DELAY_TIME, EventQueue::Priority::LOW); + handler->RemoveEvent(REMOVE_EVENT_ID); + usleep(REMOVE_WAIT_TIME); + auto ran = eventRan.load(); + EXPECT_FALSE(ran); +} + +/* + * @tc.name: RemoveEvent003 + * @tc.desc: remove all the events which belong to one handler with same id and param + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, RemoveEvent003, TestSize.Level1) +{ + /** + * @tc.setup: init handler and runner. + */ + int64_t eventParam = 0; + auto runner = EventRunner::Create(true); + auto handler = std::make_shared(runner); + auto event = InnerEvent::Get(REMOVE_EVENT_ID, eventParam); + + /** + * @tc.steps: step1. send an event with delay time, then remove this event with event id and param, + * then check whether the task is executed after delay time. + * @tc.expected: step1. the task is not executed after delay time. + */ + handler->SendEvent(event, REMOVE_DELAY_TIME, EventQueue::Priority::LOW); + handler->RemoveEvent(REMOVE_EVENT_ID, eventParam); + usleep(REMOVE_WAIT_TIME); + auto ran = eventRan.load(); + EXPECT_FALSE(ran); +} + +/* + * @tc.name: RemoveEvent004 + * @tc.desc: remove events with task from queue + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, RemoveEvent004, TestSize.Level1) +{ + /** + * @tc.setup: init handler and runner, get event with callback and name. + */ + int64_t delayTime = 5; + int64_t delayWaitTime = 10000; + std::string taskName("taskName"); + std::atomic taskCalled(false); + auto f = [&taskCalled]() { taskCalled.store(true); }; + auto runner = EventRunner::Create(true); + auto handler = std::make_shared(runner); + auto event = InnerEvent::Get(f, taskName); + + /** + * @tc.steps: step1. send an event with delay time, then remove this event with taskname, + * then check whether the task is executed after delay time. + * @tc.expected: step1. the task is not executed after delay time. + */ + handler->SendEvent(event, delayTime, EventQueue::Priority::LOW); + handler->RemoveTask(taskName); + usleep(delayWaitTime); + auto called = taskCalled.load(); + EXPECT_FALSE(called); +} + +/* + * @tc.name: NotifyQueue001 + * @tc.desc: wake up the queue which is blocked when we need to execute a task + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, NotifyQueue001, TestSize.Level1) +{ + /** + * @tc.setup: init handler and runner. + */ + std::atomic taskCalled(false); + auto runner = EventRunner::Create(false); + auto handler = std::make_shared(runner); + + /** + * @tc.steps: step1. post a delay task to block handler thread, then new a thread to post a task to wake up the + * blocked handler. + * @tc.expected: step1. the task is executed as expect. + */ + auto mainTask = [&taskCalled, &runner]() { + taskCalled.store(false); + runner->Stop(); + }; + handler->PostTask(mainTask, DELAY_TIME); + auto f = [&taskCalled, &handler]() { + usleep(10000); + auto task = [&taskCalled]() { taskCalled.store(true); }; + handler->PostTask(task); + usleep(10000); + auto called = taskCalled.load(); + EXPECT_TRUE(called); + }; + std::thread newThread(f); + newThread.detach(); + runner->Run(); + auto called = taskCalled.load(); + EXPECT_FALSE(called); +} + +/* + * @tc.name: NotifyQueue002 + * @tc.desc: add FileDescriptor and wake up the queue with epoll which is blocked when we need to execute a task + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, NotifyQueue002, TestSize.Level1) +{ + /** + * @tc.setup: init handler and runner. + */ + std::atomic taskCalled(false); + auto runner = EventRunner::Create(false); + auto handler = std::make_shared(runner); + + /** + * @tc.steps: step1. add file descripter listener to handler, handler will use epoll to wake up block thread. + */ + int32_t fds[] = {-1, -1}; + int32_t fileDescriptor = InitFileDescriptor(fds); + uint32_t event = 1; + + auto fileDescriptorListener = std::make_shared(); + handler->AddFileDescriptorListener(fileDescriptor, event, fileDescriptorListener); + + /** + * @tc.steps: step2. post a delay task to block handler thread, then new a thread to post a task to wake up the + * blocked handler. + * @tc.expected: step2. the task is executed as expect. + */ + auto mainThreadTask = [&taskCalled, &runner]() { + taskCalled.store(false); + runner->Stop(); + }; + handler->PostTask(mainThreadTask, DELAY_TIME); + auto newThreadTask = [&taskCalled, &handler]() { + usleep(10000); + auto tempTask = [&taskCalled]() { taskCalled.store(true); }; + handler->PostTask(tempTask); + usleep(10000); + auto called = taskCalled.load(); + EXPECT_TRUE(called); + }; + std::thread newThread(newThreadTask); + newThread.detach(); + runner->Run(); + auto called = taskCalled.load(); + EXPECT_FALSE(called); + + /** + * @tc.steps: step3. remove file descripter listener and close pipe. + */ + handler->RemoveFileDescriptorListener(fileDescriptor); + close(fds[0]); + close(fds[1]); +} + +/* + * @tc.name: NotifyQueue003 + * @tc.desc: wake up the queue with epoll which is blocked when we need to execute a task + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, NotifyQueue003, TestSize.Level1) +{ + /** + * @tc.setup: init handler and runner. + */ + std::atomic taskCalled(false); + auto runner = EventRunner::Create(false); + auto handler = std::make_shared(runner); + auto fileDescriptorListener = std::make_shared(); + auto called = taskCalled.load(); + auto main = [&taskCalled, &runner]() { + taskCalled.store(false); + runner->Stop(); + }; + + /** + * @tc.steps: step1. post delay task to block handler. + */ + handler->PostTask(main, DELAY_TIME); + int32_t fds[] = {-1, -1}; + int32_t fileDescriptor = InitFileDescriptor(fds); + uint32_t event = 1; + + /** + * @tc.steps: step2. new a thread to post a delay task to add file descriptor listener to handler, + * then post a new task. + * @tc.expected: step2. all the task is executed as expect. + */ + auto newTask = [&handler, &fileDescriptor, &event, &fileDescriptorListener, &taskCalled]() { + usleep(10000); + handler->AddFileDescriptorListener(fileDescriptor, event, fileDescriptorListener); + usleep(10000); + auto newCalled = taskCalled.load(); + EXPECT_FALSE(newCalled); + auto innerTask = [&taskCalled]() { taskCalled.store(true); }; + handler->PostTask(innerTask); + usleep(10000); + newCalled = taskCalled.load(); + EXPECT_TRUE(newCalled); + }; + std::thread newThread(newTask); + newThread.detach(); + runner->Run(); + called = taskCalled.load(); + EXPECT_FALSE(called); + + /** + * @tc.steps: step3. remove file descripter listener and close pipe. + */ + handler->RemoveFileDescriptorListener(fileDescriptor); + close(fds[0]); + close(fds[1]); +} + +/* + * @tc.name: RemoveOrphan001 + * @tc.desc: Remove event without owner, and check remove result + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, RemoveOrphan001, TestSize.Level1) +{ + /** + * @tc.steps: step1. init orphan handler and post a task. + */ + std::atomic orphanTaskCalled(false); + std::atomic commonTaskCalled(false); + auto runner = EventRunner::Create(false); + auto orphanHandler = std::make_shared(runner); + auto g = [&orphanTaskCalled]() { orphanTaskCalled.store(true); }; + orphanHandler->PostTask(g); + + /** + * @tc.steps: step2. init common handler and post a task. + */ + auto commonHandler = std::make_shared(runner); + auto f = [&commonTaskCalled, &runner]() { + commonTaskCalled.store(true); + runner->Stop(); + }; + commonHandler->PostTask(f); + + /** + * @tc.steps: step3. reset orphan handler and start runner. + * @tc.expected: step3. the task post through orphan handler is not executed, the task + * post through common handler is executed. + */ + orphanHandler.reset(); + usleep(10000); + runner->Run(); + auto orphanCalled = orphanTaskCalled.load(); + EXPECT_FALSE(orphanCalled); + auto commonCalled = commonTaskCalled.load(); + EXPECT_TRUE(commonCalled); +} + +/* + * @tc.name: AddAndRemoveFileDescriptorListener001 + * @tc.desc: add file descriptor listener and remove file descriptor listener with fd + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, AddAndRemoveFileDescriptorListener001, TestSize.Level1) +{ + /** + * @tc.setup: init queue and prepare queue. + */ + EventQueue queue; + queue.Prepare(); + + int32_t fds[] = {-1, -1}; + EXPECT_GE(pipe(fds), 0); + + /** + * @tc.steps: step1. add file descriptor listener to queue, then remove file descriptor listener with fd, + * close pipe. + * @tc.expected: step1. add file descriptor listener success. + */ + int32_t fileDescriptor = fds[0]; + uint32_t event = 1; + auto fileDescriptorListener = std::make_shared(); + auto result = queue.AddFileDescriptorListener(fileDescriptor, event, fileDescriptorListener); + EXPECT_EQ(result, ERR_OK); + queue.RemoveFileDescriptorListener(-1); + queue.RemoveFileDescriptorListener(fileDescriptor); + close(fds[0]); + close(fds[1]); +} + +/* + * @tc.name: AddAndRemoveFileDescriptorListener002 + * @tc.desc: add file descriptor listener and remove file descriptor listener with handler + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, AddAndRemoveFileDescriptorListener002, TestSize.Level1) +{ + /** + * @tc.setup: init handler and runner, prepare queue. + */ + auto runner = EventRunner::Create(false); + auto handler = std::make_shared(runner); + EventQueue queue; + queue.Prepare(); + + /** + * @tc.steps: step1. add file descriptor listener to queue, then remove file descriptor listener with handler, + * close pipe. + * @tc.expected: step1. add file descriptor listener success. + */ + int32_t fds[] = {-1, -1}; + int32_t fileDescriptor = InitFileDescriptor(fds); + uint32_t event = 1; + + auto fileDescriptorListener = std::make_shared(); + fileDescriptorListener->SetOwner(handler); + auto result = queue.AddFileDescriptorListener(fileDescriptor, event, fileDescriptorListener); + EXPECT_EQ(result, ERR_OK); + queue.RemoveFileDescriptorListener(nullptr); + queue.RemoveFileDescriptorListener(handler); + close(fds[0]); + close(fds[1]); +} + +/* + * @tc.name: AddFileDescriptorListener001 + * @tc.desc: add file descriptor listener multi times + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, AddFileDescriptorListener001, TestSize.Level1) +{ + /** + * @tc.setup: init handler and runner, prepare queue. + */ + auto runner = EventRunner::Create(false); + auto handler = std::make_shared(runner); + EventQueue queue; + queue.Prepare(); + + int32_t fds[] = {-1, -1}; + int32_t fileDescriptor = InitFileDescriptor(fds); + uint32_t listenEvent = 1; + + /** + * @tc.steps: step1. add file descriptor listener to queue multi times, then remove file descriptor listener + * with handler, close pipe. + * @tc.expected: step1. first time add file descriptor listener success, second time failed. + */ + auto fileDescriptorListener = std::make_shared(); + fileDescriptorListener->SetOwner(handler); + auto result = queue.AddFileDescriptorListener(fileDescriptor, listenEvent, fileDescriptorListener); + EXPECT_EQ(result, ERR_OK); + result = queue.AddFileDescriptorListener(fileDescriptor, listenEvent, fileDescriptorListener); + EXPECT_EQ(result, EVENT_HANDLER_ERR_FD_ALREADY); + queue.RemoveFileDescriptorListener(handler); + close(fds[0]); + close(fds[1]); +} + +/* + * @tc.name: AddFileDescriptorListener002 + * @tc.desc: add file descriptor listener with wrong type of event + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, AddFileDescriptorListener002, TestSize.Level1) +{ + /** + * @tc.setup: init handler and runner, prepare queue. + */ + auto runner = EventRunner::Create(false); + auto handler = std::make_shared(runner); + EventQueue queue; + queue.Prepare(); + + /** + * @tc.steps: step1. add file descriptor listener to queue with wrong type of event, + * then remove file descriptor listener with handler, close pipe. + * @tc.expected: step1. add file descriptor listener failed. + */ + int32_t fds[] = {-1, -1}; + int32_t fileDescriptor = InitFileDescriptor(fds); + uint32_t newEvent = 0; + + auto fileDescriptorListener = std::make_shared(); + fileDescriptorListener->SetOwner(handler); + auto result = queue.AddFileDescriptorListener(fileDescriptor, newEvent, fileDescriptorListener); + EXPECT_EQ(result, EVENT_HANDLER_ERR_INVALID_PARAM); + queue.RemoveFileDescriptorListener(handler); + close(fds[0]); + close(fds[1]); +} + +/* + * @tc.name: AddFileDescriptorListener003 + * @tc.desc: add file descriptor listener with nullptr listener function + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, AddFileDescriptorListener003, TestSize.Level1) +{ + /** + * @tc.setup: init handler and runner, prepare queue. + */ + auto runner = EventRunner::Create(false); + auto handler = std::make_shared(runner); + EventQueue queue; + queue.Prepare(); + + /** + * @tc.steps: step1. add file descriptor listener to queue with nullptr listener, + * then remove file descriptor listener with handler, close pipe. + * @tc.expected: step1. add file descriptor listener failed. + */ + int32_t fds[] = {-1, -1}; + int32_t fileDescriptor = InitFileDescriptor(fds); + uint32_t event = 1; + + auto fileDescriptorListener = std::make_shared(); + fileDescriptorListener->SetOwner(handler); + auto result = queue.AddFileDescriptorListener(fileDescriptor, event, nullptr); + EXPECT_EQ(result, EVENT_HANDLER_ERR_INVALID_PARAM); + queue.RemoveFileDescriptorListener(handler); + close(fds[0]); + close(fds[1]); +} + +/* + * @tc.name: AddFileDescriptorListener004 + * @tc.desc: add file descriptor listener with wrong fd + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, AddFileDescriptorListener004, TestSize.Level1) +{ + /** + * @tc.setup: init handler and runner, prepare queue. + */ + auto runner = EventRunner::Create(false); + auto handler = std::make_shared(runner); + EventQueue queue; + queue.Prepare(); + + /** + * @tc.steps: step1. add file descriptor listener to queue with wrong pipe, then remove + * file descriptor listener with handler, close pipe. + * @tc.expected: step1. add file descriptor listener failed. + */ + int32_t fds[] = {-1, -1}; + + int32_t fileDescriptor = fds[0]; + uint32_t event = 1; + auto fileDescriptorListener = std::make_shared(); + fileDescriptorListener->SetOwner(handler); + auto result = queue.AddFileDescriptorListener(fileDescriptor, event, fileDescriptorListener); + EXPECT_EQ(result, EVENT_HANDLER_ERR_INVALID_PARAM); + queue.RemoveFileDescriptorListener(handler); + close(fds[0]); + close(fds[1]); +} + +/* + * @tc.name: AddFileDescriptorListener005 + * @tc.desc: add file descriptor listener when there are too many open files + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, AddFileDescriptorListener005, TestSize.Level1) +{ + /** + * @tc.setup: init queue, prepare queue. + */ + int32_t fds[] = {-1, -1}; + auto result = pipe(fds); + EXPECT_GE(result, 0); + EventQueue queue; + queue.Prepare(); + int32_t readFileDescriptor = fds[0]; + + /** + * @tc.steps: step1. get max num of files the system could support, and open max files + */ + struct rlimit rLimit {}; + result = getrlimit(RLIMIT_NOFILE, &rLimit); + EXPECT_EQ(result, 0); + for (uint64_t pos = 1; pos < rLimit.rlim_cur; pos++) { + dup(readFileDescriptor); + } + + /** + * @tc.steps: step2. add file descriptor listener to queue, then remove + * file descriptor listener with handler, close pipe. + * @tc.expected: step2. add file descriptor listener failed. + */ + uint32_t event = (FILE_DESCRIPTOR_INPUT_EVENT | FILE_DESCRIPTOR_OUTPUT_EVENT); + auto fileDescriptorListener = std::make_shared(); + result = queue.AddFileDescriptorListener(readFileDescriptor, event, fileDescriptorListener); + EXPECT_EQ(result, EVENT_HANDLER_ERR_FD_NOT_SUPPORT); + close(fds[0]); + close(fds[1]); +} + +/* + * @tc.name: HasEventWithID001 + * @tc.desc: check whether an event with the given ID can be found among the events that have been + * sent but not processed. + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, HasEventWithID001, TestSize.Level1) +{ + /** + * @tc.setup: init handler and runner. + */ + + auto runner = EventRunner::Create(true); + auto handler = std::make_shared(runner); + auto event = InnerEvent::Get(HAS_EVENT_ID); + + /** + * @tc.steps: step1. send a event with delay time, then check has this event with this id, + * then check executed after delay time has no this event with this id. + * @tc.expected: step1. Has this event with event id. + */ + handler->SendEvent(event, HAS_DELAY_TIME, EventQueue::Priority::LOW); + bool HasInnerEvent = handler->HasInnerEvent(HAS_EVENT_ID); + EXPECT_TRUE(HasInnerEvent); + int64_t delayWaitTime = 100000; + usleep(delayWaitTime); + HasInnerEvent = handler->HasInnerEvent(HAS_EVENT_ID); + EXPECT_FALSE(HasInnerEvent); +} + +/* + * @tc.name: HasEventWithID002 + * @tc.desc: check when runner is null ptr Has Inner Event process fail + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, HasEventWithID002, TestSize.Level1) +{ + /** + * @tc.setup: init runner. + */ + auto handler = std::make_shared(nullptr); + auto event = InnerEvent::Get(HAS_EVENT_ID); + + /** + * @tc.steps: step1. HasInnerEvent process + * + * @tc.expected: step1. HasInnerEvent process fail. + */ + bool HasInnerEvent = handler->HasInnerEvent(HAS_EVENT_ID); + EXPECT_FALSE(HasInnerEvent); +} + +/* + * @tc.name: HasEventWithID003 + * @tc.desc: check when runner is null ptr Has Inner Event process fail + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, HasEventWithID003, TestSize.Level1) +{ + /** + * @tc.setup: init runner. + */ + auto runner = EventRunner::Create(true); + + auto event = InnerEvent::Get(HAS_EVENT_ID); + + /** + * @tc.steps: step1. HasInnerEvent process + * + * @tc.expected: step1. HasInnerEvent process fail. + */ + bool HasInnerEvent = runner->GetEventQueue()->HasInnerEvent(nullptr, HAS_EVENT_ID); + EXPECT_FALSE(HasInnerEvent); +} + +/* + * @tc.name: HasEventWithParam001 + * @tc.desc: check whether an event with the given param can be found among the events that have been + * sent but not processed. + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, HasEventWithParam001, TestSize.Level1) +{ + /** + * @tc.setup: init handler and runner. + */ + + auto runner = EventRunner::Create(true); + auto handler = std::make_shared(runner); + auto event = InnerEvent::Get(HAS_EVENT_ID, HAS_EVENT_PARAM); + + /** + * @tc.steps: step1. send a event with delay time, then check has this event with this param, + * then check executed after delay time has no this event with this param. + * @tc.expected: step1. Has this event with event param. + */ + handler->SendEvent(event, HAS_DELAY_TIME, EventQueue::Priority::LOW); + bool HasInnerEvent = handler->HasInnerEvent(HAS_EVENT_PARAM); + EXPECT_TRUE(HasInnerEvent); + int64_t delayWaitTime = 100000; + usleep(delayWaitTime); + HasInnerEvent = handler->HasInnerEvent(HAS_EVENT_PARAM); + EXPECT_FALSE(HasInnerEvent); +} + +/* + * @tc.name: HasEventWithParam002 + * @tc.desc: check when runner is null ptr Has Inner Event process fail + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, HasEventWithParam002, TestSize.Level1) +{ + /** + * @tc.setup: init runner. + */ + auto handler = std::make_shared(nullptr); + auto event = InnerEvent::Get(HAS_EVENT_PARAM); + + /** + * @tc.steps: step1. HasInnerEvent process + * + * @tc.expected: step1. HasInnerEvent process fail. + */ + bool HasInnerEvent = handler->HasInnerEvent(HAS_EVENT_PARAM); + EXPECT_FALSE(HasInnerEvent); +} + +/* + * @tc.name: HasEventWithParam003 + * @tc.desc: check when runner is null ptr Has Inner Event process fail + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, HasEventWithParam003, TestSize.Level1) +{ + /** + * @tc.setup: init runner. + */ + auto runner = EventRunner::Create(true); + + auto event = InnerEvent::Get(HAS_EVENT_PARAM); + + /** + * @tc.steps: step1. HasInnerEvent process + * + * @tc.expected: step1. HasInnerEvent process fail. + */ + bool HasInnerEvent = runner->GetEventQueue()->HasInnerEvent(nullptr, HAS_EVENT_PARAM); + EXPECT_FALSE(HasInnerEvent); +} + +/* + * @tc.name: GetEventName001 + * @tc.desc: check when send event has no task return event id + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, GetEventName001, TestSize.Level1) +{ + /** + * @tc.setup: init runner and handler + */ + auto runner = EventRunner::Create(true); + auto handler = std::make_shared(runner); + auto event = InnerEvent::Get(HAS_EVENT_ID); + + /** + * @tc.steps: step1. GetEventName + * @tc.expected: step1. GetEventName return event id + */ + std::string eventName = handler->GetEventName(event); + EXPECT_EQ(eventName, std::to_string(HAS_EVENT_ID)); +} + +/* + * @tc.name: GetEventName002 + * @tc.desc: check when send event has task event name is "name" return event name "name" + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, GetEventName002, TestSize.Level1) +{ + /** + * @tc.setup: init runner and handler + */ + auto runner = EventRunner::Create(true); + auto handler = std::make_shared(runner); + auto task = []() {; }; + auto event = InnerEvent::Get(task, "name"); + + /** + * @tc.steps: step1. GetEventName + * @tc.expected: step1. GetEventName return name + */ + std::string eventName = handler->GetEventName(event); + EXPECT_EQ(eventName, "name"); +} + +/* + * @tc.name: GetEventName003 + * @tc.desc: check when send event has task task name is "" return event name "" + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, GetEventName003, TestSize.Level1) +{ + /** + * @tc.setup: init runner and handler + */ + auto runner = EventRunner::Create(true); + auto handler = std::make_shared(runner); + auto task = []() {; }; + auto event = InnerEvent::Get(task, ""); + + /** + * @tc.steps: step1. GetEventName + * @tc.expected: step1. GetEventName return name + */ + std::string eventName = handler->GetEventName(event); + EXPECT_EQ(eventName, ""); +} + +/* + * @tc.name: Dump001 + * @tc.desc: Check Dump + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, Dump001, TestSize.Level1) +{ + /** + * @tc.setup: init runner and handler + */ + auto runner = EventRunner::Create(true); + auto handler = std::make_shared(runner); + auto task = []() {; }; + auto event = InnerEvent::Get(task, ""); + DumpTest dumptest; + /** + * @tc.steps: step1. Dump + * @tc.expected: step1. Dump Success + */ + usleep(100 * 1000); + handler->Dump(dumptest); + EXPECT_TRUE(isDump); +} + +/* + * @tc.name: Dump002 + * @tc.desc: Check Dump after post task + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, Dump002, TestSize.Level1) +{ + isDump = false; + /** + * @tc.setup: init runner and handler + */ + auto runner = EventRunner::Create(true); + auto handler = std::make_shared(runner); + auto task = []() {; }; + DumpTest dumptest; + /** + * @tc.steps: step1. PosTask then PostTask + * @tc.expected: step1. PostTask success + */ + handler->PostTask(task, HAS_DELAY_TIME, EventQueue::Priority::LOW); + usleep(100 * 1000); + handler->Dump(dumptest); + EXPECT_TRUE(isDump); +} + +/* + * @tc.name: Dump003 + * @tc.desc: Check Dump after send event with event id + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, Dump003, TestSize.Level1) +{ + isDump = false; + /** + * @tc.setup: init runner and handler + */ + auto runner = EventRunner::Create(true); + auto handler = std::make_shared(runner); + auto event = InnerEvent::Get(HAS_EVENT_ID); + DumpTest dumptest; + /** + * @tc.steps: step1. SendEvent then Dump + * @tc.expected: step1. Dump Success + */ + handler->SendEvent(event, HAS_DELAY_TIME, EventQueue::Priority::LOW); + usleep(100 * 1000); + handler->Dump(dumptest); + EXPECT_TRUE(isDump); +} + +/* + * @tc.name: Dump004 + * @tc.desc: Check Dump after send event with event id and param + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, Dump004, TestSize.Level1) +{ + isDump = false; + /** + * @tc.setup: init runner and handler + */ + auto runner = EventRunner::Create(true); + auto handler = std::make_shared(runner); + auto event = InnerEvent::Get(HAS_EVENT_ID, HAS_EVENT_PARAM); + DumpTest dumptest; + /** + * @tc.steps: step1. SendEvent then Dump + * @tc.expected: step1. Dump Success + */ + handler->SendEvent(event, HAS_DELAY_TIME, EventQueue::Priority::LOW); + usleep(100 * 1000); + handler->Dump(dumptest); + EXPECT_TRUE(isDump); +} + +/* + * @tc.name: Dump005 + * @tc.desc: check when send event and post task dump success + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, Dump005, TestSize.Level1) +{ + isDump = false; + /** + * @tc.setup: init runner and handler + */ + auto runner = EventRunner::Create(true); + auto handler = std::make_shared(runner); + auto event = InnerEvent::Get(HAS_EVENT_ID, HAS_EVENT_PARAM); + auto task = []() {; }; + DumpTest dumptest; + + /** + * @tc.steps: step1. send event and post task then dump + * @tc.expected: step1. dump success + */ + handler->SendEvent(event, HAS_DELAY_TIME, EventQueue::Priority::LOW); + handler->PostTask(task, HAS_DELAY_TIME * 2, EventQueue::Priority::LOW); + usleep(100 * 1000); + handler->Dump(dumptest); + EXPECT_TRUE(isDump); +} + +/* + * @tc.name: IsIdle + * @tc.desc: check when idle IsIdle return true + * @tc.type: FUNC + + */ +HWTEST_F(LibEventHandlerEventQueueTest, IsIdle001, TestSize.Level1) +{ + auto runner = EventRunner::Create(true); + auto handler = std::make_shared(runner); + /** + * @tc.steps: step1. IsIdle + * @tc.expected: step1. when idle IsIdle return true + */ + bool ret = handler->IsIdle(); + EXPECT_TRUE(ret); +} + +/* + * @tc.name: IsQueueEmpty001 + * @tc.desc: check when queue is empty IsQueueEmpty return true + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, IsQueueEmpty001, TestSize.Level1) +{ + auto runner = EventRunner::Create(true); + bool ret = runner->GetEventQueue()->IsQueueEmpty(); + EXPECT_TRUE(ret); +} + +/* + * @tc.name: IsQueueEmpty002 + * @tc.desc: check when queue is not empty has low event IsQueueEmpty return false + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, IsQueueEmpty002, TestSize.Level1) +{ + /** + * @tc.setup: init runner and handler + */ + auto runner = EventRunner::Create(true); + auto handler = std::make_shared(runner); + auto event = InnerEvent::Get(HAS_EVENT_ID, HAS_EVENT_PARAM); + + /** + * @tc.steps: step1. send event and IsQueueEmpty + * @tc.expected: step1. when queue is not empty has low event IsQueueEmpty return false + */ + handler->SendEvent(event, HAS_DELAY_TIME, EventQueue::Priority::LOW); + bool ret = runner->GetEventQueue()->IsQueueEmpty(); + EXPECT_FALSE(ret); +} + +/* + * @tc.name: IsQueueEmpty003 + * @tc.desc: check when queue is not empty has idle event IsQueueEmpty return false + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventQueueTest, IsQueueEmpty003, TestSize.Level1) +{ + /** + * @tc.setup: init runner and handler + */ + auto runner = EventRunner::Create(true); + auto handler = std::make_shared(runner); + auto event = InnerEvent::Get(HAS_EVENT_ID, HAS_EVENT_PARAM); + + /** + * @tc.steps: step1. send event and IsQueueEmpty + * @tc.expected: step1. when queue is not empty has idle event IsQueueEmpty return false + */ + handler->SendEvent(event, HAS_DELAY_TIME, EventQueue::Priority::IDLE); + bool ret = runner->GetEventQueue()->IsQueueEmpty(); + EXPECT_FALSE(ret); +} \ No newline at end of file diff --git a/libs/libeventhandler/test/unittest/lib_event_handler_event_runner_test.cpp b/libs/libeventhandler/test/unittest/lib_event_handler_event_runner_test.cpp new file mode 100644 index 000000000..8262f6c48 --- /dev/null +++ b/libs/libeventhandler/test/unittest/lib_event_handler_event_runner_test.cpp @@ -0,0 +1,372 @@ +/* + * 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 "event_handler.h" +#include "event_runner.h" + +#include + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; + +static const uint32_t HAS_EVENT_ID = 100; +static const int64_t HAS_EVENT_PARAM = 1000; +bool isSetLogger = false; + +/** + * Wait until task is executed. + * + * @param f task we post. + * @param handler handler we use to post task. + * @param taskCalled flag to record whether task is executed. + */ +template +static void WaitUntilTaskCalled(F const &f, const std::shared_ptr &handler, const std::atomic &taskCalled) +{ + const uint32_t maxRetryCount = 1000; + const uint32_t sleepTime = 1000; + uint32_t count = 0; + if (handler->PostTask(f)) { + while (!taskCalled.load()) { + ++count; + // if delay more than 1 second, break + if (count >= maxRetryCount) { + break; + } + + usleep(sleepTime); + } + } +} + +/** + * Create runner with name. + * + * @param handler handler we use to post task. + * @param threadName name of thread we set. + */ +static void CreateRunnerWithName(const std::shared_ptr &handler, const std::string &threadName) +{ + std::atomic sameThreadName(false); + std::atomic taskCalled(false); + auto f = [&sameThreadName, &taskCalled, &threadName]() { + const size_t MAX_THREAD_NAME_SIZE = 16; + char thisThreadName[MAX_THREAD_NAME_SIZE + 1]; + + // Get current thread name and compare with the specified one. + int32_t ret = prctl(PR_GET_NAME, thisThreadName); + if (ret == 0) { + thisThreadName[MAX_THREAD_NAME_SIZE] = '\0'; + sameThreadName.store(threadName == thisThreadName); + } + + taskCalled.store(true); + }; + + WaitUntilTaskCalled(f, handler, taskCalled); + + auto called = taskCalled.load(); + EXPECT_TRUE(called); + auto sameThread = sameThreadName.load(); + EXPECT_TRUE(sameThread); +} + +class LibEventHandlerEventRunnerTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +class LoggerTest : public Logger { +public: + /** + * Processes the content of a specified string. + * @param message the content of a specified string. + */ + void Log(const std::string &line) + { + isSetLogger = true; + GTEST_LOG_(INFO) << line; + }; + virtual ~LoggerTest() + {} +}; + +void LibEventHandlerEventRunnerTest::SetUpTestCase(void) +{} + +void LibEventHandlerEventRunnerTest::TearDownTestCase(void) +{} + +void LibEventHandlerEventRunnerTest::SetUp(void) +{} + +void LibEventHandlerEventRunnerTest::TearDown(void) +{} + +/* + * @tc.name: CreateAndRun001 + * @tc.desc: create eventrunner and run eventrunner in asynchronous thread + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventRunnerTest, CreateAndRun001, TestSize.Level1) +{ + /** + * @tc.setup: init handler and task. + */ + auto handler = std::make_shared(EventRunner::Create()); + std::atomic taskCalled(false); + auto f = [&taskCalled]() { taskCalled.store(true); }; + + /** + * @tc.steps: step1. post task and wait until the task is executed. + * @tc.expected: step1. the task has been executed and has not timed out. + */ + WaitUntilTaskCalled(f, handler, taskCalled); + auto called = taskCalled.load(); + EXPECT_TRUE(called); +} + +/* + * @tc.name: CreateAndRun002 + * @tc.desc: create eventrunner and run eventrunner in synchronous thread + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventRunnerTest, CreateAndRun002, TestSize.Level1) +{ + /** + * @tc.setup: init handler and runner, runner is not deposit, init task to stop runner. + */ + auto runner = EventRunner::Create(false); + auto handler = std::make_shared(runner); + auto f = [&runner]() { runner->Stop(); }; + + /** + * @tc.steps: step1. post task and run the runner . + * @tc.expected: step1. start runner success. + */ + ErrCode result = EVENT_HANDLER_ERR_RUNNER_NO_PERMIT; + if (handler->PostTask(f)) { + result = runner->Run(); + } + + EXPECT_EQ(ERR_OK, result); +} + +/* + * @tc.name: CreateAndRun003 + * @tc.desc: create eventrunner and run eventrunner in asynchronous thread with threadname + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventRunnerTest, CreateAndRun003, TestSize.Level1) +{ + /** + * @tc.setup: init handler and init runner with thread name. + */ + std::string threadName("threadName"); + auto handler = std::make_shared(EventRunner::Create(threadName)); + + /** + * @tc.steps: step1. post task to compare whether the runner thread name is the same as we set. + * @tc.expected: step1. runner thread name is the same. + */ + CreateRunnerWithName(handler, threadName); +} + +/* + * @tc.name: CreateAndRun004 + * @tc.desc: create eventrunner and run eventrunner in asynchronous thread with const + char* type threadname + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventRunnerTest, CreateAndRun004, TestSize.Level1) +{ + /** + * @tc.setup: init handler and init runner with with const char* type threadname. + */ + auto handler = std::make_shared(EventRunner::Create("threadName")); + + /** + * @tc.steps: step1. post task to compare whether the runner thread name is the same as we set. + * @tc.expected: step1. runner thread name is the same. + */ + CreateRunnerWithName(handler, "threadName"); +} + +/* + * @tc.name: CreateAndRun005 + * @tc.desc: execute Run() function from one EventRunner multi times + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventRunnerTest, CreateAndRun005, TestSize.Level1) +{ + /** + * @tc.setup: init handler and runner, init a task to stop runner. + */ + const int64_t DELAY_TIME = 30; + auto runner = EventRunner::Create(false); + auto handler = std::make_shared(runner); + auto mainTask = [&runner]() { runner->Stop(); }; + + /** + * @tc.steps: step1. post delay task to start runner then new a thread to start the same runner again. + * @tc.expected: step1. return runner is already running error. + */ + auto f = [&runner]() { + usleep(10000); + auto runResult = runner->Run(); + EXPECT_EQ(EVENT_HANDLER_ERR_RUNNER_ALREADY, runResult); + }; + handler->PostTask(mainTask, DELAY_TIME); + std::thread newThread(f); + newThread.detach(); + runner->Run(); +} + +/* + * @tc.name: Stop001 + * @tc.desc: stop eventrunner in synchronous thread + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventRunnerTest, Stop001, TestSize.Level1) +{ + /** + * @tc.setup: init handler and runner, runner is not deposit, init a task to stop runner. + */ + auto runner = EventRunner::Create(false); + auto handler = std::make_shared(runner); + ErrCode result = EVENT_HANDLER_ERR_RUNNER_NO_PERMIT; + auto f = [&result, runner]() { result = runner->Stop(); }; + + /** + * @tc.steps: step1. post task and start runner, check whether the runner + * is stopped successfully in synchronous thread. + * @tc.expected: step1. runner is stopped successfully. + */ + if (handler->PostTask(f)) { + runner->Run(); + } + + EXPECT_EQ(ERR_OK, result); +} + +/* + * @tc.name: Stop002 + * @tc.desc: stop eventrunner in asynchronous thread + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventRunnerTest, Stop002, TestSize.Level1) +{ + /** + * @tc.setup: init handler and runner, runner is deposit. + */ + auto runner = EventRunner::Create(); + + /** + * @tc.steps: step1. call run() and stop() of runner. + * @tc.expected: step1. runner do not allow us to start or stop is manually when it is in asynchronous thread. + */ + auto runResult = runner->Run(); + auto stopResult = runner->Stop(); + EXPECT_EQ(EVENT_HANDLER_ERR_RUNNER_NO_PERMIT, runResult); + EXPECT_EQ(EVENT_HANDLER_ERR_RUNNER_NO_PERMIT, stopResult); +} + +/* + * @tc.name: Stop003 + * @tc.desc: execute Stop() function from one EventRunner multi times + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventRunnerTest, Stop003, TestSize.Level1) +{ + /** + * @tc.setup: init handler and runner, runner is not deposit, init a task to stop runner. + */ + auto runner = EventRunner::Create(false); + auto handler = std::make_shared(runner); + auto task = [&runner]() { runner->Stop(); }; + + /** + * @tc.steps: step1. post the stop stop task then run the runner, then stop runner again. + * @tc.expected: step1. stop() could be called multi times. + */ + handler->PostTask(task); + runner->Run(); + usleep(10000); + auto stopResult = runner->Stop(); + EXPECT_EQ(ERR_OK, stopResult); +} + +/* + * @tc.name: Current001 + * @tc.desc: start a runner, use Current() to get the running runner then compare + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventRunnerTest, Current001, TestSize.Level1) +{ + /** + * @tc.setup: init handler and runner, runner is not deposit. + */ + auto runner = EventRunner::Create(false); + auto handler = std::make_shared(runner); + + /** + * @tc.steps: step1. post a task to compare the current running runner and the runner the handler binded to. + * @tc.expected: step1. the current running runner is the same runner we run the task. + */ + auto f = [&runner]() { + auto currentRunner = EventRunner::Current(); + EXPECT_EQ(currentRunner, runner); + runner->Stop(); + }; + handler->PostTask(f); + runner->Run(); +} + +/* + * @tc.name: SetLogger001 + * @tc.desc: check SetLogger001 success + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventRunnerTest, SetLogger001, TestSize.Level1) +{ + /** + * @tc.setup: init handler and runner + */ + auto runner = EventRunner::Create(true); + auto handler = std::make_shared(runner); + auto event = InnerEvent::Get(HAS_EVENT_ID, HAS_EVENT_PARAM); + auto task = []() {; }; + /** + * @tc.steps: step1. send event + * @tc.expected: step1. SetLogger success + */ + std::shared_ptr logtest = std::make_shared(); + runner->SetLogger(logtest); + handler->SendEvent(event, EventQueue::Priority::LOW); + handler->PostTask(task, "task1"); + handler->PostTask(task); + usleep(100 * 1000); + EXPECT_TRUE(isSetLogger); +} diff --git a/libs/libeventhandler/test/unittest/lib_event_handler_event_test.cpp b/libs/libeventhandler/test/unittest/lib_event_handler_event_test.cpp new file mode 100644 index 000000000..b589699f6 --- /dev/null +++ b/libs/libeventhandler/test/unittest/lib_event_handler_event_test.cpp @@ -0,0 +1,436 @@ +/* + * 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 "event_handler.h" +#include "inner_event.h" + +using namespace testing::ext; +using namespace OHOS::AppExecFwk; +namespace { +const size_t MAX_POOL_SIZE = 64; +} + +/** + * test for task information. + */ +static void TestTaskInfo() +{ + string taskName("taskName"); + bool callbackCalled = false; + auto f = [&callbackCalled]() { callbackCalled = true; }; + auto event = InnerEvent::Get(f, taskName); + auto getName = event->GetTaskName(); + EXPECT_EQ(taskName, getName); + // execute callback function, check whether the callback function is the one we set + (event->GetTaskCallback())(); + // drop event, execute destructor function + EXPECT_TRUE(callbackCalled); +} + +/** + * Deleter of event shared pointer. + */ +inline static void Deleter(uint32_t *object) +{ + if (object == nullptr) { + return; + } + delete object; + object = nullptr; +} + +class LibEventHandlerEventTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void LibEventHandlerEventTest::SetUpTestCase(void) +{} + +void LibEventHandlerEventTest::TearDownTestCase(void) +{} + +void LibEventHandlerEventTest::SetUp(void) +{} + +void LibEventHandlerEventTest::TearDown(void) +{} + +/* + * @tc.name: GetEvent001 + * @tc.desc: get event from pool, set id and param + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventTest, GetEvent001, TestSize.Level1) +{ + /** + * @tc.steps: step1. get event with event id and param, then get event id and param from event. + * @tc.expected: step1. the event id and param is the same as we set. + */ + uint32_t eventId = 0; + int64_t eventParam = 0; + auto event = InnerEvent::Get(eventId, eventParam); + auto id = event->GetInnerEventId(); + auto param = event->GetParam(); + EXPECT_EQ(eventId, id); + EXPECT_EQ(eventParam, param); +} + +/* + * @tc.name: GetEvent002 + * @tc.desc: get event from pool , set id param and shared pointer object + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventTest, GetEvent002, TestSize.Level1) +{ + /** + * @tc.steps: step1. get event with event id, object, and param, then get event id, object and param from event. + * @tc.expected: step1. the event id, object and param is the same as we set. + */ + uint32_t eventId = 0; + int64_t eventParam = 0; + auto object = std::make_shared(); + auto event = InnerEvent::Get(eventId, object, eventParam); + auto id = event->GetInnerEventId(); + auto param = event->GetParam(); + auto sharedObject = event->GetSharedObject(); + EXPECT_EQ(eventId, id); + EXPECT_EQ(eventParam, param); + EXPECT_EQ(object, sharedObject); +} + +/* + * @tc.name: GetEvent003 + * @tc.desc: get event from pool , set id param and weak pointer object + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventTest, GetEvent003, TestSize.Level1) +{ + /** + * @tc.steps: step1. get event with event id, weak pointer object, and param, then get event id, + * shared object and param from event. + * @tc.expected: step1. the event id, object and param is the same as we set. + */ + uint32_t eventId = 0; + int64_t eventParam = 0; + auto object = std::make_shared(); + std::weak_ptr weakObject = object; + auto event = InnerEvent::Get(eventId, weakObject, eventParam); + auto id = event->GetInnerEventId(); + auto param = event->GetParam(); + auto sharedObject = event->GetSharedObject(); + auto weakToSharedObject = weakObject.lock(); + EXPECT_EQ(eventId, id); + EXPECT_EQ(eventParam, param); + EXPECT_EQ(weakToSharedObject, sharedObject); +} + +/* + * @tc.name: GetEvent004 + * @tc.desc: get event from pool , set id param and rvalue unique_ptr object + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventTest, GetEvent004, TestSize.Level1) +{ + /** + * @tc.steps: step1. get event with event id, rvalue unique_ptr object, and param. then get event id, + * unique object and param from event. + * @tc.expected: step1. the event id, object and param is the same as we set. + */ + uint32_t eventId = 0; + int64_t eventParam = 0; + uint32_t number = 1; + std::unique_ptr object = std::make_unique(number); + auto event = InnerEvent::Get(eventId, object, eventParam); + auto id = event->GetInnerEventId(); + auto param = event->GetParam(); + auto uniqueNumber = *(event->GetUniqueObject()); + EXPECT_EQ(eventId, id); + EXPECT_EQ(eventParam, param); + EXPECT_EQ(number, uniqueNumber); +} + +/* + * @tc.name: GetEvent005 + * @tc.desc: get event from pool , set id param and lvalue unique_ptr object + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventTest, GetEvent005, TestSize.Level1) +{ + /** + * @tc.steps: step1. get event with event id, lvalue unique_ptr object, and param. then get event id, + * unique object and param from event. + * @tc.expected: step1. the event id, object and param is the same as we set. + */ + uint32_t eventId = 0; + int64_t eventParam = 0; + uint32_t number = 1; + std::unique_ptr object = std::make_unique(number); + auto event = InnerEvent::Get(eventId, object, eventParam); + auto id = event->GetInnerEventId(); + auto param = event->GetParam(); + auto uniqueNumber = *(event->GetUniqueObject()); + EXPECT_EQ(eventId, id); + EXPECT_EQ(eventParam, param); + EXPECT_EQ(number, uniqueNumber); +} + +/* + * @tc.name: GetEvent006 + * @tc.desc: get event from pool set task name and callback + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventTest, GetEvent006, TestSize.Level1) +{ + /** + * @tc.steps: step1. get event with task and taskname, then get taskname from task and execute task, + * check whether the taskname and executed task is the same as we set. + * @tc.expected: step1. the taskname and executed task is the same as we set. + */ + TestTaskInfo(); +} + +/* + * @tc.name: GetEvent007 + * @tc.desc: Get Unique pointer of saved unique_ptr object + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventTest, GetEvent007, TestSize.Level1) +{ + /** + * @tc.steps: step1. get event with event id, param, and unique_ptr type object. then get event id, + * unique_ptr type unique object and param from event. + * @tc.expected: step1. the event id, object and param is the same as we set. + */ + using deleter = void (*)(uint32_t *); + uint32_t eventId = 0; + int64_t eventParam = 0; + uint32_t number = 1; + std::unique_ptr object(new uint32_t(number), Deleter); + auto event = InnerEvent::Get(eventId, object, eventParam); + auto id = event->GetInnerEventId(); + auto param = event->GetParam(); + auto uniqueNumber = *(event->GetUniqueObject()); + EXPECT_EQ(eventId, id); + EXPECT_EQ(eventParam, param); + EXPECT_EQ(number, uniqueNumber); +} + +/* + * @tc.name: GetEventInfo001 + * @tc.desc: set event owner and get event owner then compare + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventTest, GetEventInfo001, TestSize.Level1) +{ + /** + * @tc.steps: step1. init handler, get event with event id. then set the handler as the event owner + * and get event owner. + * @tc.expected: step1. the event owner is the same as we set. + */ + uint32_t eventId = 0; + auto handler = std::make_shared(); + auto event = InnerEvent::Get(eventId); + event->SetOwner(handler); + auto owner = event->GetOwner(); + EXPECT_EQ(handler, owner); +} + +/* + * @tc.name: GetEventInfo002 + * @tc.desc: set event sendTime and get event sendTime then compare + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventTest, GetEventInfo002, TestSize.Level1) +{ + /** + * @tc.steps: step1. get event with event id. then set the send time of the event, get send time of the event. + * @tc.expected: step1. the event send time is the same as we set. + */ + uint32_t eventId = 0; + auto event = InnerEvent::Get(eventId); + InnerEvent::TimePoint now = InnerEvent::Clock::now(); + event->SetSendTime(now); + auto sendTime = event->GetSendTime(); + EXPECT_EQ(now, sendTime); +} + +/* + * @tc.name: GetEventInfo003 + * @tc.desc: set event handleTime and get event handleTime then compare + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventTest, GetEventInfo003, TestSize.Level1) +{ + /** + * @tc.steps: step1. get event with event id. then set the handle time of the event, get handle time of the event. + * @tc.expected: step1. the event handle time is the same as we set. + */ + uint32_t eventId = 0; + auto event = InnerEvent::Get(eventId); + InnerEvent::TimePoint now = InnerEvent::Clock::now(); + event->SetHandleTime(now); + auto handleTime = event->GetHandleTime(); + EXPECT_EQ(now, handleTime); +} + +/* + * @tc.name: GetEventInfo004 + * @tc.desc: set event param and get event param then compare + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventTest, GetEventInfo004, TestSize.Level1) +{ + /** + * @tc.steps: step1. get event with event id and param. then get event param of the event. + * @tc.expected: step1. the event param is the same as we set. + */ + uint32_t eventId = 0; + int64_t eventParam = 0; + auto event = InnerEvent::Get(eventId, eventParam); + auto param = event->GetParam(); + EXPECT_EQ(eventParam, param); +} + +/* + * @tc.name: GetEventInfo005 + * @tc.desc: set event callback taskName and and get event callback taskName then compare + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventTest, GetEventInfo005, TestSize.Level1) +{ + /** + * @tc.steps: step1. get event with task and taskname, then get taskname from task and execute task, + * check whether the taskname and executed task is the same as we set. + * @tc.expected: step1. the taskname and executed task is the same as we set. + */ + TestTaskInfo(); +} + +/* + * @tc.name: GetEventInfo006 + * @tc.desc: judge whether the event has a task if it takes a task return true + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventTest, GetEventInfo006, TestSize.Level1) +{ + /** + * @tc.steps: step1. get event with task and taskname, then use HasTask() to check if the event has a task. + * @tc.expected: step1. the event we get from event pool has a task. + */ + string taskName("taskName"); + auto f = []() {}; + auto event = InnerEvent::Get(f, taskName); + auto whetherHasTask = event->HasTask(); + EXPECT_TRUE(whetherHasTask); +} + +/* + * @tc.name: DrainPool001 + * @tc.desc: get event from pool when the pool is full, then get event from new memory area + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventTest, DrainPool001, TestSize.Level1) +{ + /** + * @tc.steps: step1. Drain the event pool, make sure event pool is empty + */ + std::vector drainPool; + int64_t param = 0; + uint32_t eventId = 1; + for (size_t i = 0; i < MAX_POOL_SIZE; ++i) { + drainPool.push_back(InnerEvent::Get(eventId)); + ++eventId; + } + + ++eventId; + auto event = InnerEvent::Get(eventId, param); + + /** + * @tc.steps: step2. clear all the event we get from pool, make sure the pool is full. + */ + drainPool.clear(); + + /** + * @tc.steps: step3. get the event address of the event we get after the event pool is empty, + * then reset all the event we get from pool before and get event, compare the two events address. + * @tc.expected: step3. the two event address are not the same. + */ + auto firstAddr = event.get(); + event.reset(nullptr); + + auto f = []() {}; + event = InnerEvent::Get(f); + auto secondAddr = event.get(); + event.reset(nullptr); + + EXPECT_NE(firstAddr, secondAddr); +} + +/* + * @tc.name: DrainPool002 + * @tc.desc: get event from pool when the pool is not full, then get event from new memory area + * @tc.type: FUNC + */ +HWTEST_F(LibEventHandlerEventTest, DrainPool002, TestSize.Level1) +{ + /** + * @tc.steps: step1. Drain the event pool, make sure event pool is empty + */ + std::vector drainPool; + auto param = 0; + uint32_t eventId = 1; + for (size_t i = 0; i < MAX_POOL_SIZE; ++i) { + drainPool.push_back(InnerEvent::Get(eventId)); + ++eventId; + } + + /** + * @tc.steps: step2. get event from pool and get the address of the event. + */ + ++eventId; + auto event = InnerEvent::Get(eventId, param); + auto firstAddr = event.get(); + event.reset(nullptr); + + /** + * @tc.steps: step3. get another event from event pool, get the address of the event. + */ + auto f = []() {}; + event = InnerEvent::Get(f); + auto secondAddr = event.get(); + event.reset(nullptr); + + /** + * @tc.steps: step4. reset the event pool + */ + for (size_t i = 0; i < MAX_POOL_SIZE; ++i) { + drainPool.back().reset(nullptr); + } + + /** + * @tc.steps: step5. compare the two event addresses. + * @tc.expected: step3. the two event addresses are the same. + */ + EXPECT_EQ(firstAddr, secondAddr); +} \ No newline at end of file diff --git a/libs/test/BUILD.gn b/libs/test/BUILD.gn new file mode 100644 index 000000000..5cfe37ad4 --- /dev/null +++ b/libs/test/BUILD.gn @@ -0,0 +1,20 @@ +# 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") + +group("moduletest") { + testonly = true + + deps = [ "moduletest/common/event_handler:moduletest" ] +} diff --git a/libs/test/moduletest/common/event_handler/BUILD.gn b/libs/test/moduletest/common/event_handler/BUILD.gn new file mode 100644 index 000000000..9789d8fd4 --- /dev/null +++ b/libs/test/moduletest/common/event_handler/BUILD.gn @@ -0,0 +1,162 @@ +# +# 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") +import( + "//foundation/appexecfwk/standard/libs/libeventhandler/lib_event_handler_sources.gni") + +config("libeventhandler_module_test_config") { + include_dirs = [ "${libs_path}/libeventhandler/include/libeventhandler" ] + + defines = event_handler_log_domain_defines + + configs = [ "${libs_path}/libeventhandler:libeventhandler_config" ] +} + +module_output_path = "appexecfwk_standard/mstlibeventhandler" + +ohos_moduletest("EventHandlerSendEventModuleTest") { + module_out_path = module_output_path + + sources = lib_event_handler_sources + + sources += [ + "event_handler_send_event_module_test.cpp", + "event_handler_test_common.cpp", + ] + + configs = [ ":libeventhandler_module_test_config" ] + + deps = [ "//third_party/googletest:gtest_main" ] + + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] +} + +ohos_moduletest("EventHandlerPostTaskModuleTest") { + module_out_path = module_output_path + + sources = lib_event_handler_sources + + sources += [ + "event_handler_post_task_module_test.cpp", + "event_handler_test_common.cpp", + ] + + configs = [ ":libeventhandler_module_test_config" ] + + deps = [ "//third_party/googletest:gtest_main" ] + + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] +} + +ohos_moduletest("EventHandlerSetGetRemoveModuleTest") { + module_out_path = module_output_path + + sources = lib_event_handler_sources + + sources += [ + "event_handler_set_get_remove_module_test.cpp", + "event_handler_test_common.cpp", + ] + + configs = [ ":libeventhandler_module_test_config" ] + + deps = [ "//third_party/googletest:gtest_main" ] + + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] +} + +ohos_moduletest("EventHandlerFdListenerModuleTest") { + module_out_path = module_output_path + + sources = lib_event_handler_sources + + sources += [ + "event_handler_fd_listener_module_test.cpp", + "event_handler_test_common.cpp", + ] + + configs = [ ":libeventhandler_module_test_config" ] + + deps = [ "//third_party/googletest:gtest_main" ] + + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] +} + +ohos_moduletest("EventHandlerPressModuleTest") { + module_out_path = module_output_path + + sources = lib_event_handler_sources + + sources += [ + "event_handler_press_module_test.cpp", + "event_handler_test_common.cpp", + ] + + configs = [ ":libeventhandler_module_test_config" ] + + deps = [ "//third_party/googletest:gtest_main" ] + + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] +} + +ohos_moduletest("EventHandlerSendSyncEventModuleTest") { + module_out_path = module_output_path + + sources = lib_event_handler_sources + + sources += [ + "event_handler_send_sync_event_module_test.cpp", + "event_handler_test_common.cpp", + ] + + configs = [ ":libeventhandler_module_test_config" ] + + deps = [ "//third_party/googletest:gtest_main" ] + + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] +} + +ohos_moduletest("EventHandlerSendTimingEventModuleTest") { + module_out_path = module_output_path + + sources = lib_event_handler_sources + + sources += [ + "event_handler_send_timing_event_module_test.cpp", + "event_handler_test_common.cpp", + ] + + configs = [ ":libeventhandler_module_test_config" ] + + deps = [ "//third_party/googletest:gtest_main" ] + + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] +} + +group("moduletest") { + testonly = true + + deps = [ + ":EventHandlerFdListenerModuleTest", + ":EventHandlerPostTaskModuleTest", + ":EventHandlerPressModuleTest", + ":EventHandlerSendEventModuleTest", + ":EventHandlerSendSyncEventModuleTest", + ":EventHandlerSendTimingEventModuleTest", + ":EventHandlerSetGetRemoveModuleTest", + ] +} 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 new file mode 100644 index 000000000..f1e3e8e5c --- /dev/null +++ b/libs/test/moduletest/common/event_handler/event_handler_fd_listener_module_test.cpp @@ -0,0 +1,378 @@ +/* + * 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 "event_handler_test_common.h" + +#include + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; + +static std::string g_testMsg = ""; + +class EventHandlerFdListenerModuleTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void EventHandlerFdListenerModuleTest::SetUpTestCase(void) +{} + +void EventHandlerFdListenerModuleTest::TearDownTestCase(void) +{} + +void EventHandlerFdListenerModuleTest::SetUp(void) +{ + /** + * @tc.setup: Set the test message to null string. + */ + g_testMsg = ""; +} + +void EventHandlerFdListenerModuleTest::TearDown(void) +{} + +class MyFileDescriptorListener : public FileDescriptorListener { +public: + explicit MyFileDescriptorListener(int32_t fd = -1) : fd_(fd) + {} + + ~MyFileDescriptorListener() + {} + + void OnReadable(int32_t fileDescriptor) override + { + if (fileDescriptor < 0) { + g_testMsg = "bad fd"; + return; + } + + FileDescriptorListener::OnReadable(fileDescriptor); + + uint32_t messageSize = 64; + char message[messageSize]; + ssize_t retVal = read(fileDescriptor, message, sizeof(message) - 1); + if (retVal > 0) { + message[retVal] = '\0'; + g_testMsg = message; + } + } + + void OnWritable(int32_t fileDescriptor) override + { + if (fileDescriptor < 0) { + g_testMsg = "bad fd"; + return; + } + + FileDescriptorListener::OnWritable(fileDescriptor); + + if (fd_ >= 0) { + close(fd_); + return; + } + + auto handler = GetOwner(); + if (handler) { + handler->RemoveFileDescriptorListener(fileDescriptor); + auto f = [fileDescriptor]() { write(fileDescriptor, "test", sizeof("test")); }; + int64_t delayTime = 50; + handler->PostTask(f, delayTime); + } + } + + void OnShutdown(int32_t fileDescriptor) override + { + if (fileDescriptor < 0) { + g_testMsg = "bad fd"; + return; + } + + g_testMsg = "OnShutdown"; + FileDescriptorListener::OnShutdown(fileDescriptor); + } + + void OnException(int32_t fileDescriptor) override + { + if (fileDescriptor < 0) { + g_testMsg = "bad fd"; + return; + } + + g_testMsg = "OnException"; + FileDescriptorListener::OnException(fileDescriptor); + } + +private: + int32_t fd_; +}; + +/** + * @tc.name: AddListener001 + * @tc.desc: Add listener of input event and output event + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerFdListenerModuleTest, AddListener001, TestSize.Level1) +{ + /** + * @tc.steps: step1. Add fd listener, write and read the data. + * @tc.expected: step1. Add fd listener of input and output successfully, write and read the data correctly. + */ + int32_t fds[] = {-1, -1}; + int32_t pipe = pipe2(fds, O_NONBLOCK); + ASSERT_GE(pipe, 0); + + auto listener = std::make_shared(); + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + auto inResult = handler->AddFileDescriptorListener(fds[0], FILE_DESCRIPTOR_INPUT_EVENT, listener); + EXPECT_EQ(inResult, ERR_OK); + auto outResult = handler->AddFileDescriptorListener(fds[1], FILE_DESCRIPTOR_OUTPUT_EVENT, listener); + EXPECT_EQ(outResult, ERR_OK); + + int64_t delayTime = 100; + int64_t param = 0; + handler->SendEvent(STOP_EVENT_ID, param, delayTime); + myRunner->Run(); + EXPECT_EQ("test", g_testMsg); +} + +/** + * @tc.name: AddListener002 + * @tc.desc: Add listener with forbidden fd + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerFdListenerModuleTest, AddListener002, TestSize.Level1) +{ + /** + * @tc.steps: step1. Add fd listener with forbidden fd. + * @tc.expected: step1. Add fd listener failed and return error code. + */ + auto listener = std::make_shared(); + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + + int32_t fd = -1; + auto inResult = handler->AddFileDescriptorListener(fd, FILE_DESCRIPTOR_INPUT_EVENT, listener); + EXPECT_EQ(EVENT_HANDLER_ERR_INVALID_PARAM, inResult); +} + +/** + * @tc.name: AddListener003 + * @tc.desc: Add listener without event + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerFdListenerModuleTest, AddListener003, TestSize.Level1) +{ + /** + * @tc.steps: step1. Add fd listener without event. + * @tc.expected: step1. Add fd listener failed and return error code. + */ + int32_t fds[] = {-1, -1}; + int32_t pipe = pipe2(fds, O_NONBLOCK); + ASSERT_GE(pipe, 0); + + auto listener = std::make_shared(); + auto myRunner = EventRunner::Create(true); + auto handler = std::make_shared(myRunner); + + uint32_t event = 0; + auto inResult = handler->AddFileDescriptorListener(fds[0], event, listener); + EXPECT_EQ(EVENT_HANDLER_ERR_INVALID_PARAM, inResult); +} + +/** + * @tc.name: AddListener004 + * @tc.desc: Add listener without listener + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerFdListenerModuleTest, AddListener004, TestSize.Level1) +{ + /** + * @tc.steps: step1. Add fd listener without listener. + * @tc.expected: step1. Add fd listener failed and return error code. + */ + int32_t fds[] = {-1, -1}; + int32_t pipe = pipe2(fds, O_NONBLOCK); + ASSERT_GE(pipe, 0); + + auto myRunner = EventRunner::Create(true); + auto handler = std::make_shared(myRunner); + + auto inResult = handler->AddFileDescriptorListener(fds[0], FILE_DESCRIPTOR_INPUT_EVENT, nullptr); + EXPECT_EQ(EVENT_HANDLER_ERR_INVALID_PARAM, inResult); +} + +/** + * @tc.name: AddListener005 + * @tc.desc: Add listener without event runner + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerFdListenerModuleTest, AddListener005, TestSize.Level1) +{ + /** + * @tc.steps: step1. Add fd listener without event runner. + * @tc.expected: step1. Add fd listener failed and return error code. + */ + int32_t fds[] = {-1, -1}; + int32_t pipe = pipe2(fds, O_NONBLOCK); + ASSERT_GE(pipe, 0); + + auto listener = std::make_shared(); + auto handler = std::make_shared(nullptr); + + auto inResult = handler->AddFileDescriptorListener(fds[0], FILE_DESCRIPTOR_INPUT_EVENT, listener); + EXPECT_EQ(EVENT_HANDLER_ERR_NO_EVENT_RUNNER, inResult); +} + +/** + * @tc.name: RemoveListener001 + * @tc.desc: Remove all listeners + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerFdListenerModuleTest, RemoveListener001, TestSize.Level1) +{ + /** + * @tc.steps: step1. Add fd listener of write and read, and then remove all listener. + * @tc.expected: step1. The data not written and read after removed. + */ + int32_t fds[] = {-1, -1}; + int32_t pipe = pipe2(fds, O_NONBLOCK); + ASSERT_GE(pipe, 0); + + auto listener = std::make_shared(); + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + auto inResult = handler->AddFileDescriptorListener(fds[0], FILE_DESCRIPTOR_INPUT_EVENT, listener); + EXPECT_EQ(inResult, ERR_OK); + auto outResult = handler->AddFileDescriptorListener(fds[1], FILE_DESCRIPTOR_OUTPUT_EVENT, listener); + EXPECT_EQ(outResult, ERR_OK); + handler->RemoveAllFileDescriptorListeners(); + + int64_t delayTime = 100; + int64_t param = 0; + handler->SendEvent(STOP_EVENT_ID, param, delayTime); + myRunner->Run(); + EXPECT_EQ("", g_testMsg); +} + +/** + * @tc.name: RemoveListener002 + * @tc.desc: Remove a listener by fd + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerFdListenerModuleTest, RemoveListener002, TestSize.Level1) +{ + /** + * @tc.steps: step1. Add fd listener of write and read, and then remove the listener by fd. + * @tc.expected: step1. The data not read after removed. + */ + int32_t fds[] = {-1, -1}; + int32_t pipe = pipe2(fds, O_NONBLOCK); + ASSERT_GE(pipe, 0); + + auto listener = std::make_shared(); + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + auto inResult = handler->AddFileDescriptorListener(fds[0], FILE_DESCRIPTOR_INPUT_EVENT, listener); + EXPECT_EQ(inResult, ERR_OK); + auto outResult = handler->AddFileDescriptorListener(fds[1], FILE_DESCRIPTOR_OUTPUT_EVENT, listener); + EXPECT_EQ(outResult, ERR_OK); + handler->RemoveFileDescriptorListener(fds[0]); + + int64_t delayTime = 100; + int64_t param = 0; + handler->SendEvent(STOP_EVENT_ID, param, delayTime); + myRunner->Run(); + EXPECT_EQ("", g_testMsg); +} + +/** + * @tc.name: TriggerShutdown001 + * @tc.desc: Trigger shutdown event + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerFdListenerModuleTest, TriggerShutdown001, TestSize.Level1) +{ + /** + * @tc.steps: step1. Add fd listener of read, and then close the write fd. + * @tc.expected: step1. The shutdown event appeared. + */ + int32_t fds[] = {-1, -1}; + int32_t pipe = pipe2(fds, O_NONBLOCK); + ASSERT_GE(pipe, 0); + + auto listener = std::make_shared(); + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + auto otherHandler = std::make_shared(EventRunner::Create()); + auto inResult = handler->AddFileDescriptorListener(fds[0], FILE_DESCRIPTOR_INPUT_EVENT, listener); + EXPECT_EQ(inResult, ERR_OK); + + int64_t delayTime = 100; + int64_t param = 0; + handler->SendEvent(STOP_EVENT_ID, param, delayTime); + auto task = [fds, otherHandler]() { + auto f = [fds]() { close(fds[1]); }; + otherHandler->PostTask(f); + }; + + handler->PostTask(task); + myRunner->Run(); + EXPECT_EQ("OnShutdown", g_testMsg); +} + +/** + * @tc.name: TriggerException001 + * @tc.desc: Trigger exception event + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerFdListenerModuleTest, TriggerException001, TestSize.Level1) +{ + /** + * @tc.steps: step1. Add fd listener of write, and then run the runner. + * @tc.expected: step1. The exception event appeared. + */ + int32_t fds[] = {-1, -1}; + int32_t pipe = pipe2(fds, O_NONBLOCK); + ASSERT_GE(pipe, 0); + + auto listener = std::make_shared(fds[0]); + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + auto inResult = handler->AddFileDescriptorListener(fds[1], FILE_DESCRIPTOR_OUTPUT_EVENT, listener); + EXPECT_EQ(inResult, ERR_OK); + + int64_t delayTime = 100; + int64_t param = 0; + handler->SendEvent(STOP_EVENT_ID, param, delayTime); + myRunner->Run(); + EXPECT_EQ("OnException", g_testMsg); +} \ No newline at end of file diff --git a/libs/test/moduletest/common/event_handler/event_handler_post_task_module_test.cpp b/libs/test/moduletest/common/event_handler/event_handler_post_task_module_test.cpp new file mode 100644 index 000000000..66c4e5320 --- /dev/null +++ b/libs/test/moduletest/common/event_handler/event_handler_post_task_module_test.cpp @@ -0,0 +1,233 @@ +/* + * 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 "event_handler_test_common.h" + +#include + +using namespace testing::ext; +using namespace OHOS::AppExecFwk; + +class EventHandlerPostTaskModuleTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void EventHandlerPostTaskModuleTest::SetUpTestCase(void) +{} + +void EventHandlerPostTaskModuleTest::TearDownTestCase(void) +{} + +void EventHandlerPostTaskModuleTest::SetUp(void) +{ + /** + * @tc.setup: Set the value of test flags to the default. + */ + CommonUtils::TaskCalledSet(false); +} + +void EventHandlerPostTaskModuleTest::TearDown(void) +{} + +/** + * @tc.name: Post001 + * @tc.desc: Post a task with callback, name, delayTime and priority + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ + */ +HWTEST_F(EventHandlerPostTaskModuleTest, Post001, TestSize.Level1) +{ + /** + * @tc.steps: step1. Post a task with callback, name, delayTime and priority. + * @tc.expected: step1. Post successfully and the task handled. + */ + int64_t delayTime = 1; + string taskName = std::to_string(Random()); + auto f = []() { CommonUtils::TaskCalledSet(true); }; + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + + bool postResult = handler->PostTask(f, taskName, delayTime, EventQueue::Priority::LOW); + EXPECT_TRUE(postResult); + int64_t param = 0; + handler->SendEvent(STOP_EVENT_ID, param, delayTime + 1); + myRunner->Run(); + bool runResult = CommonUtils::TaskCalledGet(); + EXPECT_TRUE(runResult); +} + +/** + * @tc.name: Post002 + * @tc.desc: Post a task with callback, delayTime and priority + * @tc.type: FUNC + * @tc.require: SR000BTOPM AR000CQ2AE + */ +HWTEST_F(EventHandlerPostTaskModuleTest, Post002, TestSize.Level1) +{ + /** + * @tc.steps: step1. Post a task with callback, delayTime and priority. + * @tc.expected: step1. Post successfully and the task handled. + */ + int64_t delayTime = 0; + auto f = []() { CommonUtils::TaskCalledSet(true); }; + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + + bool postResult = handler->PostTask(f, delayTime, EventQueue::Priority::HIGH); + EXPECT_TRUE(postResult); + handler->SendEvent(STOP_EVENT_ID); + myRunner->Run(); + bool runResult = CommonUtils::TaskCalledGet(); + EXPECT_TRUE(runResult); +} + +/** + * @tc.name: Post003 + * @tc.desc: Post an immediate task with callback and name + * @tc.type: FUNC + * @tc.require: AR000CQ2A8 SR000CQ2AH + */ +HWTEST_F(EventHandlerPostTaskModuleTest, Post003, TestSize.Level1) +{ + /** + * @tc.steps: step1. Post an immediate task with callback and name. + * @tc.expected: step1. Post successfully and the task handled. + */ + string taskName = std::to_string(Random()); + auto f = []() { CommonUtils::TaskCalledSet(true); }; + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + + bool postResult = handler->PostImmediateTask(f, taskName); + EXPECT_TRUE(postResult); + handler->SendEvent(STOP_EVENT_ID); + myRunner->Run(); + bool runResult = CommonUtils::TaskCalledGet(); + EXPECT_TRUE(runResult); +} + +/** + * @tc.name: Post004 + * @tc.desc: Post a high priority with callback, name and delayTime + * @tc.type: FUNC + * @tc.require: AR000CQ2A9 SR000CQ2AH + */ +HWTEST_F(EventHandlerPostTaskModuleTest, Post004, TestSize.Level1) +{ + /** + * @tc.steps: step1. Post a high priority with callback, name and delayTime. + * @tc.expected: step1. Post successfully and the task handled. + */ + int64_t delayTime = 0; + string taskName = std::to_string(Random()); + auto f = []() { CommonUtils::TaskCalledSet(true); }; + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + + bool postResult = handler->PostHighPriorityTask(f, taskName, delayTime); + EXPECT_TRUE(postResult); + handler->SendEvent(STOP_EVENT_ID); + myRunner->Run(); + bool runResult = CommonUtils::TaskCalledGet(); + EXPECT_TRUE(runResult); +} + +/** + * @tc.name: Post005 + * @tc.desc: Post a high priority with callback and delayTime + * @tc.type: FUNC + * @tc.require: AR000CQ2AA SR000CQ2AH + */ +HWTEST_F(EventHandlerPostTaskModuleTest, Post005, TestSize.Level1) +{ + /** + * @tc.steps: step1. Post a high priority with callback and delayTime. + * @tc.expected: step1. Post successfully and the task handled. + */ + int64_t delayTime = 0; + auto f = []() { CommonUtils::TaskCalledSet(true); }; + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + + bool postResult = handler->PostHighPriorityTask(f, delayTime); + EXPECT_TRUE(postResult); + handler->SendEvent(STOP_EVENT_ID); + myRunner->Run(); + bool runResult = CommonUtils::TaskCalledGet(); + EXPECT_TRUE(runResult); +} + +/** + * @tc.name: Post006 + * @tc.desc: Post a idle priority with callback, name and delayTime + * @tc.type: FUNC + * @tc.require: AR000CQ2AB SR000BTOPJ + */ +HWTEST_F(EventHandlerPostTaskModuleTest, Post006, TestSize.Level1) +{ + /** + * @tc.steps: step1. Post a idle priority with callback, name and delayTime. + * @tc.expected: step1. Post successfully and the task handled. + */ + int64_t delayTime = 0; + string taskName = std::to_string(Random()); + auto f = []() { CommonUtils::TaskCalledSet(true); }; + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + + bool postResult = handler->PostIdleTask(f, taskName, delayTime); + EXPECT_TRUE(postResult); + auto fStop = [&myRunner]() { myRunner->Stop(); }; + handler->PostIdleTask(fStop, delayTime + 1); + int64_t param = 0; + int64_t offsetTime = 2; + handler->SendEvent(RUN_EVENT_ID, param, delayTime + offsetTime); + myRunner->Run(); + bool runResult = CommonUtils::TaskCalledGet(); + EXPECT_TRUE(runResult); +} + +/** + * @tc.name: Post007 + * @tc.desc: Post a idle priority with callback and delayTime + * @tc.type: FUNC + * @tc.require: AR000CQ2AC SR000BTOPJ + */ +HWTEST_F(EventHandlerPostTaskModuleTest, Post007, TestSize.Level1) +{ + /** + * @tc.steps: step1. Post a idle priority with callback and delayTime. + * @tc.expected: step1. Post successfully and the task handled. + */ + int64_t delayTime = 0; + int64_t param = 0; + auto f = []() { CommonUtils::TaskCalledSet(true); }; + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + + bool postResult = handler->PostIdleTask(f, delayTime); + EXPECT_TRUE(postResult); + auto fStop = [&myRunner]() { myRunner->Stop(); }; + handler->PostIdleTask(fStop, delayTime + 1); + int64_t offsetTime = 2; + handler->SendEvent(RUN_EVENT_ID, param, delayTime + offsetTime); + myRunner->Run(); + bool runResult = CommonUtils::TaskCalledGet(); + EXPECT_TRUE(runResult); +} 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 new file mode 100644 index 000000000..0d035a301 --- /dev/null +++ b/libs/test/moduletest/common/event_handler/event_handler_press_module_test.cpp @@ -0,0 +1,223 @@ +/* + * 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 "event_handler_test_common.h" + +#include + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; + +namespace { +const uint32_t TEST_TIMES = 10000; +uint32_t g_sendCount = 0; +uint32_t g_readDataSize = 0; +uint32_t g_writeDataSize = 0; + +inline uint32_t RandomInTen() +{ + uint32_t remainderNum = 10; + return static_cast(std::rand() % remainderNum); +} + +std::string CreateData(size_t dataSize) +{ + std::string message = ""; + for (size_t i = 0; i < dataSize; i++) { + message += std::to_string(RandomInTen()); + } + return message; +} +} // unnamed namespace + +class EventHandlerPressModuleTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void EventHandlerPressModuleTest::SetUpTestCase(void) +{} + +void EventHandlerPressModuleTest::TearDownTestCase(void) +{} + +void EventHandlerPressModuleTest::SetUp(void) +{ + /** + * @tc.setup: Set the value of test flags to the default. + */ + CommonUtils::EventRunSet(false); + CommonUtils::EventRunCountReset(); + g_sendCount = 0; + g_readDataSize = 0; + g_writeDataSize = 0; +} + +void EventHandlerPressModuleTest::TearDown(void) +{} + +class MyFileDescriptorListener : public FileDescriptorListener { +public: + MyFileDescriptorListener() + {} + ~MyFileDescriptorListener() + {} + + void OnReadable(int32_t fileDescriptor) override + { + uint32_t messageSize = 1024; + char message[messageSize]; + ssize_t retVal = read(fileDescriptor, message, sizeof(message) - 1); + if (retVal > 0) { + message[retVal] = '\0'; + g_readDataSize += retVal; + } + } + + void OnWritable(int32_t fileDescriptor) override + { + auto handler = GetOwner(); + if (handler) { + handler->RemoveFileDescriptorListener(fileDescriptor); + size_t dataSize = 10; + int64_t delayTime = 10; + uint32_t writeTimes = 1000; + for (uint32_t i = 0; i < writeTimes; ++i) { + std::string message = CreateData(dataSize); + auto f = [fileDescriptor, message]() { write(fileDescriptor, message.c_str(), message.size()); }; + handler->PostTask(f, delayTime * (i + 1)); + g_writeDataSize += message.size(); + } + } + } +}; + +/** + * @tc.name: SendPress001 + * @tc.desc: Send the same event for 10000 times + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerPressModuleTest, SendPress001, TestSize.Level3) +{ + /** + * @tc.steps: step1. Send event for 10000 times. + * @tc.expected: step1. Send successfully and the event handled, and the succeeded times equals to test times. + */ + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + + for (uint32_t i = 0; i < TEST_TIMES; ++i) { + bool sentResult = handler->SendEvent(RUN_EVENT_ID); + handler->SendEvent(STOP_EVENT_ID); + myRunner->Run(); + if (sentResult && CommonUtils::EventRunGet()) { + g_sendCount++; + } + } + EXPECT_EQ(TEST_TIMES, g_sendCount); +} + +/** + * @tc.name: SendPress002 + * @tc.desc: Send event by different handler for 10000 times + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerPressModuleTest, SendPress002, TestSize.Level3) +{ + /** + * @tc.steps: step1. Send event by different handler for 10000 times. + * @tc.expected: step1. Send successfully and the event handled, + * and the succeeded times equals to test times. + * the test result is right, equals to test times multiply by 2. + */ + auto myRunner = EventRunner::Create(false); + auto handler1 = std::make_shared(myRunner); + auto handler2 = std::make_shared(myRunner); + + for (uint32_t i = 0; i < TEST_TIMES; ++i) { + bool sentResult1 = handler1->SendEvent(RUN_EVENT_ID); + bool sentResult2 = handler2->SendEvent(RUN_EVENT_ID); + handler2->SendEvent(STOP_EVENT_ID); + myRunner->Run(); + if (sentResult1 && sentResult2) { + g_sendCount++; + } + } + EXPECT_EQ(TEST_TIMES, g_sendCount); + EXPECT_EQ(TEST_TIMES * 2, CommonUtils::EventRunCount()); +} + +/** + * @tc.name: SendPress003 + * @tc.desc: Send different event for 10000 times + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerPressModuleTest, SendPress003, TestSize.Level3) +{ + /** + * @tc.steps: step1. Send different event for 10000 times. + * @tc.expected: step1. Send successfully and the event handled, and the succeeded times equals to test times. + */ + auto myRunner = EventRunner::Create(true); + auto handler = std::make_shared(myRunner); + for (uint32_t i = 0; i < TEST_TIMES; ++i) { + bool sentResult = handler->SendEvent(Random() + 1); + if (sentResult) { + g_sendCount++; + } + } + handler->SendEvent(STOP_EVENT_ID); + EXPECT_EQ(TEST_TIMES, g_sendCount); +} + +/** + * @tc.name: FdListenerPress001 + * @tc.desc: Press test of listener via epoll + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerPressModuleTest, FdListenerPress001, TestSize.Level3) +{ + /** + * @tc.steps: step1. Add fd listener, write and read data for 1000 times. + * @tc.expected: step1. Add fd listener of input and output successfully, write and read the data correctly. + */ + int32_t fds[] = {-1, -1}; + int32_t pipe = pipe2(fds, O_NONBLOCK); + ASSERT_GE(pipe, 0); + + auto listener = std::make_shared(); + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + auto inResult = handler->AddFileDescriptorListener(fds[0], FILE_DESCRIPTOR_INPUT_EVENT, listener); + ASSERT_EQ(inResult, ERR_OK); + auto outResult = handler->AddFileDescriptorListener(fds[1], FILE_DESCRIPTOR_OUTPUT_EVENT, listener); + ASSERT_EQ(outResult, ERR_OK); + + int64_t delayTime = 20000; + int64_t param = 0; + handler->SendEvent(STOP_EVENT_ID, param, delayTime); + myRunner->Run(); + EXPECT_EQ(g_writeDataSize, g_readDataSize); +} \ No newline at end of file diff --git a/libs/test/moduletest/common/event_handler/event_handler_send_event_module_test.cpp b/libs/test/moduletest/common/event_handler/event_handler_send_event_module_test.cpp new file mode 100644 index 000000000..857369b89 --- /dev/null +++ b/libs/test/moduletest/common/event_handler/event_handler_send_event_module_test.cpp @@ -0,0 +1,588 @@ +/* + * 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 "event_handler_test_common.h" + +#include + +using namespace testing::ext; +using namespace OHOS::AppExecFwk; + +namespace { +/** + * Function: Send an event with default priority, and then check the processed result. + * @param delayTime Delay time for processing. + * @param priority Priority of event. + */ +void SendAndCheck(int64_t delayTime, EventQueue::Priority priority) +{ + auto event = InnerEvent::Get(RUN_EVENT_ID); + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + bool lValueResult = handler->SendEvent(event, delayTime, priority); + EXPECT_TRUE(lValueResult); + + bool rValueResult = handler->SendEvent(InnerEvent::Get(RUN_EVENT_ID), delayTime, priority); + EXPECT_TRUE(rValueResult); + + handler->SendEvent(STOP_EVENT_ID, 0, delayTime + 1); + myRunner->Run(); + uint32_t runResult = 2; + EXPECT_EQ(runResult, CommonUtils::EventRunCount()); +} + +/** + * Function: Send an event with HIGH or IMMEDIATE priority, and chen check the processed result. + * @param priority Priority of event. + */ +void SendEventWithPriority(EventQueue::Priority priority) +{ + auto event = InnerEvent::Get(RUN_EVENT_ID); + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + + bool lvalueSendResult = false; + bool rvalueSendResult = false; + int64_t delayTime = 0; + + if (priority == EventQueue::Priority::HIGH) { + lvalueSendResult = handler->SendHighPriorityEvent(event, delayTime); + rvalueSendResult = + handler->SendHighPriorityEvent(InnerEvent::Get(RUN_EVENT_ID, std::make_unique(1)), delayTime); + } + + if (priority == EventQueue::Priority::IMMEDIATE) { + lvalueSendResult = handler->SendImmediateEvent(event); + rvalueSendResult = handler->SendImmediateEvent(InnerEvent::Get(RUN_EVENT_ID, std::make_unique(1))); + } + + EXPECT_TRUE(lvalueSendResult); + EXPECT_TRUE(rvalueSendResult); + handler->SendEvent(STOP_EVENT_ID); + myRunner->Run(); + uint32_t runResult = 2; + EXPECT_EQ(runResult, CommonUtils::EventRunCount()); +} + +/** + * Function: Send an event by event id with different priority, and check the processed result. + * @param priority Priority of event. + */ +void SendEventWithPriorityByEventId(EventQueue::Priority priority) +{ + /** + * @tc.steps: step1. Set event by event id with different priority (LOW, HIGH, IMMEDIATE). + */ + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + bool sendResult = false; + int64_t param = 0; + int64_t delayTime = 0; + + if (priority == EventQueue::Priority::LOW) { + sendResult = handler->SendEvent(RUN_EVENT_ID, param, delayTime); + } + if (priority == EventQueue::Priority::HIGH) { + sendResult = handler->SendHighPriorityEvent(RUN_EVENT_ID, param, delayTime); + } + if (priority == EventQueue::Priority::IMMEDIATE) { + sendResult = handler->SendImmediateEvent(RUN_EVENT_ID, param); + } + + /** + * @tc.steps: step2. Check the send and handled result. + * @tc.expected: step2. Send successfully and the event handled. + */ + EXPECT_TRUE(sendResult); + handler->SendEvent(STOP_EVENT_ID); + myRunner->Run(); + EXPECT_TRUE(CommonUtils::EventRunGet()); +} + +/** + * Function: Send an event with shared pointer or weak pointer, and check the send result. + * @param handler Event handler. + * @param priority Priority of event. + * @param ptr Shared pointer or weak pointer. + */ +template +void SendEventWithSharedOrWeakPtr( + const std::shared_ptr &handler, EventQueue::Priority priority, const T &ptr) +{ + bool retVal = false; + if (priority == EventQueue::Priority::LOW) { + retVal = handler->SendEvent(RUN_EVENT_ID, ptr, 0); + } + if (priority == EventQueue::Priority::HIGH) { + retVal = handler->SendHighPriorityEvent(RUN_EVENT_ID, ptr, 0); + } + if (priority == EventQueue::Priority::IMMEDIATE) { + retVal = handler->SendImmediateEvent(RUN_EVENT_ID, ptr); + } + EXPECT_TRUE(retVal); +} + +/** + * Function: Send an event with unique pointer, and check the send result. + * @param handler Event handler. + * @param priority Priority of event. + * @param isRValue Is or not right value. + */ +void SendEventWithUniquePtr( + const std::shared_ptr &handler, EventQueue::Priority priority, bool isRValue = false) +{ + auto f = [](int *intPtr) { delete intPtr; }; + auto uniquePtr = std::unique_ptr((new int(1)), f); + bool retVal = false; + switch (priority) { + case EventQueue::Priority::LOW: { + if (!isRValue) { + retVal = handler->SendEvent(RUN_EVENT_ID, uniquePtr, 0); + } else { + retVal = handler->SendEvent(RUN_EVENT_ID, std::unique_ptr((new int(1)), f), 0); + } + break; + } + case EventQueue::Priority::HIGH: { + if (!isRValue) { + retVal = handler->SendHighPriorityEvent(RUN_EVENT_ID, uniquePtr, 0); + } else { + retVal = handler->SendHighPriorityEvent( + RUN_EVENT_ID, std::unique_ptr((new int(1)), f), 0); + } + break; + } + case EventQueue::Priority::IMMEDIATE: { + if (!isRValue) { + retVal = handler->SendImmediateEvent(RUN_EVENT_ID, uniquePtr); + } else { + retVal = + handler->SendImmediateEvent(RUN_EVENT_ID, std::unique_ptr((new int(1)), f)); + } + break; + } + default: + break; + } + + EXPECT_TRUE(retVal); +} + +/** + * Function: Send event with smart pointer, and then check the processed result. + * @param smartPointerType One of smart pointer. + * @param priority Priority of event. + */ +void SendEventWithSmartPtr(SmartPointerType smartPointerType, EventQueue::Priority priority) +{ + /** + * @tc.steps: step1. Send event with different priority and smart pointer. + * @tc.expected: step1. Send successfully and the event handled. + */ + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + auto sharedPtr = std::make_shared(1); + auto weakPtr = std::weak_ptr(sharedPtr); + + switch (smartPointerType) { + case SmartPointerType::SHARED_PTR: { + SendEventWithSharedOrWeakPtr(handler, priority, sharedPtr); + break; + } + case SmartPointerType::WEAK_PTR: { + SendEventWithSharedOrWeakPtr(handler, priority, weakPtr); + break; + } + case SmartPointerType::LVALUE_REFERENCE_UNIQUE_PTR: { + SendEventWithUniquePtr(handler, priority); + break; + } + case SmartPointerType::RVALUE_REFERENCE_UNIQUE_PTR: { + SendEventWithUniquePtr(handler, priority, true); + break; + } + default: + break; + } + + handler->SendEvent(STOP_EVENT_ID, 0, 1); + myRunner->Run(); + EXPECT_TRUE(CommonUtils::EventRunGet()); +} +} // unnamed namespace + +class EventHandlerSendEventModuleTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void EventHandlerSendEventModuleTest::SetUpTestCase(void) +{} + +void EventHandlerSendEventModuleTest::TearDownTestCase(void) +{} + +void EventHandlerSendEventModuleTest::SetUp(void) +{ + /** + * @tc.setup: Set the value of test flags to the default. + */ + CommonUtils::EventRunSet(false); + CommonUtils::EventRunCountReset(); +} + +void EventHandlerSendEventModuleTest::TearDown(void) +{} + +/** + * @tc.name: Send001 + * @tc.desc: Send event with delayTime = 0 and priority = LOW + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendEventModuleTest, Send001, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send event with delayTime and priority. + * @tc.expected: step1. Send successfully and the event handled. + */ + int64_t delayTime = 0; + SendAndCheck(delayTime, EventQueue::Priority::LOW); +} + +/** + * @tc.name: Send002 + * @tc.desc: Send event with delayTime > 0 and priority = LOW + * @tc.type: FUNC + * @tc.require: SR000CQ2AL SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendEventModuleTest, Send002, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send event with delayTime and priority. + * @tc.expected: step1. Send successfully and the event handled. + */ + int64_t delayTime = 1; + SendAndCheck(delayTime, EventQueue::Priority::LOW); +} + +/** + * @tc.name: Send003 + * @tc.desc: Send event with delayTime < 0 and priority = LOW + * @tc.type: FUNC + * @tc.require: AR000CQ2AD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendEventModuleTest, Send003, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send event with delayTime and priority. + * @tc.expected: step1. Send successfully and the event handled. + */ + int64_t delayTime = -1; + SendAndCheck(delayTime, EventQueue::Priority::LOW); +} + +/** + * @tc.name: Send004 + * @tc.desc: Send event with priority = HIGH + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendEventModuleTest, Send004, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send event with HIGH priority. + * @tc.expected: step1. Send successfully and the event handled. + */ + int64_t delayTime = 1; + SendAndCheck(delayTime, EventQueue::Priority::HIGH); +} + +/** + * @tc.name: Send005 + * @tc.desc: Send event with priority = IDLE + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendEventModuleTest, Send005, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send event with IDLE priority. + * @tc.expected: step1. Send successfully and the event handled. + */ + int64_t delayTime = 0; + auto event = InnerEvent::Get(RUN_EVENT_ID); + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + bool sendResult = handler->SendEvent(event, delayTime, EventQueue::Priority::IDLE); + EXPECT_TRUE(sendResult); + + auto f = [&myRunner]() { myRunner->Stop(); }; + handler->PostIdleTask(f, delayTime); + uint32_t newEventId = 1; + int64_t param = 0; + handler->SendEvent(newEventId, param, delayTime + 1); + myRunner->Run(); + bool runResult = CommonUtils::EventRunGet(); + EXPECT_TRUE(runResult); +} + +/** + * @tc.name: Send006 + * @tc.desc: Send event with delayTime and IMMEDIATE priority + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendEventModuleTest, Send006, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send event with delayTime and IMMEDIATE priority. + * @tc.expected: step1. Send successfully and the event handled. + */ + int64_t delayTime = 10; + SendAndCheck(delayTime, EventQueue::Priority::IMMEDIATE); +} + +/** + * @tc.name: Send007 + * @tc.desc: Send event with nullptr + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendEventModuleTest, Send007, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send event with nullptr. + * @tc.expected: step1. Send failed. + */ + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + auto nullPtr = InnerEvent::Pointer(nullptr, nullptr); + bool result = handler->SendEvent(nullPtr); + handler->SendEvent(STOP_EVENT_ID); + myRunner->Run(); + EXPECT_FALSE(result); +} + +/** + * @tc.name: Send008 + * @tc.desc: Send event without event runner + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendEventModuleTest, Send008, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send event without event runner. + * @tc.expected: step1. Send failed. + */ + uint32_t eventId = Random(); + int64_t param = 0; + int64_t delayTime = 0; + auto event = InnerEvent::Get(eventId, param); + auto handler = std::make_shared(nullptr); + bool result = handler->SendEvent(event, delayTime, EventQueue::Priority::LOW); + EXPECT_FALSE(result); +} + +/** + * @tc.name: Send009 + * @tc.desc: Send event with eventId, param and delayTime + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendEventModuleTest, Send009, TestSize.Level1) +{ + SendEventWithPriorityByEventId(EventQueue::Priority::LOW); +} + +/** + * @tc.name: Send010 + * @tc.desc: Send event with eventId, shared_ptr and delayTime + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendEventModuleTest, Send010, TestSize.Level1) +{ + SendEventWithSmartPtr(SmartPointerType::SHARED_PTR, EventQueue::Priority::LOW); +} + +/** + * @tc.name: Send011 + * @tc.desc: Send event with eventId, weak_ptr and delayTime + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendEventModuleTest, Send011, TestSize.Level1) +{ + SendEventWithSmartPtr(SmartPointerType::WEAK_PTR, EventQueue::Priority::LOW); +} + +/** + * @tc.name: Send012 + * @tc.desc: Send event with eventId, unique_ptr and delayTime + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendEventModuleTest, Send012, TestSize.Level1) +{ + SendEventWithSmartPtr(SmartPointerType::LVALUE_REFERENCE_UNIQUE_PTR, EventQueue::Priority::LOW); +} + +/** + * @tc.name: Send013 + * @tc.desc: Send event with eventId, rvalue reference unique_ptr and delayTime + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendEventModuleTest, Send013, TestSize.Level1) +{ + SendEventWithSmartPtr(SmartPointerType::RVALUE_REFERENCE_UNIQUE_PTR, EventQueue::Priority::LOW); +} + +/** + * @tc.name: SendHigh001 + * @tc.desc: Send high priority event + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendEventModuleTest, SendHigh001, TestSize.Level1) +{ + SendEventWithPriority(EventQueue::Priority::HIGH); +} + +/** + * @tc.name: SendHigh002 + * @tc.desc: Send high priority event with eventId, param and delayTime + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendEventModuleTest, SendHigh002, TestSize.Level1) +{ + SendEventWithPriorityByEventId(EventQueue::Priority::HIGH); +} + +/** + * @tc.name: SendHigh003 + * @tc.desc: Send high priority event with eventId, shared_ptr and delayTime + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendEventModuleTest, SendHigh003, TestSize.Level1) +{ + SendEventWithSmartPtr(SmartPointerType::SHARED_PTR, EventQueue::Priority::HIGH); +} + +/** + * @tc.name: SendHigh004 + * @tc.desc: Send high priority event with eventId, weak_ptr and delayTime + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendEventModuleTest, SendHigh004, TestSize.Level1) +{ + SendEventWithSmartPtr(SmartPointerType::WEAK_PTR, EventQueue::Priority::HIGH); +} + +/** + * @tc.name: SendHigh005 + * @tc.desc: Send high priority event with eventId, unique_ptr and delayTime + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendEventModuleTest, SendHigh005, TestSize.Level1) +{ + SendEventWithSmartPtr(SmartPointerType::LVALUE_REFERENCE_UNIQUE_PTR, EventQueue::Priority::HIGH); +} + +/** + * @tc.name: SendHigh006 + * @tc.desc: Send high priority event with eventId, rvalue reference unique_ptr and delayTime + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendEventModuleTest, SendHigh006, TestSize.Level1) +{ + SendEventWithSmartPtr(SmartPointerType::RVALUE_REFERENCE_UNIQUE_PTR, EventQueue::Priority::HIGH); +} + +/** + * @tc.name: SendImmediate001 + * @tc.desc: Send immediate priority event + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendEventModuleTest, SendImmediate001, TestSize.Level1) +{ + SendEventWithPriority(EventQueue::Priority::IMMEDIATE); +} + +/** + * @tc.name: SendImmediate002 + * @tc.desc: Send immediate priority event with eventId and param + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendEventModuleTest, SendImmediate002, TestSize.Level1) +{ + SendEventWithPriorityByEventId(EventQueue::Priority::IMMEDIATE); +} + +/** + * @tc.name: SendImmediate003 + * @tc.desc: Send immediate priority event with eventId, shared_ptr and delayTime + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendEventModuleTest, SendImmediate003, TestSize.Level1) +{ + SendEventWithSmartPtr(SmartPointerType::SHARED_PTR, EventQueue::Priority::IMMEDIATE); +} + +/** + * @tc.name: SendImmediate004 + * @tc.desc: Send immediate priority event with eventId, weak_ptr and delayTime + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendEventModuleTest, SendImmediate004, TestSize.Level1) +{ + SendEventWithSmartPtr(SmartPointerType::WEAK_PTR, EventQueue::Priority::IMMEDIATE); +} + +/** + * @tc.name: SendImmediate005 + * @tc.desc: Send immediate priority event with eventId, unique_ptr and delayTime + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendEventModuleTest, SendImmediate005, TestSize.Level1) +{ + SendEventWithSmartPtr(SmartPointerType::LVALUE_REFERENCE_UNIQUE_PTR, EventQueue::Priority::IMMEDIATE); +} + +/** + * @tc.name: SendImmediate006 + * @tc.desc: Send immediate priority event with eventId, rvalue reference unique_ptr and delayTime + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendEventModuleTest, SendImmediate006, TestSize.Level1) +{ + SendEventWithSmartPtr(SmartPointerType::RVALUE_REFERENCE_UNIQUE_PTR, EventQueue::Priority::IMMEDIATE); +} \ No newline at end of file diff --git a/libs/test/moduletest/common/event_handler/event_handler_send_sync_event_module_test.cpp b/libs/test/moduletest/common/event_handler/event_handler_send_sync_event_module_test.cpp new file mode 100644 index 000000000..88570c778 --- /dev/null +++ b/libs/test/moduletest/common/event_handler/event_handler_send_sync_event_module_test.cpp @@ -0,0 +1,391 @@ +/* + * 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 "event_handler_test_common.h" + +#include + +using namespace testing::ext; +using namespace OHOS::AppExecFwk; + +namespace { +const uint32_t MAX_RETRY_COUNT = 1000; +const uint32_t SLEEP_TIME = 1000; + +/** + * Function: Waiting for task run, the most waiting time is 1s. + * @param f Task callback. + * @param handler Event handler. + */ +template +void WaitTaskCalled(const F &f, const std::shared_ptr &handler) +{ + uint32_t count = 0; + if (handler->PostTask(f)) { + while (true) { + if (CommonUtils::EventRunGet()) { + break; + } + if (CommonUtils::TaskCalledGet()) { + break; + } + // If delay more than 1s, break + if (count >= MAX_RETRY_COUNT) { + break; + } + + usleep(SLEEP_TIME); + count++; + } + } +} + +/** + * Function: Send event with different shared pointer, and then check the processed result. + * @param smartPointerType One of smart pointer. + */ +void SendEventWithSmartPtr(SmartPointerType smartPointerType) +{ + auto myRunner = EventRunner::Create(); + auto handler = std::make_shared(myRunner); + auto sharedPtr = std::make_shared(1); + auto weakPtr = std::weak_ptr(sharedPtr); + auto f = [](int *intPtr) { delete intPtr; }; + auto uniquePtr = std::unique_ptr((new int(1)), f); + + int32_t result = 0; + auto task = [&handler, &result, &sharedPtr, &weakPtr, &uniquePtr, &f, smartPointerType]() { + switch (smartPointerType) { + case SmartPointerType::SHARED_PTR: { + result = handler->SendSyncEvent(RUN_EVENT_ID, sharedPtr); + break; + } + case SmartPointerType::WEAK_PTR: { + result = handler->SendSyncEvent(RUN_EVENT_ID, weakPtr); + break; + } + case SmartPointerType::LVALUE_REFERENCE_UNIQUE_PTR: { + result = handler->SendSyncEvent(RUN_EVENT_ID, uniquePtr); + break; + } + case SmartPointerType::RVALUE_REFERENCE_UNIQUE_PTR: { + result = handler->SendSyncEvent(RUN_EVENT_ID, std::unique_ptr((new int(1)), f)); + break; + } + default: + break; + } + }; + + WaitTaskCalled(task, handler); + + uint32_t count = 0; + while (true) { + if (result || (count >= MAX_RETRY_COUNT)) { + break; + } + usleep(SLEEP_TIME); + count++; + } + + EXPECT_EQ(1, result); +} +} // unnamed namespace + +class EventHandlerSendSyncEventModuleTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void EventHandlerSendSyncEventModuleTest::SetUpTestCase(void) +{} + +void EventHandlerSendSyncEventModuleTest::TearDownTestCase(void) +{} + +void EventHandlerSendSyncEventModuleTest::SetUp(void) +{ + /** + * @tc.setup: Set the value of flags to the default. + */ + CommonUtils::EventRunSet(false); + CommonUtils::TaskCalledSet(false); +} + +void EventHandlerSendSyncEventModuleTest::TearDown(void) +{} + +/** + * @tc.name: SendSync001 + * @tc.desc: Send null event + * @tc.type: FUNC + * @tc.require: AR000CQ2AF SR000BTOPM + */ +HWTEST_F(EventHandlerSendSyncEventModuleTest, SendSync001, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send a null event. + * @tc.expected: step1. Send failed. + */ + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + auto nullPtr = InnerEvent::Pointer(nullptr, nullptr); + bool result = handler->SendSyncEvent(nullPtr, EventQueue::Priority::LOW); + EXPECT_FALSE(result); +} + +/** + * @tc.name: SendSync002 + * @tc.desc: Send event with IDLE priority + * @tc.type: FUNC + * @tc.require: SR000CQ2A7 SR000BTOPM + */ +HWTEST_F(EventHandlerSendSyncEventModuleTest, SendSync002, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send an event with IDLE priority. + * @tc.expected: step1. Send failed, and event will not be run. + */ + auto event = InnerEvent::Get(RUN_EVENT_ID); + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + bool result = handler->SendSyncEvent(event, EventQueue::Priority::IDLE); + EXPECT_FALSE(result); + + bool runResult = CommonUtils::EventRunGet(); + EXPECT_FALSE(runResult); +} + +/** + * @tc.name: SendSync003 + * @tc.desc: Send non-null event with priority which not IDLE + * @tc.type: FUNC + * @tc.require: SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendSyncEventModuleTest, SendSync003, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send a non-idle priority event in a task. + * @tc.expected: step1. Send successfully, and event will be run. + */ + auto event = InnerEvent::Get(RUN_EVENT_ID); + auto myRunner = EventRunner::Create(); + auto handler = std::make_shared(myRunner); + + auto f = [&handler, &event]() { + bool result = handler->SendSyncEvent(event, EventQueue::Priority::IMMEDIATE); + EXPECT_TRUE(result); + }; + WaitTaskCalled(f, handler); + + bool runResult = CommonUtils::EventRunGet(); + EXPECT_TRUE(runResult); +} + +/** + * @tc.name: SendSync004 + * @tc.desc: Send non-null event with priority which not IDLE in new runner + * @tc.type: FUNC + * @tc.require: SR000CQ2AQ SR000BTOPM + */ +HWTEST_F(EventHandlerSendSyncEventModuleTest, SendSync004, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send an event with priority which not IDLE in new runner. + * @tc.expected: step1. Send successfully, and event will be run. + */ + auto event = InnerEvent::Get(RUN_EVENT_ID); + auto myRunner = EventRunner::Create(); + auto handler = std::make_shared(myRunner); + bool result = handler->SendSyncEvent(event, EventQueue::Priority::HIGH); + EXPECT_TRUE(result); + + bool runResult = CommonUtils::EventRunGet(); + EXPECT_TRUE(runResult); +} + +/** + * @tc.name: SendSync005 + * @tc.desc: Send r-value event with priority which not IDLE + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendSyncEventModuleTest, SendSync005, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send r-value event with priority which not IDLE in a task. + * @tc.expected: step1. Send successfully, the event will be run. + */ + auto event = InnerEvent::Get(RUN_EVENT_ID); + auto myRunner = EventRunner::Create(); + auto handler = std::make_shared(myRunner); + + auto f = [&handler]() { + bool rValueResult = handler->SendSyncEvent(InnerEvent::Get(RUN_EVENT_ID), EventQueue::Priority::LOW); + EXPECT_TRUE(rValueResult); + }; + WaitTaskCalled(f, handler); + + bool runResult = CommonUtils::EventRunGet(); + EXPECT_TRUE(runResult); +} + +/** + * @tc.name: SendSync006 + * @tc.desc: Send event with eventId, param and priority which not IDLE + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendSyncEventModuleTest, SendSync006, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send event in a task with eventId, param and priority which not IDLE. + * @tc.expected: step1. Send successfully, the event will be run. + */ + auto myRunner = EventRunner::Create(); + auto handler = std::make_shared(myRunner); + + auto f = [&handler]() { + bool result = handler->SendSyncEvent(RUN_EVENT_ID, 0); + EXPECT_TRUE(result); + }; + WaitTaskCalled(f, handler); + + bool runResult = CommonUtils::EventRunGet(); + EXPECT_TRUE(runResult); +} + +/** + * @tc.name: SendSync007 + * @tc.desc: Send event with eventId, shared_ptr object and priority which not IDLE + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendSyncEventModuleTest, SendSync007, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send event in a task with eventId, shared_ptr object and priority which not IDLE. + * @tc.expected: step1. Send successfully, the event will be run. + */ + SendEventWithSmartPtr(SmartPointerType::SHARED_PTR); + bool runResult = CommonUtils::EventRunGet(); + EXPECT_TRUE(runResult); +} + +/** + * @tc.name: SendSync008 + * @tc.desc: Send event with eventId, weak_ptr object and priority which not IDLE + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendSyncEventModuleTest, SendSync008, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send event in a task with eventId, weak_ptr object and priority which not IDLE. + * @tc.expected: step1. Send successfully, the event will be run. + */ + SendEventWithSmartPtr(SmartPointerType::WEAK_PTR); + bool runResult = CommonUtils::EventRunGet(); + EXPECT_TRUE(runResult); +} + +/** + * @tc.name: SendSync009 + * @tc.desc: Send event with eventId, unique_ptr object and priority which not IDLE + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendSyncEventModuleTest, SendSync009, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send event in a task with eventId, unique_ptr object and priority which not IDLE. + * @tc.expected: step1. Send successfully, the event will be run. + */ + SendEventWithSmartPtr(SmartPointerType::LVALUE_REFERENCE_UNIQUE_PTR); + bool runResult = CommonUtils::EventRunGet(); + EXPECT_TRUE(runResult); +} + +/** + * @tc.name: SendSync010 + * @tc.desc: Send event with eventId, rvalue reference unique_ptr object and priority which not IDLE + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendSyncEventModuleTest, SendSync010, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send event in a task with eventId, + * rvalue reference unique_ptr object and priority which not IDLE. + * @tc.expected: step1. Send successfully, the event will be run. + */ + SendEventWithSmartPtr(SmartPointerType::RVALUE_REFERENCE_UNIQUE_PTR); + bool runResult = CommonUtils::EventRunGet(); + EXPECT_TRUE(runResult); +} + +/** + * @tc.name: SendSync011 + * @tc.desc: Post task with callback, taskName and priority + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendSyncEventModuleTest, SendSync011, TestSize.Level1) +{ + /** + * @tc.steps: step1. Post task in another task with callback, taskName and priority. + * @tc.expected: step1. Post successfully, the task will be run. + */ + string taskName = "myTask"; + auto myTask = []() { CommonUtils::TaskCalledSet(true); }; + auto myRunner = EventRunner::Create(); + auto handler = std::make_shared(myRunner); + auto f = [&handler, &myTask, &taskName]() { + bool result = handler->PostSyncTask(myTask, taskName); + EXPECT_TRUE(result); + }; + WaitTaskCalled(f, handler); + + bool runResult = CommonUtils::TaskCalledGet(); + EXPECT_TRUE(runResult); +} + +/** + * @tc.name: SendSync012 + * @tc.desc: Post task with callback and priority + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSendSyncEventModuleTest, SendSync012, TestSize.Level1) +{ + /** + * @tc.steps: step1. Post task in another task with callback and priority. + * @tc.expected: step1. Post successfully, the task will be run. + */ + auto myTask = []() { CommonUtils::TaskCalledSet(true); }; + auto myRunner = EventRunner::Create(); + auto handler = std::make_shared(myRunner); + auto f = [&handler, &myTask]() { + bool result = handler->PostSyncTask(myTask, EventQueue::Priority::HIGH); + EXPECT_TRUE(result); + }; + WaitTaskCalled(f, handler); + + bool runResult = CommonUtils::TaskCalledGet(); + EXPECT_TRUE(runResult); +} \ No newline at end of file diff --git a/libs/test/moduletest/common/event_handler/event_handler_send_timing_event_module_test.cpp b/libs/test/moduletest/common/event_handler/event_handler_send_timing_event_module_test.cpp new file mode 100644 index 000000000..5caf61a7f --- /dev/null +++ b/libs/test/moduletest/common/event_handler/event_handler_send_timing_event_module_test.cpp @@ -0,0 +1,323 @@ +/* + * 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 "event_handler_test_common.h" +#include "event_handler_utils.h" + +#include + +using namespace testing::ext; +using namespace OHOS::AppExecFwk; + +namespace { +const uint32_t MAX_RETRY_COUNT = 2000; +const uint32_t SLEEP_TIME = 1000; + +int64_t GetNowSysTime() +{ + InnerEvent::TimePoint nowSys = InnerEvent::Clock::now(); + auto epoch = nowSys.time_since_epoch(); + auto value = std::chrono::duration_cast(epoch); + int64_t duration = value.count(); + return duration; +} + +/** + * Function: Waiting for task run, the most waiting time is 1s. + * @param f Task callback. + * @param handler Event handler. + */ +template +void WaitTaskCalled(const F &f, const std::shared_ptr &handler) +{ + int64_t nowTime = GetNowSysTime(); + int64_t delayTime = 1; + uint32_t count = 0; + if (handler->PostTimingTask(f, nowTime + delayTime)) { + while (true) { + if (CommonUtils::EventRunGet()) { + break; + } + if (CommonUtils::TaskCalledGet()) { + break; + } + // If delay more than 1s, break + if (count >= MAX_RETRY_COUNT) { + break; + } + usleep(SLEEP_TIME); + count++; + } + } +} + +/** + * Function: Send event with different shared pointer, and then check the processed result. + * @param smartPointerType One of smart pointer. + */ +void SendEventWithSmartPtr(SmartPointerType smartPointerType) +{ + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + auto sharedPtr = std::make_shared(1); + auto weakPtr = std::weak_ptr(sharedPtr); + auto f = [](int *intPtr) { delete intPtr; }; + auto uniquePtr = std::unique_ptr((new int(1)), f); + + int64_t nowTime = GetNowSysTime(); + int64_t delayTime = 10; + switch (smartPointerType) { + case SmartPointerType::SHARED_PTR: { + handler->SendTimingEvent(RUN_EVENT_ID, sharedPtr, nowTime + delayTime); + break; + } + case SmartPointerType::WEAK_PTR: { + handler->SendTimingEvent(RUN_EVENT_ID, weakPtr, nowTime + delayTime); + break; + } + case SmartPointerType::LVALUE_REFERENCE_UNIQUE_PTR: { + handler->SendTimingEvent(RUN_EVENT_ID, uniquePtr, nowTime + delayTime); + break; + } + case SmartPointerType::RVALUE_REFERENCE_UNIQUE_PTR: { + handler->SendTimingEvent( + RUN_EVENT_ID, std::unique_ptr((new int(1)), f), nowTime + delayTime); + break; + } + default: + break; + } + handler->SendTimingEvent(STOP_EVENT_ID, delayTime + delayTime + nowTime); + myRunner->Run(); + + bool runResult = CommonUtils::EventRunGet(); + EXPECT_TRUE(runResult); +} +} // unnamed namespace + +class EventHandlerSendTimingEventModuleTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void EventHandlerSendTimingEventModuleTest::SetUpTestCase(void) +{} + +void EventHandlerSendTimingEventModuleTest::TearDownTestCase(void) +{} + +void EventHandlerSendTimingEventModuleTest::SetUp(void) +{ + /** + * @tc.setup: Set the value of flags to the default. + */ + CommonUtils::EventRunSet(false); + CommonUtils::EventRunCountReset(); + CommonUtils::TaskCalledSet(false); +} + +void EventHandlerSendTimingEventModuleTest::TearDown(void) +{} + +/** + * @tc.name: SendTiming001 + * @tc.desc: Send null event + * @tc.type: FUNC + * @tc.require: SR000DPU9L AR000DPVJS + */ +HWTEST_F(EventHandlerSendTimingEventModuleTest, SendTiming001, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send a null event. + * @tc.expected: step1. Send failed. + */ + int64_t nowTime = GetNowSysTime(); + int64_t delayTime = 2; + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + auto nullPtr = InnerEvent::Pointer(nullptr, nullptr); + bool result = handler->SendTimingEvent(nullPtr, nowTime + delayTime, EventQueue::Priority::LOW); + EXPECT_FALSE(result); +} + +/** + * @tc.name: SendTiming002 + * @tc.desc: Send r-value event with event and event id + * @tc.type: FUNC + * @tc.require: SR000DPU9L AR000DPVJS + */ +HWTEST_F(EventHandlerSendTimingEventModuleTest, SendTiming002, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send r-value event with priority which not IDLE in a task. + * @tc.expected: step1. Send successfully, the event will be run. + */ + int64_t nowTime = GetNowSysTime(); + int64_t delayTime = 10; + auto event = InnerEvent::Get(RUN_EVENT_ID); + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + handler->SendTimingEvent(event, delayTime + nowTime); + handler->SendTimingEvent(STOP_EVENT_ID, delayTime * 2 + nowTime); + myRunner->Run(); + + uint32_t runResult = 1; + EXPECT_EQ(runResult, CommonUtils::EventRunCount()); +} + +/** + * @tc.name: SendTiming003 + * @tc.desc: Send r-value event with event, event id and priority + * @tc.type: FUNC + * @tc.require: SR000DPU9L AR000DPVJS + */ +HWTEST_F(EventHandlerSendTimingEventModuleTest, SendTiming003, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send r-value event with priority which not IDLE in a task. + * @tc.expected: step1. Send successfully, the event will be run. + */ + int64_t nowTime = GetNowSysTime(); + int64_t delayTime = 10; + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + handler->SendTimingEvent(RUN_EVENT_ID, delayTime + nowTime, EventQueue::Priority::LOW); + handler->SendTimingEvent(STOP_EVENT_ID, delayTime * 2 + nowTime); + myRunner->Run(); + + uint32_t runResult = 1; + EXPECT_EQ(runResult, CommonUtils::EventRunCount()); +} + +/** + * @tc.name: SendTiming004 + * @tc.desc: Send r-value event with event, event id and param + * @tc.type: FUNC + * @tc.require: SR000DPU9L AR000DPVJS + */ +HWTEST_F(EventHandlerSendTimingEventModuleTest, SendTiming004, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send r-value event with priority which not IDLE in a task. + * @tc.expected: step1. Send successfully, the event will be run. + */ + int64_t nowTime = GetNowSysTime(); + int64_t delayTime = 10; + auto event = InnerEvent::Get(RUN_EVENT_ID); + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + handler->SendTimingEvent(RUN_EVENT_ID, delayTime + nowTime, 1); + handler->SendTimingEvent(STOP_EVENT_ID, delayTime * 2 + nowTime); + myRunner->Run(); + + uint32_t runResult = 1; + EXPECT_EQ(runResult, CommonUtils::EventRunCount()); +} +/** + * @tc.name: SendTiming005 + * @tc.desc: Send event with eventId, shared_ptr object and priority which not IDLE + * @tc.type: FUNC + * @tc.require: SR000DPU9L AR000DPVJS + */ +HWTEST_F(EventHandlerSendTimingEventModuleTest, SendTiming005, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send event in a task with eventId, shared_ptr object and priority which not IDLE. + * @tc.expected: step1. Send successfully, the event will be run. + */ + SendEventWithSmartPtr(SmartPointerType::SHARED_PTR); + bool runResult = CommonUtils::EventRunGet(); + EXPECT_TRUE(runResult); +} + +/** + * @tc.name: SendTiming006 + * @tc.desc: Send event with eventId, weak_ptr object and priority which not IDLE + * @tc.type: FUNC + * @tc.require: SR000DPU9L AR000DPVJS + */ +HWTEST_F(EventHandlerSendTimingEventModuleTest, SendTiming006, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send event in a task with eventId, weak_ptr object and priority which not IDLE. + * @tc.expected: step1. Send successfully, the event will be run. + */ + SendEventWithSmartPtr(SmartPointerType::WEAK_PTR); + bool runResult = CommonUtils::EventRunGet(); + EXPECT_TRUE(runResult); +} + +/** + * @tc.name: SendTiming007 + * @tc.desc: Send event with eventId, unique_ptr object and priority which not IDLE + * @tc.type: FUNC + * @tc.require: SR000DPU9L AR000DPVJS + */ +HWTEST_F(EventHandlerSendTimingEventModuleTest, SendTiming007, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send event in a task with eventId, unique_ptr object and priority which not IDLE. + * @tc.expected: step1. Send successfully, the event will be run. + */ + SendEventWithSmartPtr(SmartPointerType::LVALUE_REFERENCE_UNIQUE_PTR); + bool runResult = CommonUtils::EventRunGet(); + EXPECT_TRUE(runResult); +} + +/** + * @tc.name: SendTiming008 + * @tc.desc: Send event with eventId, rvalue reference unique_ptr object and priority which not IDLE + * @tc.type: FUNC + * @tc.require: SR000DPU9L AR000DPVJS + */ +HWTEST_F(EventHandlerSendTimingEventModuleTest, SendTiming008, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send event in a task with eventId, + * rvalue reference unique_ptr object and priority which not IDLE. + * @tc.expected: step1. Send successfully, the event will be run. + */ + SendEventWithSmartPtr(SmartPointerType::RVALUE_REFERENCE_UNIQUE_PTR); + bool runResult = CommonUtils::EventRunGet(); + EXPECT_TRUE(runResult); +} + +/** + * @tc.name: SendTiming009 + * @tc.desc: Send r-value event with event, event id and param at past time + * @tc.type: FUNC + * @tc.require: SR000DPU9L AR000DPVJS + */ +HWTEST_F(EventHandlerSendTimingEventModuleTest, SendTiming009, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send r-value event with priority which not IDLE in a task. + * @tc.expected: step1. Send successfully, the event will be run. + */ + int64_t nowTime = GetNowSysTime(); + int64_t delayTime = 10; + auto event = InnerEvent::Get(RUN_EVENT_ID); + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + handler->SendTimingEvent(RUN_EVENT_ID, nowTime - delayTime, 1); + handler->SendTimingEvent(STOP_EVENT_ID, delayTime + nowTime); + myRunner->Run(); + + uint32_t runResult = 1; + EXPECT_EQ(runResult, CommonUtils::EventRunCount()); +} diff --git a/libs/test/moduletest/common/event_handler/event_handler_set_get_remove_module_test.cpp b/libs/test/moduletest/common/event_handler/event_handler_set_get_remove_module_test.cpp new file mode 100644 index 000000000..0af5b7ace --- /dev/null +++ b/libs/test/moduletest/common/event_handler/event_handler_set_get_remove_module_test.cpp @@ -0,0 +1,448 @@ +/* + * 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 "event_handler_test_common.h" + +#include + +using namespace testing::ext; +using namespace OHOS::AppExecFwk; + +class EventHandlerSetGetRemoveModuleTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void EventHandlerSetGetRemoveModuleTest::SetUpTestCase(void) +{} + +void EventHandlerSetGetRemoveModuleTest::TearDownTestCase(void) +{} + +void EventHandlerSetGetRemoveModuleTest::SetUp(void) +{ + /** + * @tc.setup: Set the value of flags to the default. + */ + CommonUtils::EventRunSet(false); + CommonUtils::TaskCalledSet(false); +} + +void EventHandlerSetGetRemoveModuleTest::TearDown(void) +{} + +/** + * @tc.name: SetRunner001 + * @tc.desc: Set the EventRunner for the EventHandler + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSetGetRemoveModuleTest, SetRunner001, TestSize.Level1) +{ + /** + * @tc.steps: step1. Set the event runner for current handler. + * @tc.expected: step1. Set successfully and the event can be send. + */ + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(nullptr); + handler->SetEventRunner(myRunner); + bool result = handler->SendEvent(STOP_EVENT_ID); + myRunner->Run(); + EXPECT_TRUE(result); +} + +/** + * @tc.name: SetRunner002 + * @tc.desc: Set a null EventRunner for the EventHandler + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSetGetRemoveModuleTest, SetRunner002, TestSize.Level1) +{ + /** + * @tc.steps: step1. Set a null event runner for current handler. + * @tc.expected: step1. Set failed and the event can not be send. + */ + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + handler->SetEventRunner(nullptr); + bool allowSend = handler->SendEvent(Random()); + EXPECT_FALSE(allowSend); +} + +/** + * @tc.name: GetRunner001 + * @tc.desc: Get the EventRunner of the EventHandler + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSetGetRemoveModuleTest, GetRunner001, TestSize.Level1) +{ + /** + * @tc.steps: step1. Get the event runner of current handler. + * @tc.expected: step1. The got runner has the same addr as created runner. + */ + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + auto currentRunner = handler->GetEventRunner(); + EXPECT_EQ(myRunner, currentRunner); +} + +/** + * @tc.name: GetRunner002 + * @tc.desc: Get a null EventRunner of the EventHandler + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSetGetRemoveModuleTest, GetRunner002, TestSize.Level1) +{ + /** + * @tc.steps: step1. Get the event runner of handler which not loaded the runner. + * @tc.expected: step1. Return a nullptr. + */ + auto handler = std::make_shared(nullptr); + auto currentRunner = handler->GetEventRunner(); + EXPECT_EQ(nullptr, currentRunner); +} + +/** + * @tc.name: DistributeEvent001 + * @tc.desc: Distribute an event + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSetGetRemoveModuleTest, DistributeEvent001, TestSize.Level1) +{ + /** + * @tc.steps: step1. Create and distribute the event. + * @tc.expected: step1. Distribute successfully and the event handled. + */ + auto event = InnerEvent::Get(RUN_EVENT_ID); + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + + handler->DistributeEvent(event); + bool result = CommonUtils::EventRunGet(); + EXPECT_TRUE(result); +} + +/** + * @tc.name: DistributeEvent002 + * @tc.desc: Distribute a task + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSetGetRemoveModuleTest, DistributeEvent002, TestSize.Level1) +{ + /** + * @tc.steps: step1. Create and distribute the task. + * @tc.expected: step1. Distribute successfully and the task executed. + */ + auto f = []() { CommonUtils::TaskCalledSet(true); }; + auto event = InnerEvent::Get(f); + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + + handler->DistributeEvent(event); + bool result = CommonUtils::TaskCalledGet(); + EXPECT_TRUE(result); +} + +/** + * @tc.name: DistributeEvent003 + * @tc.desc: Distribute a null event + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSetGetRemoveModuleTest, DistributeEvent003, TestSize.Level1) +{ + /** + * @tc.steps: step1. Distribute a null event. + * @tc.expected: step1. Distribute failed and the event not handled. + */ + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + auto nullPtr = InnerEvent::Pointer(nullptr, nullptr); + + handler->DistributeEvent(nullPtr); + bool result = CommonUtils::EventRunGet(); + EXPECT_FALSE(result); +} + +/** + * @tc.name: CurrentHandler001 + * @tc.desc: Get current handler when handler running + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSetGetRemoveModuleTest, CurrentHandler001, TestSize.Level1) +{ + /** + * @tc.steps: step1. Get current handler when handler running. + * @tc.expected: step1. Get successfully and the same as created handler. + */ + auto myRunner = EventRunner::Create(); + auto handler = std::make_shared(myRunner); + std::shared_ptr myHandler; + auto f = [&myHandler, &handler]() { myHandler = handler->Current(); }; + + handler->PostTask(f); + uint32_t sleepTime = 20000; + usleep(sleepTime); + EXPECT_EQ(handler, myHandler); +} + +/** + * @tc.name: CurrentHandler002 + * @tc.desc: Get current handler when handler not running + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSetGetRemoveModuleTest, CurrentHandler002, TestSize.Level1) +{ + /** + * @tc.steps: step1. Get current handler when handler not running. + * @tc.expected: step1. Return a nullptr. + */ + auto myRunner = EventRunner::Create(); + auto handler = std::make_shared(myRunner); + std::shared_ptr myHandler = handler->Current(); + + EXPECT_EQ(nullptr, myHandler); +} + +/** + * @tc.name: CurrentHandler003 + * @tc.desc: Get current handler when running in different handler + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSetGetRemoveModuleTest, CurrentHandler003, TestSize.Level1) +{ + /** + * @tc.steps: step1. Get current handler when handler running in different handler. + * @tc.expected: step1. Get successfully and the same as created handler. + */ + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + std::shared_ptr myHandler; + auto f = [&handler, &myHandler]() { + auto inRunner = EventRunner::Create(false); + auto inHandler = std::make_shared(inRunner); + auto fIn = [&inHandler]() { EXPECT_EQ(inHandler, inHandler->Current()); }; + inHandler->PostTask(fIn); + inHandler->SendEvent(STOP_EVENT_ID); + inRunner->Run(); + myHandler = handler->Current(); + }; + + handler->PostTask(f); + handler->SendEvent(STOP_EVENT_ID); + myRunner->Run(); + EXPECT_EQ(handler, myHandler); +} + +/** + * @tc.name: Remove001 + * @tc.desc: Remove all events + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSetGetRemoveModuleTest, Remove001, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send multi events to event queue. + */ + int64_t delayTime = 0; + uint32_t taskCalledCount = 0; + uint32_t expectResult = 0; + auto f = [&taskCalledCount]() { taskCalledCount++; }; + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + + for (uint32_t i = 0; i < 2; ++i) { + handler->PostTask(f, delayTime, EventQueue::Priority::HIGH); + delayTime++; + } + + /** + * @tc.steps: step2. Remove all events, and run the runner. + * @tc.expected: step2. Remove successfully and no event run. + */ + handler->RemoveAllEvents(); + int64_t param = 0; + int64_t offsetTime = 3; + handler->SendEvent(STOP_EVENT_ID, param, delayTime + offsetTime); + myRunner->Run(); + EXPECT_EQ(expectResult, taskCalledCount); +} + +/** + * @tc.name: Remove002 + * @tc.desc: Remove all events without runner + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSetGetRemoveModuleTest, Remove002, TestSize.Level1) +{ + /** + * @tc.steps: step1. Remove all events without runner. + * @tc.expected: step1. Remove failed. + */ + auto handler = std::make_shared(nullptr); + handler->RemoveAllEvents(); + bool result = handler->SendEvent(RUN_EVENT_ID); + EXPECT_FALSE(result); +} + +/** + * @tc.name: Remove003 + * @tc.desc: Remove an event by eventId + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSetGetRemoveModuleTest, Remove003, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send event to event queue. + */ + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + handler->SendEvent(RUN_EVENT_ID); + + /** + * @tc.steps: step2. Remove the event by eventId. + * @tc.expected: step2. Remove successfully and removed event not run. + */ + handler->RemoveEvent(RUN_EVENT_ID); + handler->SendEvent(STOP_EVENT_ID); + myRunner->Run(); + bool result = CommonUtils::EventRunGet(); + EXPECT_FALSE(result); +} + +/** + * @tc.name: Remove004 + * @tc.desc: Remove an event by eventId without runner + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSetGetRemoveModuleTest, Remove004, TestSize.Level1) +{ + /** + * @tc.steps: step1. Remove an event by eventId without runner. + * @tc.expected: step1. Remove failed. + */ + auto handler = std::make_shared(nullptr); + handler->RemoveEvent(Random()); + bool result = handler->SendEvent(RUN_EVENT_ID); + EXPECT_FALSE(result); +} + +/** + * @tc.name: Remove005 + * @tc.desc: Remove an event by eventId and param + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSetGetRemoveModuleTest, Remove005, TestSize.Level1) +{ + /** + * @tc.steps: step1. Send event to event queue. + */ + int64_t param = 0; + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + handler->SendEvent(RUN_EVENT_ID, param, 0); + + /** + * @tc.steps: step2. Remove the event by eventId and param. + * @tc.expected: step2. Remove successfully and removed event not run. + */ + handler->RemoveEvent(RUN_EVENT_ID, param); + handler->SendEvent(STOP_EVENT_ID); + myRunner->Run(); + bool result = CommonUtils::EventRunGet(); + EXPECT_FALSE(result); +} + +/** + * @tc.name: Remove006 + * @tc.desc: Remove an event by eventId and param without runner + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSetGetRemoveModuleTest, Remove006, TestSize.Level1) +{ + /** + * @tc.steps: step1. Remove an event by eventId and param without runner. + * @tc.expected: step1. Remove failed. + */ + int64_t param = 0; + auto handler = std::make_shared(nullptr); + handler->RemoveEvent(Random(), param); + bool result = handler->SendEvent(RUN_EVENT_ID); + EXPECT_FALSE(result); +} + +/** + * @tc.name: Remove007 + * @tc.desc: Remove a task by name + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSetGetRemoveModuleTest, Remove007, TestSize.Level1) +{ + /** + * @tc.steps: step1. Post a task to event queue. + */ + string taskName = std::to_string(Random()); + auto f = []() { CommonUtils::TaskCalledSet(true); }; + auto myRunner = EventRunner::Create(false); + auto handler = std::make_shared(myRunner); + handler->PostTask(f, taskName); + + /** + * @tc.steps: step2. Remove the task by name. + * @tc.expected: step2. Remove successfully and removed task not run. + */ + handler->RemoveTask(taskName); + handler->SendEvent(STOP_EVENT_ID); + myRunner->Run(); + bool result = CommonUtils::TaskCalledGet(); + EXPECT_FALSE(result); +} + +/** + * @tc.name: Remove008 + * @tc.desc: Remove a task by name without runner + * @tc.type: FUNC + * @tc.require: SR000BTOPD SR000BTOPJ SR000BTOPM + */ +HWTEST_F(EventHandlerSetGetRemoveModuleTest, Remove008, TestSize.Level1) +{ + /** + * @tc.steps: step1. Remove a task by name without runner. + * @tc.expected: step1. Remove failed. + */ + string taskName = std::to_string(Random()); + auto handler = std::make_shared(nullptr); + handler->RemoveTask(taskName); + bool result = handler->SendEvent(RUN_EVENT_ID); + EXPECT_FALSE(result); +} diff --git a/libs/test/moduletest/common/event_handler/event_handler_test_common.cpp b/libs/test/moduletest/common/event_handler/event_handler_test_common.cpp new file mode 100644 index 000000000..fa0c76ce4 --- /dev/null +++ b/libs/test/moduletest/common/event_handler/event_handler_test_common.cpp @@ -0,0 +1,43 @@ +/* + * 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 "event_handler_test_common.h" + +namespace OHOS { +namespace AppExecFwk { +std::atomic CommonUtils::eventRun_ {false}; +std::atomic CommonUtils::taskCalled_ {false}; +std::atomic CommonUtils::eventRunTimes_ {0}; + +MyEventHandler::MyEventHandler(const std::shared_ptr &runner) : EventHandler(runner) +{} + +MyEventHandler::~MyEventHandler() +{} + +void MyEventHandler::ProcessEvent(const InnerEvent::Pointer &event) +{ + auto eventId = event->GetInnerEventId(); + if (eventId == STOP_EVENT_ID) { + GetEventRunner()->Stop(); + } + + if (eventId == RUN_EVENT_ID) { + CommonUtils::EventRunSet(true); + CommonUtils::EventRunCountIncrement(); + } +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/libs/test/moduletest/common/event_handler/event_handler_test_common.h b/libs/test/moduletest/common/event_handler/event_handler_test_common.h new file mode 100644 index 000000000..e776f4f11 --- /dev/null +++ b/libs/test/moduletest/common/event_handler/event_handler_test_common.h @@ -0,0 +1,132 @@ +/* + * 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_LIBS_TEST_MODULETEST_COMMON_EVENT_HANDLER_EVENT_HANDLER_TEST_COMMON_H +#define FOUNDATION_APPEXECFWK_LIBS_TEST_MODULETEST_COMMON_EVENT_HANDLER_EVENT_HANDLER_TEST_COMMON_H + +#include + +#include "nocopyable.h" + +#include "event_handler.h" +#include "event_runner.h" + +namespace OHOS { +namespace AppExecFwk { +const uint32_t STOP_EVENT_ID = 0; +const uint32_t RUN_EVENT_ID = 10; + +/** + * Function: Create random number for uint32_t type. + */ +inline uint32_t Random() +{ + return static_cast(std::rand()); +} + +enum class SmartPointerType { + SHARED_PTR = 0, + WEAK_PTR, + LVALUE_REFERENCE_UNIQUE_PTR, + RVALUE_REFERENCE_UNIQUE_PTR, +}; + +class CommonUtils { +public: + CommonUtils() = delete; + ~CommonUtils() = delete; + DISALLOW_COPY_AND_MOVE(CommonUtils); + + /** + * Function: Get the processed result of event. + * @return Returns true if event has been processed. + */ + static inline bool EventRunGet() + { + return eventRun_.load(); + } + + /** + * Function: Set the processed result of event. + * @param run Set false or true for processed result. + */ + static inline void EventRunSet(bool run) + { + eventRun_.store(run); + } + + /** + * Function: Get the called result of task. + * @return Returns true if task has been called. + */ + static inline bool TaskCalledGet() + { + return taskCalled_.load(); + } + + /** + * Function: Set the called result of task. + * @param run Set false or true for called result. + */ + static inline void TaskCalledSet(bool called) + { + taskCalled_.store(called); + } + + /** + * Function: Get the processed times of event. + * @return Returns processed times. + */ + static inline uint32_t EventRunCount() + { + return eventRunTimes_; + } + + /** + * Function: Increment of event processed times. + */ + static inline void EventRunCountIncrement() + { + eventRunTimes_++; + } + + /** + * Function: Reset the count of event processed to 0. + */ + static inline void EventRunCountReset() + { + eventRunTimes_ = 0; + } + +private: + static std::atomic eventRun_; + static std::atomic taskCalled_; + static std::atomic eventRunTimes_; +}; + +class MyEventHandler : public EventHandler { +public: + explicit MyEventHandler(const std::shared_ptr &runner); + ~MyEventHandler(); + + /** + * Function: Process the event. Override the method of base class. + * @param event The event need to be processed. + */ + void ProcessEvent(const InnerEvent::Pointer &event) override; +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // #ifndef FOUNDATION_APPEXECFWK_LIBS_TEST_MODULETEST_COMMON_EVENT_HANDLER_EVENT_HANDLER_TEST_COMMON_H \ No newline at end of file diff --git a/ohos.build b/ohos.build new file mode 100644 index 000000000..9565276fc --- /dev/null +++ b/ohos.build @@ -0,0 +1,93 @@ +{ + "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" + ], + + "variants": [ + "phone", + "ivi" + ] + } + }, + "subsystem": "appexecfwk" +} diff --git a/sa_profile/401.xml b/sa_profile/401.xml new file mode 100644 index 000000000..49afb6897 --- /dev/null +++ b/sa_profile/401.xml @@ -0,0 +1,27 @@ + + + + foundation + + 401 + /system/lib64/libbms.z.so + + + true + false + 1 + + diff --git a/sa_profile/501.xml b/sa_profile/501.xml new file mode 100644 index 000000000..5ea1be2db --- /dev/null +++ b/sa_profile/501.xml @@ -0,0 +1,27 @@ + + + + foundation + + 501 + /system/lib64/libams.z.so + + + true + false + 1 + + diff --git a/sa_profile/BUILD.gn b/sa_profile/BUILD.gn new file mode 100644 index 000000000..a7a99a086 --- /dev/null +++ b/sa_profile/BUILD.gn @@ -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. + +import("//build/ohos.gni") +import("//build/ohos/sa_profile/sa_profile.gni") + +ohos_sa_profile("appexecfwk_sa_profile") { + sources = [ + "401.xml", + "501.xml", + ] + + part_name = "appexecfwk_standard" +} + +ohos_prebuilt_etc("foundation.rc") { + source = "foundation.rc" + relative_install_dir = "init" + subsystem_name = "appexecfwk" + part_name = "appexecfwk_standard" +} diff --git a/sa_profile/foundation.rc b/sa_profile/foundation.rc new file mode 100755 index 000000000..f49c74ac1 --- /dev/null +++ b/sa_profile/foundation.rc @@ -0,0 +1,28 @@ +# 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. + +on boot + # Add permision for powermanager to control suspend + # It should be executed before foundation started + # because powermanager will run in foundation process + chown radio system /sys/power/wake_lock + chown radio system /sys/power/wake_unlock + chmod 0664 /sys/power/wakeup_count + start foundation + +service foundation /system/bin/sa_main /system/profile/foundation.xml + class foundation + priority -20 + user system + group system + seclabel u:r:foundation:s0 diff --git a/services/BUILD.gn b/services/BUILD.gn new file mode 100644 index 000000000..03d564f61 --- /dev/null +++ b/services/BUILD.gn @@ -0,0 +1,19 @@ +# 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. + +group("services_target") { + deps = [ + "appmgr:ams_target", + "bundlemgr:bms_target", + ] +} diff --git a/services/appmgr/BUILD.gn b/services/appmgr/BUILD.gn new file mode 100644 index 000000000..b6095232f --- /dev/null +++ b/services/appmgr/BUILD.gn @@ -0,0 +1,90 @@ +# 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("appmgr_config") { + include_dirs = [ + "include", + "${appspawn_path}/include", + "//utils/system/safwk/native/include", + ] +} + +group("ams_target") { + deps = [ + ":libams", + "examples:appmgrserviceregtest", + "examples:appspawnclienttest", + ] +} + +ohos_shared_library("libams") { + sources = [ + "src/ability_running_record.cpp", + "src/ams_mgr_scheduler.cpp", + "src/app_death_recipient.cpp", + "src/app_lifecycle_deal.cpp", + "src/app_mgr_service.cpp", + "src/app_mgr_service_event_handler.cpp", + "src/app_mgr_service_inner.cpp", + "src/app_process_manager.cpp", + "src/app_running_manager.cpp", + "src/app_running_record.cpp", + "src/app_spawn_client.cpp", + "src/app_spawn_msg_wrapper.cpp", + "src/app_spawn_socket.cpp", + "src/cgroup_manager.cpp", + "src/lmk_util.cpp", + "src/lmkd_client.cpp", + "src/process_optimizer.cpp", + "src/process_optimizer_uba.cpp", + "src/remote_client_manager.cpp", + ] + + defines = [ + "APP_LOG_TAG = \"AppMgrService\"", + "LOG_DOMAIN = 0xD001110", + ] + + configs = [ + ":appmgr_config", + "${libs_path}/libeventhandler:libeventhandler_config", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appmgr_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/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", + ] + + subsystem_name = "appexecfwk" + part_name = "appexecfwk_standard" +} diff --git a/services/appmgr/examples/BUILD.gn b/services/appmgr/examples/BUILD.gn new file mode 100644 index 000000000..0b8c62ae3 --- /dev/null +++ b/services/appmgr/examples/BUILD.gn @@ -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. + +import("//build/ohos.gni") + +ohos_executable("appspawnclienttest") { + sources = [ "app_spawn_client_test/main.cpp" ] + + configs = [ + ":test_config", + "//foundation/appexecfwk/standard/libs/libeventhandler:libeventhandler_config", + ] + + deps = [ + #"startup:appspawn_jni", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "//foundation/appexecfwk/standard/services/appmgr:libams", + ] +} + +ohos_executable("appmgrserviceregtest") { + sources = [ "app_mgr_service_register_test/main_client.cpp" ] + + configs = [ + ":test_config", + "//foundation/appexecfwk/standard/libs/libeventhandler:libeventhandler_config", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core:appmgr_sdk_config", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base:appexecfwk_base_sdk_config", + "//utils/native/base:utils_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "//foundation/appexecfwk/standard/services/appmgr:libams", + + #"startup:appspawn_jni", + "//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", + ] +} + +config("test_config") { + # header file path + include_dirs = [ + "//foundation/appexecfwk/standard/interfaces", + "//foundation/appexecfwk/standard/services/appmgr/include", + "//foundation/appexecfwk/standard/services/common/include", + ] + + # enable exception + cflags_cc = [ "-fexceptions" ] + + configs = [ "//foundation/appexecfwk/standard/services/appmgr:appmgr_config" ] +} diff --git a/services/appmgr/examples/app_mgr_service_register_test/main_client.cpp b/services/appmgr/examples/app_mgr_service_register_test/main_client.cpp new file mode 100644 index 000000000..3b25dd2bf --- /dev/null +++ b/services/appmgr/examples/app_mgr_service_register_test/main_client.cpp @@ -0,0 +1,44 @@ +/* + * 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 "if_system_ability_manager.h" +#include "system_ability_definition.h" +#include "iservice_registry.h" +#include "ipc_skeleton.h" +#include "app_mgr_interface.h" + +using namespace OHOS; +using namespace OHOS::AppExecFwk; + +int main() +{ + sptr systemAbilityManager = + SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (!systemAbilityManager) { + printf("fail to get systemAbilityMgr!"); + return -1; + } + sptr object = systemAbilityManager->GetSystemAbility(APP_MGR_SERVICE_ID); + if (!object) { + printf("fail to get service: AppMgrService!"); + return -1; + } + sptr appMgr = iface_cast(object); + appMgr->ApplicationForegrounded(0); + + IPCSkeleton::JoinWorkThread(); +} \ No newline at end of file diff --git a/services/appmgr/examples/app_spawn_client_test/main.cpp b/services/appmgr/examples/app_spawn_client_test/main.cpp new file mode 100644 index 000000000..b3dfb86a4 --- /dev/null +++ b/services/appmgr/examples/app_spawn_client_test/main.cpp @@ -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. + */ + +#include + +#include "app_spawn_client.h" + +using OHOS::AppExecFwk::AppSpawnClient; +using OHOS::AppExecFwk::AppSpawnStartMsg; + +int main() +{ + std::shared_ptr service = std::make_shared(); + AppSpawnStartMsg startMsg = {0, 0, {0}, "test", "test"}; + pid_t pid = 0; + service->StartProcess(startMsg, pid); + printf("AppSpawnClientTest end with new PID : %d", pid); + return 0; +} diff --git a/services/appmgr/include/ability_running_record.h b/services/appmgr/include/ability_running_record.h new file mode 100644 index 000000000..b382d45f9 --- /dev/null +++ b/services/appmgr/include/ability_running_record.h @@ -0,0 +1,162 @@ +/* + * 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_APPMGR_INCLUDE_ABILITY_RUNNING_RECORD_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_ABILITY_RUNNING_RECORD_H + +#include + +#include "iremote_object.h" + +#include "ability_info.h" +#include "application_info.h" +#include "app_mgr_constants.h" + +namespace OHOS { +namespace AppExecFwk { + +class AbilityRunningRecord { +public: + AbilityRunningRecord(const std::shared_ptr &info, const sptr &token); + virtual ~AbilityRunningRecord(); + + /** + * @brief Obtains the name of the ability. + * + * @return Returns the ability name. + */ + const std::string &GetName() const; + + /** + * @brief Obtains the info of the ability. + * + * @return Returns the ability info. + */ + const std::shared_ptr &GetAbilityInfo() const; + + /** + * @brief Obtains the token of the ability. + * + * @return Returns the ability token. + */ + const sptr &GetToken() const; + + /** + * @brief Setting id for ability record. + * + * @param appId, the ability record id. + */ + void SetAppRunningRecordId(const int32_t appId); + + /** + * @brief Setting state for ability record. + * + * @param state, the ability record state. + */ + void SetState(const AbilityState state); + + /** + * @brief Obtains the state of the ability. + * + * @return Returns the ability state. + */ + AbilityState GetState() const; + + /** + * @brief Judge whether the ability status is the same. + * + * @param state, the ability state. + * + * @return Returns If true is returned, the ID will be the same, otherwise it fails. + */ + bool IsSameState(const AbilityState state) const; + + /** + * @brief Obtains the last launch time of the ability record. + * + * @return Returns the last launch time. + */ + int32_t GetLastLaunchTime() const; + + /** + * @brief Setting the unique identification to call the ability. + * + * @param preToken, the unique identification to call the ability. + */ + void SetPreToken(const sptr &preToken); + + /** + * @brief Obtains the unique identification to call the ability. + * + * @return Returns the unique identification to call the ability. + */ + const sptr GetPreToken() const; + + /** + * @brief Setting the visibility to ability. + * + * @param preToken, the visibility to ability. + */ + void SetVisibility(const int32_t visibility); + + /** + * @brief Obtains the visibility to ability. + * + * @return Returns the visibility to ability. + */ + int32_t GetVisibility() const; + + /** + * @brief Setting the perceptibility to ability. + * + * @param preToken, the perceptibility to ability. + */ + void SetPerceptibility(const int32_t perceptibility); + + /** + * @brief Obtains the perceptibility to ability. + * + * @return Returns the perceptibility to ability. + */ + int32_t GetPerceptibility() const; + + /** + * @brief Setting the connection state to service ability. + * + * @param preToken, the connection state to service ability. + */ + void SetConnectionState(const int32_t connectionState); + + /** + * @brief Obtains the connection state to service ability. + * + * @return Returnsthe connection state to service ability. + */ + int32_t GetConnectionState() const; + +private: + int32_t lastLaunchTime_ = 0; + int32_t visibility_ = 0; + int32_t perceptibility_ = 0; + int32_t connectionState_ = 0; + AbilityState state_ = AbilityState::ABILITY_STATE_BEGIN; + std::shared_ptr info_; + sptr token_; + sptr preToken_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_ABILITY_RUNNING_RECORD_H diff --git a/services/appmgr/include/ams_mgr_scheduler.h b/services/appmgr/include/ams_mgr_scheduler.h new file mode 100644 index 000000000..f70dccfed --- /dev/null +++ b/services/appmgr/include/ams_mgr_scheduler.h @@ -0,0 +1,136 @@ +/* + * 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_APPMGR_INCLUDE_AMS_MGR_SCHEDULER_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_AMS_MGR_SCHEDULER_H + +#include "if_system_ability_manager.h" +#include "nocopyable.h" + +#include "system_ability.h" +#include "ability_info.h" +#include "ability_running_record.h" +#include "appexecfwk_errors.h" +#include "application_info.h" +#include "app_mgr_constants.h" +#include "ams_mgr_stub.h" +#include "app_mgr_service_event_handler.h" +#include "app_mgr_service_inner.h" +#include "app_record_id.h" +#include "app_running_record.h" +#include "app_scheduler_proxy.h" + +namespace OHOS { +namespace AppExecFwk { + +class AmsMgrScheduler : public AmsMgrStub { +public: + AmsMgrScheduler( + const std::shared_ptr &MgrServiceInner_, const std::shared_ptr &Handler_); + virtual ~AmsMgrScheduler() override; + + /** + * LoadAbility, call LoadAbility() through proxy project, load the ability that needed to be started. + * + * @param token, the unique identification to start the ability. + * @param preToken, the unique identification to call the ability. + * @param abilityInfo, the ability information. + * @param appInfo, the app information. + * @return + */ + virtual void LoadAbility(const sptr &token, const sptr &preToken, + const std::shared_ptr &abilityInfo, const std::shared_ptr &appInfo) override; + + /** + * TerminateAbility, call TerminateAbility() through the proxy object, terminate the token ability. + * + * @param token, token, he unique identification to terminate the ability. + * @return + */ + virtual void TerminateAbility(const sptr &token) override; + + /** + * UpdateAbilityState, call UpdateAbilityState() through the proxy object, update the ability status. + * + * @param token, the unique identification to update the ability. + * @param state, ability status that needs to be updated. + * @return + */ + virtual void UpdateAbilityState(const sptr &token, const AbilityState state) override; + + /** + * RegisterAppStateCallback, call RegisterAppStateCallback() through the proxy object, register the callback. + * + * @param callback, Ams register the callback. + * @return + */ + virtual void RegisterAppStateCallback(const sptr &callback) override; + + /** + * Reset,call Reset() through the proxy object, reset DFX of AppMgr. + * + * @return + */ + virtual void Reset() override; + + /** + * AbilityBehaviorAnalysis, ability behavior analysis assistant process optimization. + * + * @param token, the unique identification to start the ability. + * @param preToken, the unique identification to call the ability. + * @param visibility, the visibility information about windows info. + * @param perceptibility, the Perceptibility information about windows info. + * @param connectionState, the service ability connection state. + * @return + */ + virtual void AbilityBehaviorAnalysis(const sptr &token, const sptr &preToken, + const int32_t visibility, const int32_t perceptibility, const int32_t connectionState) override; + + /** + * KillProcessByAbilityToken, call KillProcessByAbilityToken() through proxy object, + * kill the process by ability token. + * + * @param token, the unique identification to the ability. + * @return + */ + virtual void KillProcessByAbilityToken(const sptr &token) override; + + /** + * KillApplication, call KillApplication() through proxy object, kill the application. + * + * @param bundleName, bundle name in Application record. + * @return ERR_OK, return back success, others fail. + */ + virtual int32_t KillApplication(const std::string &bundleName) override; + +private: + /** + * @brief Judge whether the application service is ready. + * + * @return Returns true means service is ready, otherwise service is not ready. + */ + bool IsReady() const; + +private: + std::shared_ptr amsMgrServiceInner_; + std::shared_ptr amsHandler_; + sptr systemAbilityMgr_; + + DISALLOW_COPY_AND_MOVE(AmsMgrScheduler); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_AMS_MGR_SCHEDULER_H diff --git a/services/appmgr/include/app_death_recipient.h b/services/appmgr/include/app_death_recipient.h new file mode 100644 index 000000000..b7ee4974f --- /dev/null +++ b/services/appmgr/include/app_death_recipient.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_APPMGR_INCLUDE_APP_DEATH_RECIPIENT_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_APP_DEATH_RECIPIENT_H + +#include "iremote_object.h" + +#include "app_mgr_service_event_handler.h" + +namespace OHOS { +namespace AppExecFwk { + +class AppMgrServiceInner; + +class AppDeathRecipient : public IRemoteObject::DeathRecipient { +public: + virtual void OnRemoteDied(const wptr &remote) override; + + /** + * @brief Setting event handler instance. + * + * @param handler, event handler instance. + */ + void SetEventHandler(const std::shared_ptr &handler); + + /** + * @brief Setting application service internal handler instance. + * + * @param serviceInner, application service internal handler instance. + */ + void SetAppMgrServiceInner(const std::shared_ptr &serviceInner); + +private: + std::weak_ptr handler_; + std::weak_ptr appMgrServiceInner_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_APP_DEATH_RECIPIENT_H diff --git a/services/appmgr/include/app_lifecycle_deal.h b/services/appmgr/include/app_lifecycle_deal.h new file mode 100644 index 000000000..351224881 --- /dev/null +++ b/services/appmgr/include/app_lifecycle_deal.h @@ -0,0 +1,132 @@ +/* + * 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_APPMGR_INCLUDE_APP_LIFECYCLE_DEAL_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_APP_LIFECYCLE_DEAL_H + +#include "app_scheduler_proxy.h" +#include "app_launch_data.h" +#include "ability_running_record.h" + +namespace OHOS { + +namespace AppExecFwk { + +class AppLifeCycleDeal { + +public: + AppLifeCycleDeal(); + virtual ~AppLifeCycleDeal(); + + /** + * LaunchApplication, call ScheduleLaunchApplication() through proxy project, + * Notify application to launch application. + * + * @param The app data value. + * + * @return + */ + void LaunchApplication(const AppLaunchData &launchData_); + + /** + * LaunchAbility, call ScheduleLaunchAbility() through proxy project, + * Notify application to launch ability. + * + * @param The ability info. + * @return + */ + void LaunchAbility(const std::shared_ptr &ability); + + /** + * ScheduleTerminate, call ScheduleTerminateApplication() through proxy project, + * Notify application to terminate. + * + * @return + */ + void ScheduleTerminate(); + + /** + * ScheduleForegroundRunning, call ScheduleForegroundApplication() through proxy project, + * Notify application to switch to foreground. + * + * @return + */ + void ScheduleForegroundRunning(); + + /** + * ScheduleBackgroundRunning, call ScheduleBackgroundApplication() through proxy project, + * Notify application to switch to background. + * + * @return + */ + void ScheduleBackgroundRunning(); + + /** + * ScheduleTrimMemory, call ScheduleShrinkMemory() through proxy project, + * Notifies the application of the memory seen. + * + * @param The memory value. + * + * @return + */ + void ScheduleTrimMemory(int32_t timeLevel); + + /** + * LowMemoryWarning, call ScheduleLowMemory() through proxy project, + * Notify application to low memory. + * + * @return + */ + void LowMemoryWarning(); + + /** + * ScheduleCleanAbility, call ScheduleCleanAbility() through proxy project, + * Notify application to clean ability. + * + * @param token, The ability token. + * @return + */ + void ScheduleCleanAbility(const sptr &token); + + /** + * ScheduleProcessSecurityExit, call ScheduleTerminateApplication() through proxy project, + * Notify application process exit safely. + * + * @return + */ + void ScheduleProcessSecurityExit(); + + /** + * @brief Setting client for application record. + * + * @param thread, the application client. + */ + void SetApplicationClient(const sptr &thread); + + /** + * @brief Obtains the client of the application record. + * + * @return Returns the application client. + */ + sptr GetApplicationClient() const; + +private: + sptr appThread_; +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_APP_LIFECYCLE_DEAL_H \ No newline at end of file diff --git a/services/appmgr/include/app_mgr_service.h b/services/appmgr/include/app_mgr_service.h new file mode 100644 index 000000000..2219e41fc --- /dev/null +++ b/services/appmgr/include/app_mgr_service.h @@ -0,0 +1,220 @@ +/* + * 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_APPMGR_INCLUDE_APP_MGR_SERVICE_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_APP_MGR_SERVICE_H + +#include +#include +#include + +#include "if_system_ability_manager.h" +#include "nocopyable.h" +#include "system_ability.h" + +#include "ability_info.h" +#include "ability_running_record.h" +#include "appexecfwk_errors.h" +#include "application_info.h" +#include "app_mgr_constants.h" +#include "app_mgr_stub.h" +#include "app_mgr_service_event_handler.h" +#include "app_mgr_service_inner.h" +#include "app_record_id.h" +#include "app_running_record.h" +#include "app_scheduler_proxy.h" +#include "ams_mgr_scheduler.h" + +namespace OHOS { +namespace AppExecFwk { + +enum class ServiceRunningState { STATE_NOT_START, STATE_RUNNING }; + +struct AppMgrServiceState { + ServiceRunningState serviceRunningState = ServiceRunningState::STATE_NOT_START; + SpawnConnectionState connectionState = SpawnConnectionState::STATE_NOT_CONNECT; +}; + +class AMSEventHandler; + +class AppMgrService : public SystemAbility, public AppMgrStub { +public: + DECLEAR_SYSTEM_ABILITY(AppMgrService); + + AppMgrService(); + AppMgrService(const int32_t serviceId, bool runOnCreate = false); + virtual ~AppMgrService() override; + + // the function about application + // attach the application to ams, then ams can control it. + /** + * AttachApplication, call AttachApplication() through proxy object, + * get all the information needed to start the Application (data related to the Application ). + * + * @param app, information needed to start the Application. + * @return + */ + virtual void AttachApplication(const sptr &app) override; + + // notify the ams update the state of an app, when it entered foreground. + + /** + * ApplicationForegrounded, call ApplicationForegrounded() through proxy object, + * set the application to Foreground State. + * + * @param recordId, a unique record that identifies this Application from others. + * @return + */ + virtual void ApplicationForegrounded(const int32_t recordId) override; + + /** + * ApplicationBackgrounded, call ApplicationBackgrounded() through proxy object, + * set the application to Backgrounded State. + * + * @param recordId, a unique record that identifies this Application from others. + * @return + */ + virtual void ApplicationBackgrounded(const int32_t recordId) override; + + /** + * ApplicationTerminated, call ApplicationTerminated() through proxy object, + * terminate the application. + * + * @param recordId, a unique record that identifies this Application from others. + * @return + */ + virtual void ApplicationTerminated(const int32_t recordId) override; + + /** + * AbilityCleaned,call through AbilityCleaned() proxy project, clean Ability record. + * + * @param token, a unique record that identifies AbilityCleaned from others. + * @return + */ + virtual void AbilityCleaned(const sptr &token) override; + + /** + * ClearUpApplicationData, call ClearUpApplicationData() through proxy project, + * clear the application data. + * + * @param bundleName, bundle name in Application record. + * @return + */ + virtual void ClearUpApplicationData(const std::string &bundleName) override; + + /** + * IsBackgroundRunningRestricted, call IsBackgroundRunningRestricted() through proxy project, + * Checks whether the process of this application is forbidden to run in the background. + * + * @param bundleName, bundle name in Application record. + * @return ERR_OK, return back success, others fail. + */ + virtual int32_t IsBackgroundRunningRestricted(const std::string &bundleName) override; + + /** + * GetAllRunningProcesses, call GetAllRunningProcesses() through proxy project. + * Obtains information about application processes that are running on the device. + * + * @param runningProcessInfo, app name in Application record. + * @return ERR_OK ,return back success,others fail. + */ + virtual int32_t GetAllRunningProcesses(std::shared_ptr &runningProcessInfo) override; + + // the function about system + /** + * CheckPermission, call CheckPermission() through proxy object, check the permission. + * + * @param recordId, a unique record that identifies this Application from others. + * @param permission, check the permissions. + * @return ERR_OK, return back success, others fail. + */ + virtual int32_t CheckPermission(const int32_t recordId, const std::string &permission) override; + + // the function about service running info + /** + * QueryServiceState, Query application service status. + * + * @return the application service status. + */ + AppMgrServiceState QueryServiceState(); + + /** + * GetAmsMgr, call GetAmsMgr() through proxy object, get AMS interface instance. + * + * @return sptr, return to AMS interface instance. + */ + virtual sptr GetAmsMgr() override; + +private: + /** + * Init, Initialize application services. + * + * @return ERR_OK, return back success, others fail. + */ + ErrCode Init(); + + // the function that overrode from SystemAbility + /** + * OnStart, Start application service. + * + * @return + */ + virtual void OnStart() override; + + /** + * OnStop, Stop application service. + * + * @return + */ + virtual void OnStop() override; + + /** + * @brief Judge whether the application service is ready. + * + * @return Returns true means service is ready, otherwise service is not ready. + */ + bool IsReady() const; + + /** + * AddAppDeathRecipient, Add monitoring death application record. + * + * @param pid, the application pid. + * @param appDeathRecipient, Application death recipient list. + * + * @return + */ + void AddAppDeathRecipient(const pid_t pid) const; + + /** + * SetInnerService, Setting application service Inner instance. + * + * @return + */ + void SetInnerService(const std::shared_ptr &innerService); + +private: + std::shared_ptr appMgrServiceInner_; + AppMgrServiceState appMgrServiceState_; + std::shared_ptr runner_; + std::shared_ptr handler_; + sptr systemAbilityMgr_; + sptr amsMgrScheduler_; + + DISALLOW_COPY_AND_MOVE(AppMgrService); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_APP_MGR_SERVICE_H diff --git a/services/appmgr/include/app_mgr_service_event_handler.h b/services/appmgr/include/app_mgr_service_event_handler.h new file mode 100644 index 000000000..42703470a --- /dev/null +++ b/services/appmgr/include/app_mgr_service_event_handler.h @@ -0,0 +1,39 @@ +/* + * 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_APPMGR_INCLUDE_APP_MGR_SERVICE_EVENT_HANDLER_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_APP_MGR_SERVICE_EVENT_HANDLER_H + +#include "event_handler.h" + +namespace OHOS { +namespace AppExecFwk { + +class AppMgrServiceInner; + +class AMSEventHandler : public EventHandler { +public: + AMSEventHandler(const std::shared_ptr &runner, const std::shared_ptr &ams); + virtual ~AMSEventHandler() override; + + virtual void ProcessEvent(const InnerEvent::Pointer &event) override; + +private: + std::shared_ptr ams_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_APP_MGR_SERVICE_EVENT_HANDLER_H diff --git a/services/appmgr/include/app_mgr_service_inner.h b/services/appmgr/include/app_mgr_service_inner.h new file mode 100644 index 000000000..25532ad23 --- /dev/null +++ b/services/appmgr/include/app_mgr_service_inner.h @@ -0,0 +1,618 @@ +/* + * 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_APPMGR_INCLUDE_APP_MGR_SERVICE_INNER_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_APP_MGR_SERVICE_INNER_H + +#include +#include +#include + +#include "iremote_object.h" +#include "refbase.h" + +#include "ability_info.h" +#include "appexecfwk_errors.h" +#include "app_death_recipient.h" +#include "app_mgr_constants.h" +#include "app_record_id.h" +#include "app_running_record.h" +#include "app_scheduler_interface.h" +#include "app_spawn_client.h" +#include "app_task_info.h" +#include "iapp_state_callback.h" +#include "app_process_manager.h" +#include "remote_client_manager.h" +#include "app_running_manager.h" +#include "record_query_result.h" +#include "running_process_info.h" +#include "app_process_info.h" +#include "bundle_info.h" + +#include "process_optimizer_uba.h" + +#include "ohos/aafwk/content/want.h" + +namespace OHOS { +namespace AppExecFwk { + +using OHOS::AAFwk::Want; + +class AppMgrServiceInner : public std::enable_shared_from_this { +public: + AppMgrServiceInner(); + virtual ~AppMgrServiceInner(); + + /** + * LoadAbility, load the ability that needed to be started. + * + * @param token, the unique identification to start the ability. + * @param preToken, the unique identification to call the ability. + * @param abilityInfo, the ability information. + * @param appInfo, the app information. + * + * @return + */ + virtual void LoadAbility(const sptr &token, const sptr &preToken, + const std::shared_ptr &abilityInfo, const std::shared_ptr &appInfo); + + /** + * TerminateAbility, terminate the token ability. + * + * @param token, he unique identification to terminate the ability. + * + * @return + */ + virtual void TerminateAbility(const sptr &token); + + /** + * UpdateAbilityState, update the ability status. + * + * @param token, the unique identification to update the ability. + * @param state, ability status that needs to be updated. + * + * @return + */ + virtual void UpdateAbilityState(const sptr &token, const AbilityState state); + + /** + * RegisterAppStateCallback, register the callback. + * + * @param callback, Ams register the callback. + * + * @return + */ + virtual void RegisterAppStateCallback(const sptr &callback); + + /** + * StopAllProcess, Terminate all processes. + * + * @return + */ + virtual void StopAllProcess(); + + /** + * AbilityBehaviorAnalysis, ability behavior analysis assistant process optimization. + * + * @param token, the unique identification to start the ability. + * @param preToken, the unique identification to call the ability. + * @param visibility, the visibility information about windows info. + * @param perceptibility, the Perceptibility information about windows info. + * @param connectionState, the service ability connection state. + * @return + */ + virtual void AbilityBehaviorAnalysis(const sptr &token, const sptr &preToken, + const int32_t visibility, const int32_t perceptibility, const int32_t connectionState); + + /** + * KillProcessByAbilityToken, kill the process by ability token. + * + * @param token, the unique identification to the ability. + * @return + */ + virtual void KillProcessByAbilityToken(const sptr &token); + + /** + * AttachApplication, get all the information needed to start the Application + * (data related to the Application ). + * + * @param app, information needed to start the Application. + * + * @return + */ + virtual void AttachApplication(const pid_t pid, const sptr &app); + + /** + * ApplicationForegrounded, set the application to Foreground State. + * + * @param recordId, a unique record that identifies this Application from others. + * + * @return + */ + virtual void ApplicationForegrounded(const int32_t recordId); + + /** + * ApplicationBackgrounded, set the application to Backgrounded State. + * + * @param recordId, a unique record that identifies this Application from others. + * + * @return + */ + virtual void ApplicationBackgrounded(const int32_t recordId); + + /** + * ApplicationTerminated, terminate the application. + * + * @param recordId, a unique record that identifies this Application from others. + * + * @return + */ + virtual void ApplicationTerminated(const int32_t recordId); + + /** + * AbilityTerminated, terminate the ability. + * + * @param token, the unique identification to terminated the ability. + * + * @return + */ + virtual void AbilityTerminated(const sptr &token); + + /** + * KillApplication, kill the application. + * + * @param bundleName, bundle name in Application record. + * + * @return ERR_OK, return back success, others fail. + */ + virtual int32_t KillApplication(const std::string &bundleName); + + /** + * ClearUpApplicationData, clear the application data. + * + * @param bundleName, bundle name in Application record. + * @param uid, app uid in Application record. + * @param pid, app pid in Application record. + * + * @return + */ + virtual void ClearUpApplicationData(const std::string &bundleName, const int32_t uid, const pid_t pid); + + /** + * IsBackgroundRunningRestricted, Checks whether the process of this application is forbidden + * to run in the background. + * + * @param bundleName, bundle name in Application record. + * + * @return ERR_OK, return back success, others fail. + */ + virtual int32_t IsBackgroundRunningRestricted(const std::string &bundleName); + + /** + * GetAllRunningProcesses, Obtains information about application processes that are running on the device. + * + * @param runningProcessInfo, app name in Application record. + * + * @return ERR_OK ,return back success,others fail. + */ + virtual int32_t GetAllRunningProcesses(std::shared_ptr &runningProcessInfo); + + // Get AppRunningRecord according to appInfo. Create if not exists. + // Create ability record if not exists and abilityInfo not null. + // Return AppRunningRecord pointer if success get or create. + // If error occurs, error code is in |result| + + /** + * GetOrCreateAppRunningRecord, Get or create application record information. + * + * @param token, the unique identification to the ability. + * @param abilityInfo, ability information. + * @param appInfo, app information. + * @param processName, the app process name. + * @param uid, app uid in Application record. + * @param result, If error occurs, error code is in |result|. + * + * @return AppRunningRecord pointer if success get or create. + */ + std::shared_ptr GetOrCreateAppRunningRecord(const sptr &token, + const std::shared_ptr &appInfo, const std::shared_ptr &abilityInfo, + const std::string &processName, const int32_t uid, RecordQueryResult &result); + + /** + * OnStop, Application management service stopped. + * + * @return + */ + void OnStop(); + + // functions about appspawn + + /** + * OpenAppSpawnConnection, Open connection with appspwan. + * + * @return ERR_OK ,return back success,others fail. + */ + virtual ErrCode OpenAppSpawnConnection(); + + /** + * CloseAppSpawnConnection, Close connection with appspwan. + * + * @return + */ + virtual void CloseAppSpawnConnection() const; + + /** + * QueryAppSpawnConnectionState, Query the connection status with appspwan. + * + * @return Returns the connection status with appspwan. + */ + virtual SpawnConnectionState QueryAppSpawnConnectionState() const; + + /** + * SetAppSpawnClient, Setting the client to connect with appspwan. + * + * @param spawnClient, the client to connect with appspwan. + * + * @return + */ + void SetAppSpawnClient(std::shared_ptr spawnClient); + + // Schedule launch application with specified |appRecord| + + /** + * LaunchApplication, Notify application to launch application. + * + * @param appRecord, the application record. + * + * @return + */ + void LaunchApplication(const std::shared_ptr &appRecord); + + /** + * GetRecordMap, Get all the ability information in the application record. + * + * @return all the ability information in the application record. + */ + const std::map> &GetRecordMap() const; + + // functions to get special AppRunningRecord + /** + * GetAppRunningRecordByAppName, Get process record by application name. + * + * @param appName, the application name. + * + * @return process record. + */ + std::shared_ptr GetAppRunningRecordByAppName(const std::string &appName) const; + + /** + * GetAppRunningRecordByProcessName, Get process record by application name and process name. + * + * @param appName, the application name. + * @param processName, the process name. + * + * @return process record. + */ + std::shared_ptr GetAppRunningRecordByProcessName( + const std::string &appName, const std::string &processName) const; + + /** + * GetAppRunningRecordByPid, Get process record by application pid. + * + * @param pid, the application pid. + * + * @return process record. + */ + std::shared_ptr GetAppRunningRecordByPid(const pid_t pid) const; + + /** + * GetAppRunningRecordByAbilityToken, Get process record by ability token. + * + * @param abilityToken, the ability token. + * + * @return process record. + */ + std::shared_ptr GetAppRunningRecordByAbilityToken(const sptr &abilityToken) const; + + /** + * GetAppRunningRecordByAppRecordId, Get process record by application id. + * + * @param recordId, the application id. + * + * @return process record. + */ + std::shared_ptr GetAppRunningRecordByAppRecordId(const int32_t recordId) const; + + /** + * OnAbilityStateChanged, Call ability state change. + * + * @param ability, the ability info. + * @param state, the ability state. + * + * @return + */ + void OnAbilityStateChanged(const std::shared_ptr &ability, const AbilityState state); + + /** + * GetRecentAppList, Get a list of recent applications. + * + * @return a list of recent applications. + */ + const std::list> &GetRecentAppList() const; + + /** + * GetRecentAppList, Remove the corresponding latest application list data by applying the name. + * + * @param appName, the application name. + * @param processName, the process name. + * + * @return + */ + void RemoveAppFromRecentList(const std::string &appName, const std::string &processName); + + /** + * GetRecentAppList, Clear recent application list. + * + * @return + */ + void ClearRecentAppList(); + + /** + * OnRemoteDied, Equipment death notification. + * + * @param remote, Death client. + * @return + */ + void OnRemoteDied(const wptr &remote); + + /** + * AddAppDeathRecipient, Add monitoring death application record. + * + * @param pid, the application pid. + * @param appDeathRecipient, Application death recipient list. + * + * @return + */ + + virtual void AddAppDeathRecipient(const pid_t pid, const sptr &appDeathRecipient) const; + /** + * ProcessOptimizerInit, Process Optimizer init. + * + * @param + * @return ERR_OK, return back success, others fail. + */ + virtual int32_t ProcessOptimizerInit(); + + /** + * OptimizerAbilityStateChanged, Optimizer processing ability state changes. + * + * @param ability, the ability info. + * @param state, the ability state before change. + * + * @return + */ + virtual void OptimizerAbilityStateChanged( + const std::shared_ptr &ability, const AbilityState state); + + /** + * OptimizerAppStateChanged, Optimizer processing app state changes. + * + * @param appRecord, the app information. + * @param state, the app before change. + * @return + */ + virtual void OptimizerAppStateChanged( + 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). + * Start on a new boot process + * @param token, the unique identification to start the ability. + * @param preToken, the unique identification to call the ability. + * @param abilityInfo, the ability information. + * @param appInfo, the app information. + * + * @return + */ + void StartAbility(const sptr &token, const sptr &preToken, + const std::shared_ptr &abilityInfo, const std::shared_ptr &appRecord); + + /** + * UnsuspendApplication, Application process state switch to unsuspend. + * + * @param appRecord, the app information. + * + * @return + */ + void UnsuspendApplication(const std::shared_ptr &appRecord); + + /** + * SuspendApplication, Application process state switch to suspend. + * + * @param appRecord, the app information. + * + * @return + */ + void SuspendApplication(const std::shared_ptr &appRecord); + + /** + * LowMemoryApplicationAlert, Application low memory alert. + * + * @param appRecord, the app information. + * @param level, the app low memory level. + * + * @return + */ + void LowMemoryApplicationAlert( + const std::shared_ptr &appRecord, const CgroupManager::LowMemoryLevel level); + + /** + * GetAbilityOwnerApp, Get the process record of ability. + * + * @param abilityRecord, the ability information. + * + * @return process record. + */ + std::shared_ptr GetAbilityOwnerApp( + const std::shared_ptr &abilityRecord) const; + + /** + * GetAbilityRunningRecordByAbilityToken, Get the ability record by token. + * + * @param abilityToken, the ability token. + * + * @return ability record. + */ + 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). + * + * @param appName, the app name. + * @param processName, the process name. + * @param appRecord, the app information. + * + * @return + */ + void StartProcess( + const std::string &appName, const std::string &processName, const std::shared_ptr &appRecord); + + /** + * PushAppFront, Adjust the latest application record to the top level. + * + * @param recordId, the app record id. + * + * @return + */ + void PushAppFront(const int32_t recordId); + + /** + * RemoveAppFromRecentListById, Remove the specified recent application record by application record id. + * + * @param recordId, the app record id. + * + * @return + */ + void RemoveAppFromRecentListById(const int32_t recordId); + + /** + * AddAppToRecentList, Add application to recent list. + * + * @param appName, the app name. + * @param processName, the process name. + * @param pid, the app pid. + * @param recordId, the app record id. + * + * @return + */ + void AddAppToRecentList( + const std::string &appName, const std::string &processName, const pid_t pid, const int32_t recordId); + + /** + * AddAppToRecentList, Get application task information through ID. + * + * @param recordId, the app record id. + * + * @return application task information. + */ + const std::shared_ptr GetAppTaskInfoById(const int32_t recordId) const; + + /** + * KillProcessByPid, Kill process by PID. + * + * @param pid_t, the app record pid. + * + * @return ERR_OK, return back success,others fail. + */ + int32_t KillProcessByPid(const pid_t pid) const; + + /** + * WaitForRemoteProcessExit, Wait for the process to exit normally. + * + * @param pids, process number collection to exit. + * @param startTime, execution process security exit start time. + * + * @return true, return back success,others fail. + */ + bool WaitForRemoteProcessExit(std::list &pids, const int64_t startTime); + + /** + * GetPidsByBundleName, Get the corresponding pid collection through the bundle name. + * + * @param bundleName, bundle name in Application record. + * @param pids, process number collection to exit. + * + * @return true, return back success,others fail. + */ + bool GetPidsByBundleName(const std::string &bundleName, std::list &pids); + + /** + * GetAllPids, Get the corresponding pid collection. + * + * @param pids, process number collection to exit. + * + * @return true, return back success,others fail. + */ + bool GetAllPids(std::list &pids); + + /** + * process_exist, Judge whether the process exists. + * + * @param pids, process number collection to exit. + * + * @return true, return back existed,others non-existent. + */ + bool process_exist(pid_t &pid); + + /** + * CheckALLProcessExist, Determine whether all processes exist . + * + * @param pids, process number collection to exit. + * + * @return true, Returns that a process exists and all other processes do not exist. + */ + bool CheckALLProcessExist(std::list &pids); + + /** + * SystemTimeMillis, Get system time. + * + * @return the system time. + */ + int64_t SystemTimeMillis(); + + // Test add the bundle manager instance. + void SetBundleManager(sptr bundleManager); + +private: + std::vector> appStateCallbacks_; + std::shared_ptr appProcessManager_; + std::shared_ptr remoteClientManager_; + std::shared_ptr appRunningManager_; + std::shared_ptr processOptimizerUBA_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_APP_MGR_SERVICE_INNER_H diff --git a/services/appmgr/include/app_process_manager.h b/services/appmgr/include/app_process_manager.h new file mode 100644 index 000000000..ca7494017 --- /dev/null +++ b/services/appmgr/include/app_process_manager.h @@ -0,0 +1,117 @@ +/* + * 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_APPMGR_INCLUDE_AMS_MGR_PROCESS_MANAGER_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_AMS_MGR_PROCESS_MANAGER_H + +#include + +#include "iremote_object.h" +#include "refbase.h" + +#include "app_task_info.h" + +namespace OHOS { + +namespace AppExecFwk { + +class AppProcessManager { + +public: + AppProcessManager(); + virtual ~AppProcessManager(); + + /** + * RemoveAppFromRecentList, Remove the corresponding latest application list data. + * + * @param appTaskInfo, the application task information. + * + * @return + */ + void RemoveAppFromRecentList(const std::shared_ptr &appTaskInfo); + + /** + * GetRecentAppList, Clear recent application list. + * + * @return + */ + void ClearRecentAppList(); + + /** + * AddAppToRecentList, Add application to recent list. + * + * @param appName, the app name. + * @param processName, the process name. + * @param pid, the app pid. + * @param recordId, the app record id. + * + * @return + */ + void AddAppToRecentList( + const std::string &appName, const std::string &processName, const pid_t pid, const int32_t recordId); + + /** + * GetRecentAppList, Get a list of recent applications. + * + * @return a list of recent applications. + */ + const std::list> &GetRecentAppList() const; + + /** + * PushAppFront, Adjust the latest application record to the top level. + * + * @param recordId, the app record id. + * + * @return + */ + void PushAppFront(const int32_t recordId); + + /** + * RemoveAppFromRecentListById, Remove the specified recent application record by application record id. + * + * @param recordId, the app record id. + * + * @return + */ + void RemoveAppFromRecentListById(const int32_t recordId); + + /** + * AddAppToRecentList, Get application task information through ID. + * + * @param recordId, the app record id. + * + * @return application task information. + */ + const std::shared_ptr GetAppTaskInfoById(const int32_t recordId) const; + + /** + * GetAppTaskInfoByProcessName, Get application task information through process name. + * + * @param appName, the application name. + * @param processName, the process name. + * + * @return application task information. + */ + std::shared_ptr GetAppTaskInfoByProcessName( + const std::string &appName, const std::string &processName) const; + +private: + std::list> recentAppList_; +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_AMS_MGR_PROCESS_MANAGER_H \ No newline at end of file diff --git a/services/appmgr/include/app_running_manager.h b/services/appmgr/include/app_running_manager.h new file mode 100644 index 000000000..b44e56cc7 --- /dev/null +++ b/services/appmgr/include/app_running_manager.h @@ -0,0 +1,129 @@ +/* + * 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_APPMGR_INCLUDE_APP_MGR_RUNNING_MANAGER_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_APP_MGR_RUNNING_MANAGER_H + +#include + +#include "iremote_object.h" +#include "refbase.h" + +#include "app_running_record.h" +#include "ability_info.h" +#include "application_info.h" +#include "record_query_result.h" + +namespace OHOS { + +namespace AppExecFwk { + +class AppRunningManager { + +public: + AppRunningManager(); + virtual ~AppRunningManager(); + /** + * GetOrCreateAppRunningRecord, Get or create application record information. + * + * @param token, the unique identification to start the ability. + * @param abilityInfo, ability information. + * @param appInfo, app information. + * @param processName, app process name. + * @param uid, app uid in Application record. + * @param result, If error occurs, error code is in |result|. + * + * @return AppRunningRecord pointer if success get or create. + */ + std::shared_ptr GetOrCreateAppRunningRecord(const sptr &token, + const std::shared_ptr &appInfo, const std::shared_ptr &abilityInfo, + const std::string &processName, const int32_t uid, RecordQueryResult &result); + + /** + * GetAppRunningRecordByAppName, Get process record by application name. + * + * @param appName, the application name. + * + * @return process record. + */ + std::shared_ptr GetAppRunningRecordByAppName(const std::string &appName) const; + + /** + * GetAppRunningRecordByProcessName, Get process record by application name and process Name. + * + * @param appName, the application name. + * @param processName, the process name. + * + * @return process record. + */ + std::shared_ptr GetAppRunningRecordByProcessName( + const std::string &appName, const std::string &processName) const; + + /** + * GetAppRunningRecordByPid, Get process record by application pid. + * + * @param pid, the application pid. + * + * @return process record. + */ + std::shared_ptr GetAppRunningRecordByPid(const pid_t pid) const; + + /** + * GetAppRunningRecordByAbilityToken, Get process record by ability token. + * + * @param abilityToken, the ability token. + * + * @return process record. + */ + std::shared_ptr GetAppRunningRecordByAbilityToken(const sptr &abilityToken) const; + + /** + * OnRemoteDied, Equipment death notification. + * + * @param remote, Death client. + * @return + */ + std::shared_ptr OnRemoteDied(const wptr &remote); + + /** + * GetAppRunningRecordMap, Get application record list. + * + * @return the application record list. + */ + const std::map> &GetAppRunningRecordMap() const; + + /** + * RemoveAppRunningRecordById, Remove application information through application id. + * + * @param recordId, the application id. + * @return + */ + void RemoveAppRunningRecordById(const int32_t recordId); + + /** + * ClearAppRunningRecordMap, Clear application record list. + * + * @return + */ + void ClearAppRunningRecordMap(); + +private: + std::map> appRunningRecordMap_; +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_APP_MGR_RUNNING_MANAGER_H \ No newline at end of file diff --git a/services/appmgr/include/app_running_record.h b/services/appmgr/include/app_running_record.h new file mode 100644 index 000000000..a5ef75e87 --- /dev/null +++ b/services/appmgr/include/app_running_record.h @@ -0,0 +1,394 @@ +/* + * 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_APPMGR_INCLUDE_APP_RUNNING_RECORD_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_APP_RUNNING_RECORD_H + +#include +#include +#include +#include + +#include "iremote_object.h" + +#include "ability_running_record.h" +#include "application_info.h" +#include "app_death_recipient.h" +#include "app_launch_data.h" +#include "app_mgr_constants.h" +#include "app_scheduler_proxy.h" +#include "app_record_id.h" +#include "profile.h" +#include "priority_object.h" +#include "app_lifecycle_deal.h" + +namespace OHOS { +namespace AppExecFwk { + +class AbilityRunningRecord; +class AppMgrServiceInner; + +class AppRunningRecord { +public: + AppRunningRecord( + const std::shared_ptr &info, const int32_t recordId, const std::string &processName); + virtual ~AppRunningRecord() = default; + + /** + * @brief Obtains the app record bundleName. + * + * @return Returns app record bundleName. + */ + std::string GetBundleName() const; + /** + * @brief Obtains the app record id. + * + * @return Returns app record id. + */ + int32_t GetRecordId() const; + + /** + * @brief Obtains the app name. + * + * @return Returns the app name. + */ + const std::string &GetName() const; + + /** + * @brief Obtains the process name. + * + * @return Returns the process name. + */ + const std::string &GetProcessName() const; + + /** + * @brief Obtains the application uid. + * + * @return Returns the application uid. + */ + int32_t GetUid() const; + + /** + * @brief Setting the application uid. + * + * @param state, the application uid. + */ + void SetUid(const int32_t uid); + + // Get current state for this process + + /** + * @brief Obtains the application state. + * + * @return Returns the application state. + */ + ApplicationState GetState() const; + + // Set current state for this process + + /** + * @brief Setting the application state. + * + * @param state, the application state. + */ + void SetState(const ApplicationState state); + + // Get abilities_ for this process + /** + * @brief Obtains the abilitys info for the application record. + * + * @return Returns the abilitys info for the application record. + */ + const std::map, std::shared_ptr> &GetAbilities() const; + // Update appThread with appThread + + /** + * @brief Setting the application client. + * + * @param thread, the application client. + */ + void SetApplicationClient(const sptr &thread); + + /** + * @brief Obtains the application client. + * + * @return Returns the application client. + */ + sptr GetApplicationClient() const; + + // Add new ability instance to current running abilities list managed by this process + /** + * AddAbility, Add new ability instance to current running abilities list managed by this process. + * + * @param token, the unique identification to the ability. + * @param abilityInfo, the ability info. + * + * @return the ability record. + */ + std::shared_ptr AddAbility( + const sptr &token, const std::shared_ptr &abilityInfo); + + // It can only used in SINGLETON mode. + /** + * GetAbilityRunningRecord, Get ability record by the ability Name. + * + * @param abilityName, the ability name. + * + * @return the ability record. + */ + std::shared_ptr GetAbilityRunningRecord(const std::string &abilityName) const; + + // Clear(remove) the specified ability record from the list + + /** + * ClearAbility, Clear ability record by record info. + * + * @param record, the ability record. + * + * @return + */ + void ClearAbility(const std::shared_ptr &record); + + // Update the trim memory level value of this process + /** + * @brief Setting the Trim Memory Level. + * + * @param level, the Memory Level. + */ + void SetTrimMemoryLevel(int32_t level); + + // Kill this process with a given reason + /** + * ForceKillApp, Kill this process with a given reason. + * + * @param reason, The reason to kill the process. + * + * @return + */ + void ForceKillApp(const std::string &reason) const; + + // Schedule to crash this app with a given description + /** + * ScheduleAppCrash, Schedule to crash this app with a given description. + * + * @param description, the given description. + * + * @return + */ + void ScheduleAppCrash(const std::string &description) const; + + /** + * LaunchApplication, Notify application to launch application. + * + * @return + */ + void LaunchApplication(); + + /** + * LaunchAbility, Notify application to launch ability. + * + * @param ability, the ability record. + * + * @return + */ + void LaunchAbility(const std::shared_ptr &ability); + + /** + * LaunchPendingAbilities, Launch Pending Abilities. + * + * @return + */ + void LaunchPendingAbilities(); + + /** + * LowMemoryWarning, Low memory warning. + * + * @return + */ + void LowMemoryWarning(); + + /** + * ScheduleTerminate, Notify application to terminate. + * + * @return + */ + void ScheduleTerminate(); + + /** + * ScheduleForegroundRunning, Notify application to switch to foreground. + * + * @return + */ + void ScheduleForegroundRunning(); + + /** + * ScheduleBackgroundRunning, Notify application to switch to background. + * + * @return + */ + void ScheduleBackgroundRunning(); + + /** + * ScheduleTerminate, Notify application process exit safely. + * + * @return + */ + void ScheduleProcessSecurityExit(); + + /** + * ScheduleTrimMemory, Notifies the application of the memory seen. + * + * @return + */ + void ScheduleTrimMemory(); + + /** + * GetAbilityRunningRecordByToken, Obtaining the ability record through token. + * + * @param token, the unique identification to the ability. + * + * @return + */ + std::shared_ptr GetAbilityRunningRecordByToken(const sptr &token) const; + + /** + * UpdateAbilityState, update the ability status. + * + * @param token, the unique identification to update the ability. + * @param state, ability status that needs to be updated. + * + * @return + */ + void UpdateAbilityState(const sptr &token, const AbilityState state); + + /** + * PopForegroundingAbilityTokens, Extract the token record from the foreground tokens list. + * + * @return + */ + void PopForegroundingAbilityTokens(); + + /** + * TerminateAbility, terminate the token ability. + * + * @param token, he unique identification to terminate the ability. + * + * @return + */ + void TerminateAbility(const sptr &token); + + /** + * AbilityTerminated, terminate the ability. + * + * @param token, the unique identification to terminated the ability. + * + * @return + */ + void AbilityTerminated(const sptr &token); + + /** + * @brief Setting application service internal handler instance. + * + * @param serviceInner, application service internal handler instance. + */ + void SetAppMgrServiceInner(const std::weak_ptr &inner); + + /** + * @brief Setting application death recipient. + * + * @param appDeathRecipient, application death recipient instance. + */ + void SetAppDeathRecipient(const sptr &appDeathRecipient); + + /** + * RegisterAppDeathRecipient, Register application death recipient. + * + * @return + */ + void RegisterAppDeathRecipient() const; + + /** + * @brief Obtains application priority info. + * + * @return Returns the application priority info. + */ + std::shared_ptr GetPriorityObject(); + + /** + * RegisterAppDeathRecipient, Remove application death recipient record. + * + * @return + */ + void RemoveAppDeathRecipient() const; + +private: + // drive application state changes when ability state changes. + /** + * OnAbilityStateChanged, Call ability state change. + * + * @param ability, the ability info. + * @param state, the ability state. + * + * @return + */ + void OnAbilityStateChanged(const std::shared_ptr &ability, const AbilityState state); + + /** + * AbilityForeground, Handling the ability process when switching to the foreground. + * + * @param ability, the ability info. + * + * @return + */ + void AbilityForeground(const std::shared_ptr &ability); + + /** + * AbilityBackground, Handling the ability process when switching to the background. + * + * @param ability, the ability info. + * + * @return + */ + void AbilityBackground(const std::shared_ptr &ability); + + /** + * OptimizerAbilityStateChanged, Optimizer processing ability state changes. + * + * @param ability, the ability info. + * @param state, the ability state. + * + * @return + */ + void OptimizerAbilityStateChanged(const std::shared_ptr &ability, const AbilityState state); + +private: + ApplicationState curState_ = ApplicationState::APP_STATE_CREATE; // current state of this process + + std::shared_ptr appInfo_; // the application's info of this process + int32_t appRecordId_ = 0; + std::string processName_; // the name of this process + int32_t uid_ = 0; + // List of abilities running in the process + std::map, std::shared_ptr> abilities_; + std::list> foregroundingAbilityTokens_; + std::weak_ptr appMgrServiceInner_; + sptr appDeathRecipient_; + std::shared_ptr priorityObject_; + std::shared_ptr appLifeCycleDeal_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_APP_RUNNING_RECORD_H diff --git a/services/appmgr/include/app_spawn_client.h b/services/appmgr/include/app_spawn_client.h new file mode 100644 index 000000000..e82adfbbe --- /dev/null +++ b/services/appmgr/include/app_spawn_client.h @@ -0,0 +1,89 @@ +/* + * 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_APPMGR_INCLUDE_APP_SPAWN_CLIENT_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_APP_SPAWN_CLIENT_H + +#include "nocopyable.h" +#include "app_spawn_msg_wrapper.h" +#include "app_spawn_socket.h" + +namespace OHOS { +namespace AppExecFwk { + +enum class SpawnConnectionState { STATE_NOT_CONNECT, STATE_CONNECTED, STATE_CONNECT_FAILED }; + +class AppSpawnClient { +public: + /** + * Constructor. + */ + AppSpawnClient(); + + /** + * Destructor + */ + virtual ~AppSpawnClient() = default; + + /** + * Disable copy. + */ + DISALLOW_COPY_AND_MOVE(AppSpawnClient); + + /** + * Try connect to appspawn. + */ + ErrCode OpenConnection(); + + /** + * Close the connect of appspawn. + */ + void CloseConnection(); + + /** + * AppSpawnClient core function, Start request to appspawn. + * + * @param startMsg, request message. + * @param pid, pid of app process, get from appspawn. + */ + virtual ErrCode StartProcess(const AppSpawnStartMsg &startMsg, pid_t &pid); + + /** + * Return the connect state. + */ + SpawnConnectionState QueryConnectionState() const; + + /** + * Set function, unit test also use it. + */ + void SetSocket(const std::shared_ptr socket); + +private: + /** + * AppSpawnClient core function, + * + * @param startMsg, request message. + * @param pid, pid of app process, get it from appspawn. + */ + ErrCode StartProcessImpl(const AppSpawnStartMsg &startMsg, pid_t &pid); + +private: + std::shared_ptr socket_; + SpawnConnectionState state_ = SpawnConnectionState::STATE_NOT_CONNECT; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_APP_SPAWN_CLIENT_H diff --git a/services/appmgr/include/app_spawn_msg_wrapper.h b/services/appmgr/include/app_spawn_msg_wrapper.h new file mode 100644 index 000000000..558e97a3a --- /dev/null +++ b/services/appmgr/include/app_spawn_msg_wrapper.h @@ -0,0 +1,122 @@ +/* + * 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_APPMGR_INCLUDE_APP_SPAWN_MSG_WRAPPER_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_APP_SPAWN_MSG_WRAPPER_H + +#include +#include +#include + +#include "nocopyable.h" +#include "client_socket.h" + +namespace OHOS { +namespace AppExecFwk { + +struct AppSpawnStartMsg { + int32_t uid; + int32_t gid; + std::vector gids; + std::string procName; + std::string soPath; +}; + +using AppSpawnMsg = AppSpawn::ClientSocket::AppProperty; + +constexpr auto LEN_PID = sizeof(pid_t); + +union AppSpawnPidMsg { + pid_t pid = 0; + char pidBuf[LEN_PID]; +}; + +class AppSpawnMsgWrapper { +public: + /** + * Constructor. + */ + AppSpawnMsgWrapper() = default; + + /** + * Destructor + */ + ~AppSpawnMsgWrapper(); + + /** + * Disable copy. + */ + DISALLOW_COPY_AND_MOVE(AppSpawnMsgWrapper); + + /** + * Verify message and assign to member variable. + * + * @param startMsg, request message. + */ + bool AssembleMsg(const AppSpawnStartMsg &startMsg); + + /** + * Get function, return isValid_. + */ + bool IsValid() const + { + return isValid_; + } + + /** + * Get function, return member variable message. + */ + const void *GetMsgBuf() const + { + return reinterpret_cast(msg_); + } + + /** + * Get function, return message length. + */ + int32_t GetMsgLength() const + { + return isValid_ ? sizeof(AppSpawnMsg) : 0; + } + +private: + /** + * Verify message. + * + * @param startMsg, request message. + */ + bool VerifyMsg(const AppSpawnStartMsg &startMsg) const; + + /** + * Print message. + * + * @param startMsg, request message. + */ + void DumpMsg() const; + + /** + * Release message. + */ + void FreeMsg(); + +private: + bool isValid_ = false; + // because AppSpawnMsg's size is uncertain, so should use raw pointer. + AppSpawnMsg *msg_ = nullptr; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_APP_SPAWN_MSG_WRAPPER_H diff --git a/services/appmgr/include/app_spawn_socket.h b/services/appmgr/include/app_spawn_socket.h new file mode 100644 index 000000000..7ecd69251 --- /dev/null +++ b/services/appmgr/include/app_spawn_socket.h @@ -0,0 +1,84 @@ +/* + * 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_APPMGR_INCLUDE_APP_SPAWN_SOCKET_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_APP_SPAWN_SOCKET_H + +#include + +#include "nocopyable.h" +#include "client_socket.h" +#include "appexecfwk_errors.h" + +namespace OHOS { +namespace AppExecFwk { + +class AppSpawnSocket { +public: + /** + * Constructor. + */ + AppSpawnSocket(); + + /** + * Destructor + */ + virtual ~AppSpawnSocket(); + + /** + * Disable copy. + */ + DISALLOW_COPY_AND_MOVE(AppSpawnSocket); + + /** + * Create client socket and connect the socket. + */ + virtual ErrCode OpenAppSpawnConnection(); + + /** + * Close the client socket. + */ + virtual void CloseAppSpawnConnection(); + + /** + * Write message to the socket. + * + * @param buf, message pointer. + * @param len, message size. + */ + virtual ErrCode WriteMessage(const void *buf, const int32_t len); + + /** + * Read message from the socket. + * + * @param buf, message pointer. + * @param len, message size. + */ + virtual ErrCode ReadMessage(void *buf, const int32_t len); + + /** + * Set function, unit test also use it. + * + * @param clientSocket, client socket. + */ + void SetClientSocket(const std::shared_ptr clientSocket); + +private: + std::shared_ptr clientSocket_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_APP_SPAWN_SOCKET_H \ No newline at end of file diff --git a/services/appmgr/include/cgroup_manager.h b/services/appmgr/include/cgroup_manager.h new file mode 100644 index 000000000..af8da6751 --- /dev/null +++ b/services/appmgr/include/cgroup_manager.h @@ -0,0 +1,79 @@ +/* + * 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_APPMGR_INCLUDE_CGROUP_MANAGER_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_CGROUP_MANAGER_H + +#include +#include +#include + +#include "event_handler.h" +#include "file_descriptor_listener.h" +#include "nocopyable.h" +#include "singleton.h" +#include "unique_fd.h" + +namespace OHOS { +namespace AppExecFwk { + +class CgroupManager : public FileDescriptorListener, public std::enable_shared_from_this { + + DECLARE_DELAYED_SINGLETON(CgroupManager) +public: + enum SchedPolicy { + SCHED_POLICY_DEFAULT = 0, + SCHED_POLICY_BACKGROUND, + SCHED_POLICY_FREEZED, + + SCHED_POLICY_MAX + }; + + enum LowMemoryLevel { + LOW_MEMORY_LEVEL_LOW = 0, + LOW_MEMORY_LEVEL_MEDIUM, + LOW_MEMORY_LEVEL_CRITICAL, + + LOW_MEMORY_LEVEL_MAX + }; + + std::function LowMemoryAlert; + +public: + virtual bool Init(); + virtual bool IsInited() const; + virtual bool SetThreadSchedPolicy(int tid, SchedPolicy schedPolicy); + virtual bool SetProcessSchedPolicy(int pid, SchedPolicy schedPolicy); + virtual void OnReadable(int32_t fd) override; + +private: + std::shared_ptr eventHandler_; + int cpuTasksFds_[SCHED_POLICY_MAX]; + int memoryEventControlFd_; + int memoryEventFds_[LOW_MEMORY_LEVEL_MAX]; + int memoryPressureFds_[LOW_MEMORY_LEVEL_MAX]; + + bool RegisterLowMemoryMonitor(const int memoryEventFds[LOW_MEMORY_LEVEL_MAX], + const int memoryPressureFds[LOW_MEMORY_LEVEL_MAX], const int memoryEventControlFd, const LowMemoryLevel level, + const std::shared_ptr &eventHandler); + bool InitCpuTasksFds(UniqueFd cpuTasksFds[SCHED_POLICY_MAX], size_t len = SCHED_POLICY_MAX); + bool InitMemoryEventControlFd(UniqueFd &memoryEventControlFd); + bool InitMemoryEventFds(UniqueFd memoryEventFds[LOW_MEMORY_LEVEL_MAX], size_t len = LOW_MEMORY_LEVEL_MAX); + bool InitMemoryPressureFds(UniqueFd memoryPressureFds[LOW_MEMORY_LEVEL_MAX], size_t len = LOW_MEMORY_LEVEL_MAX); +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_CGROUP_MANAGER_H diff --git a/services/appmgr/include/lmk_util.h b/services/appmgr/include/lmk_util.h new file mode 100644 index 000000000..1c9653930 --- /dev/null +++ b/services/appmgr/include/lmk_util.h @@ -0,0 +1,48 @@ +/* + * 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_APPMGR_INCLUDE_LMK_MANAGER_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_LMK_MANAGER_H + +#include +#include + +#include "app_running_record.h" +#include "cgroup_manager.h" +#include "nocopyable.h" + +namespace OHOS { +namespace AppExecFwk { + +class LmkUtil : public NoCopyable { +public: + using AppPtr = std::shared_ptr; + +public: + LmkUtil(); + virtual ~LmkUtil(); + DISALLOW_COPY_AND_MOVE(LmkUtil); + + virtual int32_t KillProcess(std::list &listApp, const CgroupManager::LowMemoryLevel level, int64_t &rss); + +private: + std::string GetProcName(pid_t pid); + int32_t GetProcSize(pid_t pid); + ssize_t ReadAll(int fd, char *buf, size_t maxLen); +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_LMK_MANAGER_H diff --git a/services/appmgr/include/lmkd_client.h b/services/appmgr/include/lmkd_client.h new file mode 100644 index 000000000..940f952d9 --- /dev/null +++ b/services/appmgr/include/lmkd_client.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_SERVICES_APPMGR_INCLUDE_LMKD_CLIENT_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_LMKD_CLIENT_H + +#include +#include +#include +#include +#include + +#include "ability_running_record.h" +#include "app_running_record.h" +#include "nocopyable.h" + +namespace OHOS { +namespace AppExecFwk { + +class LmkdClient : public NoCopyable { +public: + using Targets = std::vector>; + +public: + LmkdClient(); + virtual ~LmkdClient(); + virtual int32_t Open(); + virtual void Close(); + virtual bool IsOpen() const; + virtual int32_t Target(const Targets &targets); + virtual int32_t ProcPrio(pid_t pid, uid_t uid, int oomAdj); + virtual int32_t ProcRemove(pid_t pid); + virtual bool ProcPurge(); + static bool CheckOomAdj(int v); + +private: + bool Write(const void *buf, size_t len); + +private: + int socket_; +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_LMKD_CLIENT_H diff --git a/services/appmgr/include/process_optimizer.h b/services/appmgr/include/process_optimizer.h new file mode 100644 index 000000000..9ffef9fd9 --- /dev/null +++ b/services/appmgr/include/process_optimizer.h @@ -0,0 +1,98 @@ +/* + * 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_APPMGR_INCLUDE_PROCESS_OPTIMIZER_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_PROCESS_OPTIMIZER_H + +#include +#include +#include +#include +#include + +#include "ability_running_record.h" +#include "app_running_record.h" +#include "cgroup_manager.h" +#include "lmkd_client.h" +#include "lmk_util.h" +#include "event_handler.h" +#include "nocopyable.h" + +namespace OHOS { +namespace AppExecFwk { + +class ProcessOptimizer : public NoCopyable { +public: + using EventHandlerPtr = std::shared_ptr; + using AppPtr = std::shared_ptr; + using AbilityPtr = std::shared_ptr; + using CgroupManagerPtr = std::shared_ptr; + using LmkdClientPtr = std::shared_ptr; + + static constexpr int APP_SUSPEND_TIMEOUT_DEFAULT = 5000; // in milliseconds + +public: + ProcessOptimizer(const LmkdClientPtr &lmkdClient = nullptr, int suspendTimeout = APP_SUSPEND_TIMEOUT_DEFAULT); + + virtual ~ProcessOptimizer(); + +public: + // callbacks + std::function AppSuspended; + std::function AppResumed; + std::function AppLowMemoryAlert; + std::function GetAbilityOwnerApp; + +public: + virtual bool Init(); + virtual void OnAppAdded(const AppPtr &app); + virtual void OnAppRemoved(const AppPtr &app); + virtual void OnAppStateChanged(const AppPtr &app, const ApplicationState oldState); + virtual void OnAbilityStarted(const AbilityPtr &ability); + virtual void OnAbilityConnected(const AbilityPtr &ability, const AbilityPtr &targetAbility); + virtual void OnAbilityDisconnected(const AbilityPtr &ability, const AbilityPtr &targetAbility); + virtual void OnAbilityStateChanged(const AbilityPtr &ability, const AbilityState oldState); + virtual void OnAbilityVisibleChanged(const AbilityPtr &ability); + virtual void OnAbilityPerceptibleChanged(const AbilityPtr &ability); + virtual void OnAbilityRemoved(const AbilityPtr &ability); + +protected: + bool SetAppOomAdj(const AppPtr &app, int oomAdj); + bool SetAppSchedPolicy(const AppPtr &app, const CgroupManager::SchedPolicy schedPolicy); + virtual void OnLowMemoryAlert(const CgroupManager::LowMemoryLevel level); + +private: + bool UpdateAppOomAdj(const AppPtr &app); + bool UpdateAppSchedPolicy(const AppPtr &app); + void StartAppSuspendTimer(const AppPtr &app); + void StopAppSuspendTimer(const AppPtr &app); + void SuspendApp(const AppPtr &app); + std::string GetAppSuspendTimerName(const AppPtr &app); + +private: + using AppLru = std::list; + using SuspendTimers = std::set; + + LmkdClientPtr lmkdClient_; + AppLru appLru_; + EventHandlerPtr eventHandler_; + SuspendTimers suspendTimers_; + std::unique_ptr lmkUtil_; + int suspendTimeout_; +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_PROCESS_OPTIMIZER_H diff --git a/services/appmgr/include/process_optimizer_uba.h b/services/appmgr/include/process_optimizer_uba.h new file mode 100644 index 000000000..2585bac60 --- /dev/null +++ b/services/appmgr/include/process_optimizer_uba.h @@ -0,0 +1,170 @@ +/* + * 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_APPMGR_INCLUDE_PROCESS_OPTIMIZER_UBA_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_PROCESS_OPTIMIZER_UBA_H + +#include +#include +#include +#include +#include + +#include "process_optimizer.h" + +namespace OHOS { +namespace AppExecFwk { + +// UBA short for User Behavior Analysis +using UbaService = int; +using UbaServicePtr = std::shared_ptr; + +class ProcessOptimizerUBA : public ProcessOptimizer { +public: + using AbilityToken = sptr; + +public: + ProcessOptimizerUBA(const UbaServicePtr &ubaService, const LmkdClientPtr &lmkdClient = nullptr, + int suspendTimeout = APP_SUSPEND_TIMEOUT_DEFAULT); + + virtual ~ProcessOptimizerUBA(); + +public: + // callbacks + std::function GetAbilityByToken; + +public: + void OnAppAdded(const AppPtr &app) override; + void OnAppRemoved(const AppPtr &app) override; + void OnAppStateChanged(const AppPtr &app, const ApplicationState oldState) override; + void OnAbilityStarted(const AbilityPtr &ability) override; + void OnAbilityConnected(const AbilityPtr &ability, const AbilityPtr &targetAbility) override; + void OnAbilityDisconnected(const AbilityPtr &ability, const AbilityPtr &targetAbility) override; + void OnAbilityStateChanged(const AbilityPtr &ability, const AbilityState oldState) override; + void OnAbilityVisibleChanged(const AbilityPtr &ability) override; + void OnAbilityPerceptibleChanged(const AbilityPtr &ability) override; + void OnAbilityRemoved(const AbilityPtr &ability) override; + +protected: + void OnLowMemoryAlert(const CgroupManager::LowMemoryLevel level) override; + +private: + using Clock = std::chrono::system_clock; + using TimePoint = Clock::time_point; + + class BaseAbilityAction { + public: + BaseAbilityAction(const AbilityPtr &ability); + ~BaseAbilityAction() = default; + + TimePoint GetTime() const; + std::string GetTimeString() const; + const std::string &GetName() const; + + private: + TimePoint time_; + std::string name_; + }; + + class StartAbilityAction : public BaseAbilityAction { + public: + StartAbilityAction(const AbilityPtr &ability, const AbilityPtr &preAbility); + ~StartAbilityAction() = default; + + const std::string &GetPreName() const; + + private: + std::string preName_; + }; + + class ConnectAbilityAction : public BaseAbilityAction { + public: + ConnectAbilityAction(const AbilityPtr &ability, const AbilityPtr &targetAbility); + ~ConnectAbilityAction() = default; + + const std::string &GetTargetName() const; + + private: + std::string targetName_; + }; + + class DisconnectAbilityAction : public BaseAbilityAction { + public: + DisconnectAbilityAction(const AbilityPtr &ability, const AbilityPtr &targetAbility); + ~DisconnectAbilityAction() = default; + + const std::string &GetTargetName() const; + + private: + std::string targetName_; + }; + + class ChangeAbilityStateAction : public BaseAbilityAction { + public: + ChangeAbilityStateAction(const AbilityPtr &ability, const AbilityState oldState); + ~ChangeAbilityStateAction() = default; + + AbilityState GetOldState() const; + AbilityState GetNewState() const; + + private: + AbilityState oldState_; + AbilityState newState_; + }; + + class ChangeAbilityVisible : public BaseAbilityAction { + public: + ChangeAbilityVisible(const AbilityPtr &ability); + ~ChangeAbilityVisible() = default; + }; + + class ChangeAbilityPerceptible : public BaseAbilityAction { + public: + ChangeAbilityPerceptible(const AbilityPtr &ability); + ~ChangeAbilityPerceptible() = default; + }; + + class RemoveAbilityAction : public BaseAbilityAction { + public: + RemoveAbilityAction(const AbilityPtr &ability); + ~RemoveAbilityAction() = default; + }; + + using AbilityAction = + std::variant; + + template + void RecordAbilityAction(ARGS... args) + { + abilityActionCache_[abilityActionCount_++].emplace(args...); + if (abilityActionCount_ >= ABILITY_ACTION_CACHE_SIZE) { + CommitAbilityActions(); + } + } + + void CommitAbilityActions(); + UbaServicePtr GetUbaService(); + +private: + UbaServicePtr ubaService_; + static constexpr size_t ABILITY_ACTION_CACHE_SIZE = 100; + AbilityAction abilityActionCache_[ABILITY_ACTION_CACHE_SIZE]; + size_t abilityActionCount_; +}; +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_PROCESS_OPTIMIZER_UBA_H diff --git a/services/appmgr/include/record_query_result.h b/services/appmgr/include/record_query_result.h new file mode 100644 index 000000000..c0a4a8b2a --- /dev/null +++ b/services/appmgr/include/record_query_result.h @@ -0,0 +1,41 @@ +/* + * 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_APPMGR_INCLUDE_APP_MGR_RECORF_QUERY_RESULT_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_APP_MGR_RECORF_QUERY_RESULT_H + +namespace OHOS { +namespace AppExecFwk { + +struct RecordQueryResult { + void Reset() + { + appExists = false; + abilityExists = false; + error = ERR_OK; + appRecordId = 0; + } + // if app not exists, create and set |appRecordId| + int32_t appRecordId = 0; + // if ability not exists, create and set |abilityRecordId| + bool appExists = false; + bool abilityExists = false; + ErrCode error = ERR_OK; +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_APP_MGR_RECORF_QUERY_RESULT_H \ No newline at end of file diff --git a/services/appmgr/include/remote_client_manager.h b/services/appmgr/include/remote_client_manager.h new file mode 100644 index 000000000..1f74b8e27 --- /dev/null +++ b/services/appmgr/include/remote_client_manager.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_APPMGR_INCLUDE_AMS_MGR_REMOTE_CLIENT_MANAGER_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_AMS_MGR_REMOTE_CLIENT_MANAGER_H + +#include "iremote_object.h" +#include "refbase.h" + +#include "app_spawn_client.h" +#include "bundlemgr/bundle_mgr_interface.h" + +namespace OHOS { + +namespace AppExecFwk { + +class RemoteClientManager { +public: + RemoteClientManager(); + virtual ~RemoteClientManager(); + + /** + * GetSpawnClient, Get spawn client. + * + * @return the spawn client instance. + */ + std::shared_ptr GetSpawnClient(); + + /** + * @brief Setting spawn client instance. + * + * @param appSpawnClient, the spawn client instance. + */ + void SetSpawnClient(const std::shared_ptr &appSpawnClient); + + /** + * GetBundleManager, Get bundle management services. + * + * @return the bundle management services instance. + */ + sptr GetBundleManager(); + + /** + * @brief Setting bundle management instance. + * + * @param appSpawnClient, the bundle management instance. + */ + void SetBundleManager(sptr bundleManager); + +private: + std::shared_ptr appSpawnClient_; + sptr bundleManager_; +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_AMS_MGR_REMOTE_CLIENT_MANAGER_H \ No newline at end of file diff --git a/services/appmgr/include/start_via_asan.h b/services/appmgr/include/start_via_asan.h new file mode 100644 index 000000000..a2a1d3cfe --- /dev/null +++ b/services/appmgr/include/start_via_asan.h @@ -0,0 +1,38 @@ +/* + * 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_APPMGR_INCLUDE_START_VIA_ASAN_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_START_VIA_ASAN_H + +#include + +#include "singleton.h" + +#include "app_spawn_client.h" + +namespace OHOS { +namespace AppExecFwk { + +class StartViaAsan { + DECLARE_DELAYED_SINGLETON(StartViaAsan); + +public: + bool IsAsanVersion(const std::string &appName) const; + void GetAsanStartMsg(AppSpawnStartMsg &startMsg) const; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_APPMGR_INCLUDE_START_VIA_ASAN_H \ No newline at end of file diff --git a/services/appmgr/src/ability_running_record.cpp b/services/appmgr/src/ability_running_record.cpp new file mode 100644 index 000000000..95509f607 --- /dev/null +++ b/services/appmgr/src/ability_running_record.cpp @@ -0,0 +1,106 @@ +/* + * 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_running_record.h" + +#include "iremote_object.h" + +namespace OHOS { +namespace AppExecFwk { + +AbilityRunningRecord::AbilityRunningRecord(const std::shared_ptr &info, const sptr &token) + : info_(info), token_(token) +{} + +AbilityRunningRecord::~AbilityRunningRecord() +{} + +const std::string &AbilityRunningRecord::GetName() const +{ + return info_->name; +} + +const std::shared_ptr &AbilityRunningRecord::GetAbilityInfo() const +{ + return info_; +} + +const sptr &AbilityRunningRecord::GetToken() const +{ + return token_; +} + +void AbilityRunningRecord::SetState(const AbilityState state) +{ + state_ = state; +} + +AbilityState AbilityRunningRecord::GetState() const +{ + return state_; +} + +bool AbilityRunningRecord::IsSameState(const AbilityState state) const +{ + return state_ == state; +} + +int32_t AbilityRunningRecord::GetLastLaunchTime() const +{ + return lastLaunchTime_; +} + +const sptr AbilityRunningRecord::GetPreToken() const +{ + return preToken_; +} + +void AbilityRunningRecord::SetPreToken(const sptr &preToken) +{ + preToken_ = preToken; +} + +void AbilityRunningRecord::SetVisibility(const int32_t visibility) +{ + visibility_ = visibility; +} + +int32_t AbilityRunningRecord::GetVisibility() const +{ + return visibility_; +} + +void AbilityRunningRecord::SetPerceptibility(const int32_t perceptibility) +{ + perceptibility_ = perceptibility; +} + +int32_t AbilityRunningRecord::GetPerceptibility() const +{ + return perceptibility_; +} + +void AbilityRunningRecord::SetConnectionState(const int32_t connectionState) +{ + connectionState_ = connectionState; +} + +int32_t AbilityRunningRecord::GetConnectionState() const +{ + return connectionState_; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/appmgr/src/ams_mgr_scheduler.cpp b/services/appmgr/src/ams_mgr_scheduler.cpp new file mode 100644 index 000000000..e3af5278a --- /dev/null +++ b/services/appmgr/src/ams_mgr_scheduler.cpp @@ -0,0 +1,159 @@ +/* + * 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 "ams_mgr_scheduler.h" +#include + +#include "datetime_ex.h" +#include "ipc_skeleton.h" +#include "system_ability_definition.h" + +#include "app_death_recipient.h" +#include "app_log_wrapper.h" +#include "app_mgr_constants.h" +#include "perf_profile.h" + +namespace OHOS { + +namespace AppExecFwk { + +namespace { + +const std::string TASK_LOAD_ABILITY = "LoadAbilityTask"; +const std::string TASK_TERMINATE_ABILITY = "TerminateAbilityTask"; +const std::string TASK_UPDATE_ABILITY_STATE = "UpdateAbilityStateTask"; +const std::string TASK_REGISTER_APP_STATE_CALLBACK = "RegisterAppStateCallbackTask"; +const std::string TASK_STOP_ALL_PROCESS = "StopAllProcessTask"; +const std::string TASK_ABILITY_BEHAVIOR_ANALYSIS = "AbilityBehaviorAnalysisTask"; +const std::string TASK_KILL_PROCESS_BY_ABILITYTOKEN = "KillProcessByAbilityTokenTask"; +const std::string TASK_KILL_APPLICATION = "KillApplicationTask"; +}; // namespace + +AmsMgrScheduler::AmsMgrScheduler( + const std::shared_ptr &mgrServiceInner_, const std::shared_ptr &handler_) + : amsMgrServiceInner_(mgrServiceInner_), amsHandler_(handler_) +{} + +AmsMgrScheduler::~AmsMgrScheduler() +{ + APP_LOGI("AmsMgrScheduler instance destroyed"); +} + +void AmsMgrScheduler::LoadAbility(const sptr &token, const sptr &preToken, + const std::shared_ptr &abilityInfo, const std::shared_ptr &appInfo) +{ + if (!abilityInfo || !appInfo) { + APP_LOGE("param error"); + return; + } + + if (!IsReady()) { + return; + } + PerfProfile::GetInstance().SetAbilityLoadStartTime(GetTickCount()); + std::function loadAbilityFunc = + std::bind(&AppMgrServiceInner::LoadAbility, amsMgrServiceInner_, token, preToken, abilityInfo, appInfo); + + amsHandler_->PostTask(loadAbilityFunc, TASK_LOAD_ABILITY); +} + +void AmsMgrScheduler::UpdateAbilityState(const sptr &token, const AbilityState state) +{ + if (!IsReady()) { + return; + } + std::function updateAbilityStateFunc = + std::bind(&AppMgrServiceInner::UpdateAbilityState, amsMgrServiceInner_, token, state); + amsHandler_->PostTask(updateAbilityStateFunc, TASK_UPDATE_ABILITY_STATE); +} + +void AmsMgrScheduler::TerminateAbility(const sptr &token) +{ + if (!IsReady()) { + return; + } + std::function terminateAbilityFunc = + std::bind(&AppMgrServiceInner::TerminateAbility, amsMgrServiceInner_, token); + amsHandler_->PostTask(terminateAbilityFunc, TASK_TERMINATE_ABILITY); +} + +void AmsMgrScheduler::RegisterAppStateCallback(const sptr &callback) +{ + if (!IsReady()) { + return; + } + std::function registerAppStateCallbackFunc = + std::bind(&AppMgrServiceInner::RegisterAppStateCallback, amsMgrServiceInner_, callback); + amsHandler_->PostTask(registerAppStateCallbackFunc, TASK_REGISTER_APP_STATE_CALLBACK); +} + +void AmsMgrScheduler::Reset() +{ + if (!IsReady()) { + return; + } + std::function resetFunc = std::bind(&AppMgrServiceInner::StopAllProcess, amsMgrServiceInner_); + amsHandler_->PostTask(resetFunc, TASK_STOP_ALL_PROCESS); +} + +void AmsMgrScheduler::AbilityBehaviorAnalysis(const sptr &token, const sptr &preToken, + const int32_t visibility, const int32_t perceptibility, const int32_t connectionState) +{ + if (!IsReady()) { + return; + } + std::function abilityBehaviorAnalysisFunc = std::bind(&AppMgrServiceInner::AbilityBehaviorAnalysis, + amsMgrServiceInner_, + token, + preToken, + visibility, + perceptibility, + connectionState); + amsHandler_->PostTask(abilityBehaviorAnalysisFunc, TASK_ABILITY_BEHAVIOR_ANALYSIS); +} + +void AmsMgrScheduler::KillProcessByAbilityToken(const sptr &token) +{ + if (!IsReady()) { + return; + } + std::function killProcessByAbilityTokenFunc = + std::bind(&AppMgrServiceInner::KillProcessByAbilityToken, amsMgrServiceInner_, token); + amsHandler_->PostTask(killProcessByAbilityTokenFunc, TASK_KILL_PROCESS_BY_ABILITYTOKEN); +} + +int32_t AmsMgrScheduler::KillApplication(const std::string &bundleName) +{ + if (!IsReady()) { + return ERR_INVALID_OPERATION; + } + return amsMgrServiceInner_->KillApplication(bundleName); +} + +bool AmsMgrScheduler::IsReady() const +{ + if (!amsMgrServiceInner_) { + APP_LOGE("amsMgrServiceInner_ is null"); + return false; + } + if (!amsHandler_) { + APP_LOGE("amsHandler_ is null"); + return false; + } + return true; +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/appmgr/src/app_death_recipient.cpp b/services/appmgr/src/app_death_recipient.cpp new file mode 100644 index 000000000..c9181e1d4 --- /dev/null +++ b/services/appmgr/src/app_death_recipient.cpp @@ -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. + */ + +#include "app_death_recipient.h" + +#include "app_log_wrapper.h" +#include "app_mgr_service_inner.h" + +namespace OHOS { +namespace AppExecFwk { +namespace { + +const std::string TASK_ON_REMOTE_DIED = "OnRemoteDiedTask"; +} + +void AppDeathRecipient::OnRemoteDied(const wptr &remote) +{ + if (remote == nullptr) { + APP_LOGE("remote is null"); + return; + } + + auto handler = handler_.lock(); + if (!handler) { + APP_LOGE("handler is null"); + return; + } + auto serviceInner = appMgrServiceInner_.lock(); + if (!serviceInner) { + APP_LOGE("serviceInner is null"); + return; + } + + std::function onRemoteDiedFunc = std::bind(&AppMgrServiceInner::OnRemoteDied, serviceInner, remote); + handler->PostTask(onRemoteDiedFunc, TASK_ON_REMOTE_DIED); +} + +void AppDeathRecipient::SetEventHandler(const std::shared_ptr &handler) +{ + handler_ = handler; +} + +void AppDeathRecipient::SetAppMgrServiceInner(const std::shared_ptr &serviceInner) +{ + appMgrServiceInner_ = serviceInner; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/appmgr/src/app_lifecycle_deal.cpp b/services/appmgr/src/app_lifecycle_deal.cpp new file mode 100644 index 000000000..99d47aa61 --- /dev/null +++ b/services/appmgr/src/app_lifecycle_deal.cpp @@ -0,0 +1,99 @@ +/* + * 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_lifecycle_deal.h" +#include "app_log_wrapper.h" + +namespace OHOS { + +namespace AppExecFwk { + +AppLifeCycleDeal::AppLifeCycleDeal() +{} + +AppLifeCycleDeal::~AppLifeCycleDeal() +{} + +void AppLifeCycleDeal::LaunchApplication(const AppLaunchData &launchData_) +{ + appThread_->ScheduleLaunchApplication(launchData_); +} + +void AppLifeCycleDeal::LaunchAbility(const std::shared_ptr &ability) +{ + appThread_->ScheduleLaunchAbility(*(ability->GetAbilityInfo()), ability->GetToken()); +} + +void AppLifeCycleDeal::ScheduleTerminate() +{ + if (appThread_) { + appThread_->ScheduleTerminateApplication(); + } +} + +void AppLifeCycleDeal::ScheduleForegroundRunning() +{ + if (appThread_) { + appThread_->ScheduleForegroundApplication(); + } +} + +void AppLifeCycleDeal::ScheduleBackgroundRunning() +{ + if (appThread_) { + appThread_->ScheduleBackgroundApplication(); + } +} + +void AppLifeCycleDeal::ScheduleTrimMemory(int32_t timeLevel) +{ + if (appThread_) { + appThread_->ScheduleShrinkMemory(timeLevel); + } +} + +void AppLifeCycleDeal::LowMemoryWarning() +{ + if (appThread_) { + appThread_->ScheduleLowMemory(); + } +} + +void AppLifeCycleDeal::ScheduleCleanAbility(const sptr &token) +{ + if (appThread_) { + appThread_->ScheduleCleanAbility(token); + } +} + +void AppLifeCycleDeal::ScheduleProcessSecurityExit() +{ + if (appThread_) { + appThread_->ScheduleProcessSecurityExit(); + } +} + +void AppLifeCycleDeal::SetApplicationClient(const sptr &thread) +{ + appThread_ = thread; +} + +sptr AppLifeCycleDeal::GetApplicationClient() const +{ + return appThread_; +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/appmgr/src/app_mgr_service.cpp b/services/appmgr/src/app_mgr_service.cpp new file mode 100644 index 000000000..16be2c759 --- /dev/null +++ b/services/appmgr/src/app_mgr_service.cpp @@ -0,0 +1,267 @@ +/* + * 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_mgr_service.h" + +#include + +#include "datetime_ex.h" +#include "ipc_skeleton.h" +#include "system_ability_definition.h" + +#include "app_death_recipient.h" +#include "app_log_wrapper.h" +#include "app_mgr_constants.h" +#include "perf_profile.h" + +namespace OHOS { +namespace AppExecFwk { +namespace { + +const std::string TASK_ATTACH_APPLICATION = "AttachApplicationTask"; +const std::string TASK_APPLICATION_FOREGROUNDED = "ApplicationForegroundedTask"; +const std::string TASK_APPLICATION_BACKGROUNDED = "ApplicationBackgroundedTask"; +const std::string TASK_APPLICATION_TERMINATED = "ApplicationTerminatedTask"; +const std::string TASK_ABILITY_CLEANED = "AbilityCleanedTask"; +const std::string TASK_ADD_APP_DEATH_RECIPIENT = "AddAppRecipientTask"; +const std::string TASK_CLEAR_UP_APPLICATION_DATA = "ClearUpApplicationDataTask"; + +} // namespace + +REGISTER_SYSTEM_ABILITY_BY_ID(AppMgrService, APP_MGR_SERVICE_ID, true); + +AppMgrService::AppMgrService() +{ + appMgrServiceInner_ = std::make_shared(); + APP_LOGI("instance created with no para"); + PerfProfile::GetInstance().SetAmsLoadStartTime(GetTickCount()); +} + +AppMgrService::AppMgrService(const int32_t serviceId, bool runOnCreate) : SystemAbility(serviceId, runOnCreate) +{ + appMgrServiceInner_ = std::make_shared(); + APP_LOGI("instance created"); + PerfProfile::GetInstance().SetAmsLoadStartTime(GetTickCount()); +} + +AppMgrService::~AppMgrService() +{ + APP_LOGI("instance destroyed"); +} + +void AppMgrService::OnStart() +{ + APP_LOGI("ready to start service"); + if (appMgrServiceState_.serviceRunningState == ServiceRunningState::STATE_RUNNING) { + APP_LOGW("failed to start service since it's already running"); + return; + } + + ErrCode errCode = Init(); + if (FAILED(errCode)) { + APP_LOGE("init failed, errCode: %{public}08x", errCode); + return; + } + appMgrServiceState_.serviceRunningState = ServiceRunningState::STATE_RUNNING; + APP_LOGI("start service success"); + PerfProfile::GetInstance().SetAmsLoadEndTime(GetTickCount()); + PerfProfile::GetInstance().Dump(); +} + +void AppMgrService::OnStop() +{ + APP_LOGI("ready to stop service"); + appMgrServiceState_.serviceRunningState = ServiceRunningState::STATE_NOT_START; + handler_.reset(); + runner_.reset(); + if (appMgrServiceInner_) { + appMgrServiceInner_->OnStop(); + } + APP_LOGI("stop service success"); +} + +void AppMgrService::SetInnerService(const std::shared_ptr &innerService) +{ + appMgrServiceInner_ = innerService; +} + +AppMgrServiceState AppMgrService::QueryServiceState() +{ + if (appMgrServiceInner_) { + appMgrServiceState_.connectionState = appMgrServiceInner_->QueryAppSpawnConnectionState(); + } + return appMgrServiceState_; +} + +ErrCode AppMgrService::Init() +{ + APP_LOGI("ready to init"); + // start main thread message loop. + runner_ = EventRunner::Create(Constants::APP_MGR_SERVICE_NAME); + if (!runner_) { + APP_LOGE("init failed due to create runner error"); + return ERR_INVALID_OPERATION; + } + if (!appMgrServiceInner_) { + APP_LOGE("init failed without inner service"); + return ERR_INVALID_OPERATION; + } + handler_ = std::make_shared(runner_, appMgrServiceInner_); + if (!handler_) { + APP_LOGE("init failed without handler"); + return ERR_INVALID_OPERATION; + } + ErrCode openErr = appMgrServiceInner_->OpenAppSpawnConnection(); + if (FAILED(openErr)) { + APP_LOGW("failed to connect to AppSpawnDaemon! errCode: %{public}08x", openErr); + } + if (!Publish(this)) { + APP_LOGE("failed to publish appmgrservice to systemAbilityMgr"); + return ERR_APPEXECFWK_SERVICE_NOT_CONNECTED; + } + amsMgrScheduler_ = new (std::nothrow) AmsMgrScheduler(appMgrServiceInner_, handler_); + if (!amsMgrScheduler_) { + APP_LOGE("init failed without ams scheduler"); + return ERR_INVALID_OPERATION; + } + if (appMgrServiceInner_->ProcessOptimizerInit() != ERR_OK) { + APP_LOGE("init failed without process optimizer"); + } + APP_LOGI("init success"); + return ERR_OK; +} + +int32_t AppMgrService::CheckPermission( + [[maybe_unused]] const int32_t recordId, [[maybe_unused]] const std::string &permission) +{ + APP_LOGI("check application's permission"); + + return ERR_OK; +} + +void AppMgrService::AttachApplication(const sptr &app) +{ + if (!IsReady()) { + return; + } + + pid_t pid = IPCSkeleton::GetCallingPid(); + AddAppDeathRecipient(pid); + std::function attachApplicationFunc = + std::bind(&AppMgrServiceInner::AttachApplication, appMgrServiceInner_, pid, iface_cast(app)); + handler_->PostTask(attachApplicationFunc, TASK_ATTACH_APPLICATION); +} + +void AppMgrService::ApplicationForegrounded(const int32_t recordId) +{ + if (!IsReady()) { + return; + } + std::function applicationForegroundedFunc = + std::bind(&AppMgrServiceInner::ApplicationForegrounded, appMgrServiceInner_, recordId); + handler_->PostTask(applicationForegroundedFunc, TASK_APPLICATION_FOREGROUNDED); +} + +void AppMgrService::ApplicationBackgrounded(const int32_t recordId) +{ + if (!IsReady()) { + return; + } + std::function applicationBackgroundedFunc = + std::bind(&AppMgrServiceInner::ApplicationBackgrounded, appMgrServiceInner_, recordId); + handler_->PostTask(applicationBackgroundedFunc, TASK_APPLICATION_BACKGROUNDED); +} + +void AppMgrService::ApplicationTerminated(const int32_t recordId) +{ + if (!IsReady()) { + return; + } + std::function applicationTerminatedFunc = + std::bind(&AppMgrServiceInner::ApplicationTerminated, appMgrServiceInner_, recordId); + handler_->PostTask(applicationTerminatedFunc, TASK_APPLICATION_TERMINATED); +} + +void AppMgrService::AbilityCleaned(const sptr &token) +{ + if (!IsReady()) { + return; + } + std::function abilityCleanedFunc = + std::bind(&AppMgrServiceInner::AbilityTerminated, appMgrServiceInner_, token); + handler_->PostTask(abilityCleanedFunc, TASK_ABILITY_CLEANED); +} + +bool AppMgrService::IsReady() const +{ + if (!appMgrServiceInner_) { + APP_LOGE("appMgrServiceInner is null"); + return false; + } + if (!handler_) { + APP_LOGE("handler is null"); + return false; + } + return true; +} + +void AppMgrService::AddAppDeathRecipient(const pid_t pid) const +{ + if (!IsReady()) { + return; + } + sptr appDeathRecipient = new AppDeathRecipient(); + appDeathRecipient->SetEventHandler(handler_); + appDeathRecipient->SetAppMgrServiceInner(appMgrServiceInner_); + std::function addAppRecipientFunc = + std::bind(&AppMgrServiceInner::AddAppDeathRecipient, appMgrServiceInner_, pid, appDeathRecipient); + handler_->PostTask(addAppRecipientFunc, TASK_ADD_APP_DEATH_RECIPIENT); +} + +sptr AppMgrService::GetAmsMgr() +{ + return amsMgrScheduler_; +} + +void AppMgrService::ClearUpApplicationData(const std::string &bundleName) +{ + if (!IsReady()) { + return; + } + int32_t uid = IPCSkeleton::GetCallingUid(); + pid_t pid = IPCSkeleton::GetCallingPid(); + std::function clearUpApplicationDataFunc = + std::bind(&AppMgrServiceInner::ClearUpApplicationData, appMgrServiceInner_, bundleName, uid, pid); + handler_->PostTask(clearUpApplicationDataFunc, TASK_CLEAR_UP_APPLICATION_DATA); +} + +int32_t AppMgrService::IsBackgroundRunningRestricted(const std::string &bundleName) +{ + if (!IsReady()) { + return ERR_INVALID_OPERATION; + } + return appMgrServiceInner_->IsBackgroundRunningRestricted(bundleName); +} + +int32_t AppMgrService::GetAllRunningProcesses(std::shared_ptr &runningProcessInfo) +{ + if (!IsReady()) { + return ERR_INVALID_OPERATION; + } + return appMgrServiceInner_->GetAllRunningProcesses(runningProcessInfo); +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/appmgr/src/app_mgr_service_event_handler.cpp b/services/appmgr/src/app_mgr_service_event_handler.cpp new file mode 100644 index 000000000..3c47e5001 --- /dev/null +++ b/services/appmgr/src/app_mgr_service_event_handler.cpp @@ -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. + */ + +#include "app_mgr_service_event_handler.h" + +#include "app_log_wrapper.h" +#include "app_mgr_service_inner.h" + +namespace OHOS { +namespace AppExecFwk { + +AMSEventHandler::AMSEventHandler( + const std::shared_ptr &runner, const std::shared_ptr &ams) + : EventHandler(runner), ams_(ams) +{ + APP_LOGI("instance created"); +} + +AMSEventHandler::~AMSEventHandler() +{ + APP_LOGI("instance destroyed"); +} + +void AMSEventHandler::ProcessEvent([[maybe_unused]] const InnerEvent::Pointer &event) +{} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/appmgr/src/app_mgr_service_inner.cpp b/services/appmgr/src/app_mgr_service_inner.cpp new file mode 100644 index 000000000..eb7f0b26f --- /dev/null +++ b/services/appmgr/src/app_mgr_service_inner.cpp @@ -0,0 +1,1028 @@ +/* + * 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_mgr_service_inner.h" + +#include +#include +#include + +#include "app_log_wrapper.h" +#include "perf_profile.h" +#include "datetime_ex.h" + +#include "iservice_registry.h" +#include "system_ability_definition.h" +#include "iremote_object.h" + +#include "app_process_data.h" +namespace OHOS { +namespace AppExecFwk { +namespace { + +// NANOSECONDS mean 10^9 nano second +constexpr int64_t NANOSECONDS = 1000000000; +// MICROSECONDS mean 10^6 millias second +constexpr int64_t MICROSECONDS = 1000000; +// Kill process timeout setting +constexpr int KILL_PROCESS_TIMEOUT_MICRO_SECONDS = 1000; +// Kill process delaytime setting +constexpr int KILL_PROCESS_DELAYTIME_MICRO_SECONDS = 200; +const std::string CLASS_NAME = "ohos.app.MainThread"; +const std::string FUNC_NAME = "main"; +const std::string SO_PATH = "system/lib64/libmapleappkit.z.so"; +const int32_t SIGNAL_KILL = 9; +const std::string REQ_PERMISSION = "ohos.permission.LOCATION_IN_BACKGROUND"; + +} // namespace + +AppMgrServiceInner::AppMgrServiceInner() + : appProcessManager_(std::make_shared()), + remoteClientManager_(std::make_shared()), + appRunningManager_(std::make_shared()) +{} + +AppMgrServiceInner::~AppMgrServiceInner() +{} + +void AppMgrServiceInner::LoadAbility(const sptr &token, const sptr &preToken, + const std::shared_ptr &abilityInfo, const std::shared_ptr &appInfo) +{ + if (!token || !abilityInfo || !appInfo) { + APP_LOGE("param error"); + return; + } + if (abilityInfo->name.empty() || appInfo->name.empty()) { + APP_LOGE("error abilityInfo or appInfo"); + return; + } + if (abilityInfo->applicationName != appInfo->name) { + APP_LOGE("abilityInfo and appInfo have different appName, don't load for it"); + return; + } + + std::string processName; + if (abilityInfo->process.empty()) { + processName = appInfo->bundleName; + } else { + processName = abilityInfo->process; + } + auto appRecord = GetAppRunningRecordByProcessName(appInfo->name, processName); + if (!appRecord) { + RecordQueryResult result; + int32_t defaultUid = 0; + appRecord = GetOrCreateAppRunningRecord(token, appInfo, abilityInfo, processName, defaultUid, result); + if (FAILED(result.error)) { + APP_LOGE("create appRunningRecord failed"); + return; + } + if (preToken != nullptr) { + auto abilityRecord = appRecord->GetAbilityRunningRecordByToken(token); + abilityRecord->SetPreToken(preToken); + } + StartProcess(abilityInfo->applicationName, processName, appRecord); + } else { + StartAbility(token, preToken, abilityInfo, appRecord); + } + PerfProfile::GetInstance().SetAbilityLoadEndTime(GetTickCount()); + PerfProfile::GetInstance().Dump(); + PerfProfile::GetInstance().Reset(); +} + +void AppMgrServiceInner::AttachApplication(const pid_t pid, const sptr &app) +{ + if (pid <= 0) { + APP_LOGE("invalid pid:%{public}d", pid); + return; + } + if (!app) { + APP_LOGE("app client is null"); + return; + } + APP_LOGI("attach application pid:%{public}d", pid); + auto appRecord = GetAppRunningRecordByPid(pid); + if (!appRecord) { + APP_LOGE("no such appRecord"); + return; + } + appRecord->SetApplicationClient(app); + if (appRecord->GetState() == ApplicationState::APP_STATE_CREATE) { + LaunchApplication(appRecord); + } + appRecord->RegisterAppDeathRecipient(); +} + +void AppMgrServiceInner::LaunchApplication(const std::shared_ptr &appRecord) +{ + if (!appRecord) { + APP_LOGE("appRecord is null"); + return; + } + if (appRecord->GetState() != ApplicationState::APP_STATE_CREATE) { + APP_LOGE("wrong app state"); + return; + } + appRecord->LaunchApplication(); + appRecord->SetState(ApplicationState::APP_STATE_READY); + OptimizerAppStateChanged(appRecord, ApplicationState::APP_STATE_CREATE); + appRecord->LaunchPendingAbilities(); +} + +void AppMgrServiceInner::ApplicationForegrounded(const int32_t recordId) +{ + auto appRecord = GetAppRunningRecordByAppRecordId(recordId); + if (!appRecord) { + APP_LOGE("get app record failed"); + return; + } + appRecord->PopForegroundingAbilityTokens(); + ApplicationState appState = appRecord->GetState(); + if (appState == ApplicationState::APP_STATE_READY || appState == ApplicationState::APP_STATE_BACKGROUND) { + appRecord->SetState(ApplicationState::APP_STATE_FOREGROUND); + OptimizerAppStateChanged(appRecord, appState); + OnAppStateChanged(appRecord, ApplicationState::APP_STATE_FOREGROUND); + } else { + APP_LOGW("app name(%{public}s), app state(%{public}d)!", + appRecord->GetName().c_str(), + static_cast(appState)); + } + + // push the foregrounded app front of RecentAppList. + PushAppFront(recordId); + APP_LOGI("application is foregrounded"); +} + +void AppMgrServiceInner::ApplicationBackgrounded(const int32_t recordId) +{ + auto appRecord = GetAppRunningRecordByAppRecordId(recordId); + if (!appRecord) { + APP_LOGE("get app record failed"); + return; + } + if (appRecord->GetState() == ApplicationState::APP_STATE_FOREGROUND) { + appRecord->SetState(ApplicationState::APP_STATE_BACKGROUND); + OptimizerAppStateChanged(appRecord, ApplicationState::APP_STATE_FOREGROUND); + OnAppStateChanged(appRecord, ApplicationState::APP_STATE_BACKGROUND); + } else { + APP_LOGW("app name(%{public}s), app state(%{public}d)!", + appRecord->GetName().c_str(), + static_cast(appRecord->GetState())); + } + + APP_LOGI("application is backgrounded"); +} + +void AppMgrServiceInner::ApplicationTerminated(const int32_t recordId) +{ + auto appRecord = GetAppRunningRecordByAppRecordId(recordId); + if (!appRecord) { + APP_LOGE("get app record failed"); + return; + } + if (appRecord->GetState() != ApplicationState::APP_STATE_BACKGROUND) { + APP_LOGE("current state is not background"); + return; + } + appRecord->SetState(ApplicationState::APP_STATE_TERMINATED); + OptimizerAppStateChanged(appRecord, ApplicationState::APP_STATE_BACKGROUND); + appRecord->RemoveAppDeathRecipient(); + OnAppStateChanged(appRecord, ApplicationState::APP_STATE_TERMINATED); + appRunningManager_->RemoveAppRunningRecordById(recordId); + RemoveAppFromRecentListById(recordId); + + APP_LOGI("application is terminated"); +} + +int32_t AppMgrServiceInner::KillApplication(const std::string &bundleName) +{ + int result = ERR_OK; + int64_t startTime = SystemTimeMillis(); + std::list pids; + if (!GetPidsByBundleName(bundleName, pids)) { + APP_LOGI("The process corresponding to the package name did not start"); + return result; + } + if (WaitForRemoteProcessExit(pids, startTime)) { + APP_LOGI("The remote process exited successfully "); + return result; + } + for (auto iter = pids.begin(); iter != pids.end(); ++iter) { + result = KillProcessByPid(*iter); + if (result < 0) { + APP_LOGE("KillApplication is fail bundleName: %{public}s pid: %{public}d", bundleName.c_str(), *iter); + return result; + } + } + return result; +} + +void AppMgrServiceInner::ClearUpApplicationData(const std::string &bundleName, int32_t uid, pid_t pid) +{ + if (pid <= 0) { + APP_LOGE("invalid pid:%{public}d", pid); + return; + } + if (uid <= 0) { + APP_LOGE("invalid uid:%{public}d", uid); + return; + } + auto bundleMgr_ = remoteClientManager_->GetBundleManager(); + if (bundleMgr_ == nullptr) { + APP_LOGE("GetBundleManager fail"); + return; + } + int32_t result = 0; + int32_t bmsUid = bundleMgr_->GetUidByBundleName(bundleName, 0); + if (bmsUid != uid) { + result = bundleMgr_->CheckPermission(bundleName, REQ_PERMISSION); + if (result) { + APP_LOGE("No permission to clear application data"); + return; + } + } else { + result = bundleMgr_->CheckPermission(bundleName, REQ_PERMISSION); + if (result) { + // request to clear user information permission. + } + } + // 2.delete bundle side user data + if (!bundleMgr_->CleanBundleDataFiles(bundleName)) { + APP_LOGE("Delete bundle side user data is fail"); + return; + } + // 3.kill application + // 4.revoke user rights + result = KillApplication(bundleName); + if (result < 0) { + APP_LOGE("Kill Application by bundle name is fail"); + return; + } +} + +int32_t AppMgrServiceInner::IsBackgroundRunningRestricted(const std::string &bundleName) +{ + auto bundleMgr_ = remoteClientManager_->GetBundleManager(); + if (bundleMgr_ == nullptr) { + APP_LOGE("GetBundleManager fail"); + return ERR_DEAD_OBJECT; + } + return bundleMgr_->CheckPermission(bundleName, REQ_PERMISSION); +} + +int32_t AppMgrServiceInner::GetAllRunningProcesses(std::shared_ptr &runningProcessInfo) +{ + auto bundleMgr_ = remoteClientManager_->GetBundleManager(); + if (bundleMgr_ == nullptr) { + APP_LOGE("GetBundleManager fail"); + return ERR_DEAD_OBJECT; + } + // check permission + for (const auto &item : appRunningManager_->GetAppRunningRecordMap()) { + const auto &appRecord = item.second; + AppProcessInfo appProcessInfo_; + appProcessInfo_.processName_ = appRecord->GetName(); + appProcessInfo_.pid_ = appRecord->GetPriorityObject()->GetPid(); + appProcessInfo_.uid_ = appRecord->GetUid(); + appProcessInfo_.state_ = static_cast(appRecord->GetState()); + runningProcessInfo->appProcessInfos.push_back(appProcessInfo_); + } + return ERR_OK; +} + +int32_t AppMgrServiceInner::KillProcessByPid(const pid_t pid) const +{ + int32_t ret = -1; + if (pid > 0) { + APP_LOGI("kill pid %{public}d", pid); + ret = kill(pid, SIGNAL_KILL); + } + return ret; +} + +bool AppMgrServiceInner::WaitForRemoteProcessExit(std::list &pids, const int64_t startTime) +{ + int64_t delayTime = SystemTimeMillis() - startTime; + while (delayTime < KILL_PROCESS_TIMEOUT_MICRO_SECONDS) { + if (CheckALLProcessExist(pids)) { + return true; + } + usleep(KILL_PROCESS_DELAYTIME_MICRO_SECONDS); + delayTime = SystemTimeMillis() - startTime; + } + return false; +} + +bool AppMgrServiceInner::GetPidsByBundleName(const std::string &bundleName, std::list &pids) +{ + for (const auto &item : appRunningManager_->GetAppRunningRecordMap()) { + const auto &appRecord = item.second; + if (appRecord->GetBundleName() == bundleName) { + pid_t pid = appRecord->GetPriorityObject()->GetPid(); + if (pid > 0) { + pids.push_back(pid); + appRecord->ScheduleProcessSecurityExit(); + } + } + } + + return (pids.empty() ? false : true); +} + +bool AppMgrServiceInner::GetAllPids(std::list &pids) +{ + for (const auto &appTaskInfo : appProcessManager_->GetRecentAppList()) { + if (appTaskInfo) { + auto appRecord = GetAppRunningRecordByPid(appTaskInfo->GetPid()); + if (appRecord) { + pids.push_back(appTaskInfo->GetPid()); + appRecord->ScheduleProcessSecurityExit(); + } + } + } + return (pids.empty() ? false : true); +} + +bool AppMgrServiceInner::process_exist(pid_t &pid) +{ + char pid_path[128] = {0}; + struct stat stat_buf; + if (!pid) { + return false; + } + if (snprintf_s(pid_path, sizeof(pid_path), sizeof(pid_path) - 1, "/proc/%d/status", pid) < 0) { + return false; + } + if (stat(pid_path, &stat_buf) == 0) { + return true; + } + return false; +} + +bool AppMgrServiceInner::CheckALLProcessExist(std::list &pids) +{ + for (auto iter = pids.begin(); iter != pids.end();) { + if (!process_exist(*iter) && pids.size() != 0) { + pids.erase(iter); + if (pids.empty()) { + return true; + } + } else { + iter++; + } + } + return false; +} + +int64_t AppMgrServiceInner::SystemTimeMillis() +{ + struct timespec t; + t.tv_sec = 0; + t.tv_nsec = 0; + clock_gettime(CLOCK_MONOTONIC, &t); + return (int64_t)((t.tv_sec) * NANOSECONDS + t.tv_nsec) / MICROSECONDS; +} + +std::shared_ptr AppMgrServiceInner::GetAppRunningRecordByAppName(const std::string &appName) const +{ + return appRunningManager_->GetAppRunningRecordByAppName(appName); +} + +std::shared_ptr AppMgrServiceInner::GetAppRunningRecordByProcessName( + const std::string &appName, const std::string &processName) const +{ + return appRunningManager_->GetAppRunningRecordByProcessName(appName, processName); +} + +std::shared_ptr AppMgrServiceInner::GetAppRunningRecordByPid(const pid_t pid) const +{ + return appRunningManager_->GetAppRunningRecordByPid(pid); +} + +std::shared_ptr AppMgrServiceInner::GetOrCreateAppRunningRecord(const sptr &token, + const std::shared_ptr &appInfo, const std::shared_ptr &abilityInfo, + const std::string &processName, const int32_t uid, RecordQueryResult &result) +{ + return appRunningManager_->GetOrCreateAppRunningRecord(token, appInfo, abilityInfo, processName, uid, result); +} + +void AppMgrServiceInner::TerminateAbility(const sptr &token) +{ + APP_LOGD("AppMgrServiceInner::TerminateAbility begin"); + if (!token) { + APP_LOGE("AppMgrServiceInner::TerminateAbility token is null!"); + return; + } + auto appRecord = GetAppRunningRecordByAbilityToken(token); + if (!appRecord) { + APP_LOGE("AppMgrServiceInner::TerminateAbility app is not exist!"); + return; + } + if (appRecord->GetState() == ApplicationState::APP_STATE_SUSPENDED) { + UnsuspendApplication(appRecord); + OptimizerAppStateChanged(appRecord, ApplicationState::APP_STATE_SUSPENDED); + } + appRecord->TerminateAbility(token); + APP_LOGD("AppMgrServiceInner::TerminateAbility end"); +} + +void AppMgrServiceInner::UpdateAbilityState(const sptr &token, const AbilityState state) +{ + if (!token) { + APP_LOGE("token is null!"); + return; + } + if (state > AbilityState::ABILITY_STATE_BACKGROUND || state < AbilityState::ABILITY_STATE_FOREGROUND) { + APP_LOGE("state is not foreground or background!"); + return; + } + auto appRecord = GetAppRunningRecordByAbilityToken(token); + if (!appRecord) { + APP_LOGE("app is not exist!"); + return; + } + auto abilityRecord = appRecord->GetAbilityRunningRecordByToken(token); + if (!abilityRecord) { + APP_LOGE("can not find ability record!"); + return; + } + if (state == abilityRecord->GetState()) { + APP_LOGE("current state is already, no need update!"); + return; + } + if (appRecord->GetState() == ApplicationState::APP_STATE_SUSPENDED) { + UnsuspendApplication(appRecord); + OptimizerAppStateChanged(appRecord, ApplicationState::APP_STATE_SUSPENDED); + } + appRecord->UpdateAbilityState(token, state); + APP_LOGD("end"); +} + +void AppMgrServiceInner::OnStop() +{ + appRunningManager_->ClearAppRunningRecordMap(); + CloseAppSpawnConnection(); +} + +ErrCode AppMgrServiceInner::OpenAppSpawnConnection() +{ + if (remoteClientManager_->GetSpawnClient()) { + return remoteClientManager_->GetSpawnClient()->OpenConnection(); + } + return ERR_APPEXECFWK_BAD_APPSPAWN_CLIENT; +} + +void AppMgrServiceInner::CloseAppSpawnConnection() const +{ + if (remoteClientManager_->GetSpawnClient()) { + remoteClientManager_->GetSpawnClient()->CloseConnection(); + } +} + +SpawnConnectionState AppMgrServiceInner::QueryAppSpawnConnectionState() const +{ + if (remoteClientManager_->GetSpawnClient()) { + return remoteClientManager_->GetSpawnClient()->QueryConnectionState(); + } + return SpawnConnectionState::STATE_NOT_CONNECT; +} + +const std::map> &AppMgrServiceInner::GetRecordMap() const +{ + return appRunningManager_->GetAppRunningRecordMap(); +} + +void AppMgrServiceInner::SetAppSpawnClient(std::shared_ptr spawnClient) +{ + remoteClientManager_->SetSpawnClient(std::move(spawnClient)); +} + +void AppMgrServiceInner::SetBundleManager(sptr bundleManager) +{ + remoteClientManager_->SetBundleManager(bundleManager); +} + +void AppMgrServiceInner::RegisterAppStateCallback(const sptr &callback) +{ + if (callback != nullptr) { + appStateCallbacks_.push_back(callback); + } +} + +void AppMgrServiceInner::StopAllProcess() +{ + ClearRecentAppList(); + appRunningManager_->ClearAppRunningRecordMap(); +} + +void AppMgrServiceInner::AbilityBehaviorAnalysis(const sptr &token, const sptr &preToken, + const int32_t visibility, // 0:false,1:true + const int32_t perceptibility, // 0:false,1:true + const int32_t connectionState) // 0:false,1:true +{ + if (!token) { + APP_LOGE("token is null"); + return; + } + auto appRecord = GetAppRunningRecordByAbilityToken(token); + if (!appRecord) { + APP_LOGE("app record is not exist for ability token"); + return; + } + auto abilityRecord = appRecord->GetAbilityRunningRecordByToken(token); + if (!abilityRecord) { + APP_LOGE("ability record is not exist for ability previous token"); + return; + } + if (preToken) { + abilityRecord->SetPreToken(preToken); + } + if (abilityRecord->GetVisibility() != visibility) { + if (processOptimizerUBA_) { + processOptimizerUBA_->OnAbilityVisibleChanged(abilityRecord); + } + } + if (abilityRecord->GetPerceptibility() != perceptibility) { + if (processOptimizerUBA_) { + processOptimizerUBA_->OnAbilityPerceptibleChanged(abilityRecord); + } + } + abilityRecord->SetVisibility(visibility); + abilityRecord->SetPerceptibility(perceptibility); + abilityRecord->SetConnectionState(connectionState); + OptimizerAbilityStateChanged(abilityRecord, abilityRecord->GetState()); +} + +void AppMgrServiceInner::KillProcessByAbilityToken(const sptr &token) +{ + if (!token) { + APP_LOGE("token is null"); + return; + } + auto appRecord = GetAppRunningRecordByAbilityToken(token); + if (!appRecord) { + APP_LOGE("app record is not exist for ability token"); + return; + } + std::list pids; + pid_t pid = appRecord->GetPriorityObject()->GetPid(); + if (pid > 0) { + pids.push_back(pid); + appRecord->ScheduleProcessSecurityExit(); + if (!WaitForRemoteProcessExit(pids, SystemTimeMillis())) { + int32_t result = KillProcessByPid(pid); + if (result < 0) { + APP_LOGE("KillProcessByAbilityToken kill process is fail"); + return; + } + } + } +} + +void AppMgrServiceInner::StartAbility(const sptr &token, const sptr &preToken, + const std::shared_ptr &abilityInfo, const std::shared_ptr &appRecord) +{ + APP_LOGI("already create appRecord, just start ability"); + if (!appRecord) { + APP_LOGE("appRecord is null"); + return; + } + + if (abilityInfo->launchMode == LaunchMode::SINGLETON) { + auto abilityRecord = appRecord->GetAbilityRunningRecord(abilityInfo->name); + if (abilityRecord) { + APP_LOGW("same ability info in singleton launch mode, will not add ability"); + return; + } + } + + auto abilityRecord = appRecord->GetAbilityRunningRecordByToken(token); + if (abilityRecord && preToken) { + APP_LOGE("Ability is already started"); + abilityRecord->SetPreToken(preToken); + return; + } + + ApplicationState appState = appRecord->GetState(); + if (appState == ApplicationState::APP_STATE_SUSPENDED) { + UnsuspendApplication(appRecord); + OptimizerAppStateChanged(appRecord, ApplicationState::APP_STATE_SUSPENDED); + } + + abilityRecord = appRecord->AddAbility(token, abilityInfo); + if (!abilityRecord) { + APP_LOGE("add ability failed"); + return; + } + + if (preToken != nullptr) { + abilityRecord->SetPreToken(preToken); + } + + if (appState == ApplicationState::APP_STATE_CREATE) { + APP_LOGE("in create state, don't launch ability"); + return; + } + appRecord->LaunchAbility(abilityRecord); +} + +std::shared_ptr AppMgrServiceInner::GetAppRunningRecordByAbilityToken( + const sptr &abilityToken) const +{ + return appRunningManager_->GetAppRunningRecordByAbilityToken(abilityToken); +} + +void AppMgrServiceInner::UnsuspendApplication(const std::shared_ptr &appRecord) +{ + if (!appRecord) { + APP_LOGE("app record is null"); + return; + } + + APP_LOGD("app name is %{public}s", appRecord->GetName().c_str()); + // Resume subscription via UID + appRecord->SetState(ApplicationState::APP_STATE_BACKGROUND); + OptimizerAppStateChanged(appRecord, ApplicationState::APP_STATE_SUSPENDED); +} + +void AppMgrServiceInner::SuspendApplication(const std::shared_ptr &appRecord) +{ + if (!appRecord) { + APP_LOGE("app record is null"); + return; + } + APP_LOGD("app name is %{public}s", appRecord->GetName().c_str()); + // Temporary unsubscribe via UID + appRecord->SetState(ApplicationState::APP_STATE_SUSPENDED); + OptimizerAppStateChanged(appRecord, ApplicationState::APP_STATE_BACKGROUND); +} + +void AppMgrServiceInner::LowMemoryApplicationAlert( + const std::shared_ptr &appRecord, const CgroupManager::LowMemoryLevel level) +{ + if (!appRecord) { + APP_LOGE("app record is null"); + return; + } +} + +std::shared_ptr AppMgrServiceInner::GetAbilityOwnerApp( + const std::shared_ptr &abilityRecord) const +{ + if (!abilityRecord) { + APP_LOGE("ability record is null"); + return nullptr; + } + if (!abilityRecord->GetToken()) { + APP_LOGE("ability token is null"); + return nullptr; + } + auto appRecord = GetAppRunningRecordByAbilityToken(abilityRecord->GetToken()); + if (!appRecord) { + APP_LOGE("The app information corresponding to token does not exist"); + return nullptr; + } + return appRecord; +} + +std::shared_ptr AppMgrServiceInner::GetAbilityRunningRecordByAbilityToken( + const sptr &abilityToken) const +{ + if (!abilityToken) { + APP_LOGE("ability token is null"); + return nullptr; + } + auto appRecord = GetAppRunningRecordByAbilityToken(abilityToken); + if (!appRecord) { + APP_LOGE("The app information corresponding to token does not exist"); + return nullptr; + } + auto abilityRecord = appRecord->GetAbilityRunningRecordByToken(abilityToken); + if (!abilityRecord) { + APP_LOGE("The ability information corresponding to token does not exist"); + return nullptr; + } + return abilityRecord; +} + +void AppMgrServiceInner::AbilityTerminated(const sptr &token) +{ + APP_LOGD("begin"); + if (!token) { + APP_LOGE("token is null!"); + return; + } + auto appRecord = GetAppRunningRecordByAbilityToken(token); + if (!appRecord) { + APP_LOGE("app is not exist!"); + return; + } + appRecord->AbilityTerminated(token); + APP_LOGD("end"); +} + +std::shared_ptr AppMgrServiceInner::GetAppRunningRecordByAppRecordId(const int32_t recordId) const +{ + const auto &iter = appRunningManager_->GetAppRunningRecordMap().find(recordId); + if (iter != appRunningManager_->GetAppRunningRecordMap().end()) { + return iter->second; + } + return nullptr; +} + +void AppMgrServiceInner::OnAppStateChanged( + const std::shared_ptr &appRecord, const ApplicationState state) +{ + APP_LOGD("begin, state:%{public}d", static_cast(state)); + if (!appRecord) { + APP_LOGE("app record is null"); + return; + } + + for (const auto &callback : appStateCallbacks_) { + if (callback != nullptr) { + AppProcessData processData; + processData.appName = appRecord->GetName(); + processData.processName = appRecord->GetProcessName(); + processData.pid = appRecord->GetPriorityObject()->GetPid(); + processData.appState = state; + callback->OnAppStateChanged(processData); + } + } + APP_LOGD("end"); +} + +void AppMgrServiceInner::OnAbilityStateChanged( + const std::shared_ptr &ability, const AbilityState state) +{ + APP_LOGD("begin, state:%{public}d", static_cast(state)); + if (!ability) { + APP_LOGE("ability is null"); + return; + } + for (const auto &callback : appStateCallbacks_) { + if (callback != nullptr) { + callback->OnAbilityRequestDone(ability->GetToken(), state); + } + } + APP_LOGD("end"); +} + +void AppMgrServiceInner::StartProcess( + const std::string &appName, const std::string &processName, const std::shared_ptr &appRecord) +{ + if (!remoteClientManager_->GetSpawnClient() || !appRecord) { + APP_LOGE("appSpawnClient or apprecord is null"); + return; + } + + auto bundleMgr_ = remoteClientManager_->GetBundleManager(); + if (bundleMgr_ == nullptr) { + APP_LOGE("GetBundleManager fail"); + return; + } + + AppSpawnStartMsg startMsg; + BundleInfo bundleInfo; + bool bundleMgrResult = + bundleMgr_->GetBundleInfo(appRecord->GetBundleName(), BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); + if (!bundleMgrResult) { + APP_LOGE("GetBundleInfo is fail"); + return; + } + startMsg.uid = bundleInfo.uid; + startMsg.gid = bundleInfo.gid; + + bundleMgrResult = bundleMgr_->GetBundleGids(appRecord->GetBundleName(), startMsg.gids); + if (!bundleMgrResult) { + APP_LOGE("GetBundleGids is fail"); + return; + } + startMsg.procName = processName; + startMsg.soPath = SO_PATH; + + PerfProfile::GetInstance().SetAppForkStartTime(GetTickCount()); + pid_t pid = 0; + ErrCode errCode = remoteClientManager_->GetSpawnClient()->StartProcess(startMsg, pid); + if (FAILED(errCode)) { + APP_LOGE("failed to spawn new app process, errCode %{public}08x", errCode); + appRunningManager_->RemoveAppRunningRecordById(appRecord->GetRecordId()); + return; + } + APP_LOGI("newPid %{public}d", pid); + appRecord->GetPriorityObject()->SetPid(pid); + APP_LOGI("app uid %{public}d", startMsg.uid); + appRecord->SetUid(startMsg.uid); + OptimizerAppStateChanged(appRecord, ApplicationState::APP_STATE_CREATE); + appRecord->SetAppMgrServiceInner(weak_from_this()); + OnAppStateChanged(appRecord, ApplicationState::APP_STATE_CREATE); + AddAppToRecentList(appName, appRecord->GetProcessName(), pid, appRecord->GetRecordId()); + PerfProfile::GetInstance().SetAppForkEndTime(GetTickCount()); +} + +void AppMgrServiceInner::RemoveAppFromRecentList(const std::string &appName, const std::string &processName) +{ + int64_t startTime = 0; + std::list pids; + auto appTaskInfo = appProcessManager_->GetAppTaskInfoByProcessName(appName, processName); + if (!appTaskInfo) { + return; + } + auto appRecord = GetAppRunningRecordByPid(appTaskInfo->GetPid()); + if (!appRecord) { + appProcessManager_->RemoveAppFromRecentList(appTaskInfo); + return; + } + startTime = SystemTimeMillis(); + pids.push_back(appTaskInfo->GetPid()); + appRecord->ScheduleProcessSecurityExit(); + if (!WaitForRemoteProcessExit(pids, startTime)) { + int32_t result = KillProcessByPid(appTaskInfo->GetPid()); + if (result < 0) { + APP_LOGE("RemoveAppFromRecentList kill process is fail"); + return; + } + } + appProcessManager_->RemoveAppFromRecentList(appTaskInfo); +} + +const std::list> &AppMgrServiceInner::GetRecentAppList() const +{ + return appProcessManager_->GetRecentAppList(); +} + +void AppMgrServiceInner::ClearRecentAppList() +{ + int64_t startTime = 0; + std::list pids; + if (GetAllPids(pids)) { + return; + } + startTime = SystemTimeMillis(); + if (WaitForRemoteProcessExit(pids, startTime)) { + appProcessManager_->ClearRecentAppList(); + return; + } + for (auto iter = pids.begin(); iter != pids.end(); ++iter) { + int32_t result = KillProcessByPid(*iter); + if (result < 0) { + APP_LOGE("ClearRecentAppList kill process is fail"); + return; + } + } + appProcessManager_->ClearRecentAppList(); +} + +void AppMgrServiceInner::OnRemoteDied(const wptr &remote) +{ + auto appRecord = appRunningManager_->OnRemoteDied(remote); + if (appRecord) { + for (const auto &item : appRecord->GetAbilities()) { + const auto &abilityRecord = item.second; + OptimizerAbilityStateChanged(abilityRecord, AbilityState::ABILITY_STATE_TERMINATED); + } + OptimizerAppStateChanged(appRecord, ApplicationState::APP_STATE_TERMINATED); + RemoveAppFromRecentListById(appRecord->GetRecordId()); + } +} + +void AppMgrServiceInner::PushAppFront(const int32_t recordId) +{ + appProcessManager_->PushAppFront(recordId); +} + +void AppMgrServiceInner::RemoveAppFromRecentListById(const int32_t recordId) +{ + appProcessManager_->RemoveAppFromRecentListById(recordId); +} + +void AppMgrServiceInner::AddAppToRecentList( + const std::string &appName, const std::string &processName, const pid_t pid, const int32_t recordId) +{ + appProcessManager_->AddAppToRecentList(appName, processName, pid, recordId); +} + +const std::shared_ptr AppMgrServiceInner::GetAppTaskInfoById(const int32_t recordId) const +{ + return appProcessManager_->GetAppTaskInfoById(recordId); +} + +void AppMgrServiceInner::AddAppDeathRecipient(const pid_t pid, const sptr &appDeathRecipient) const +{ + std::shared_ptr appRecord = GetAppRunningRecordByPid(pid); + if (appRecord) { + appRecord->SetAppDeathRecipient(appDeathRecipient); + } +} + +int32_t AppMgrServiceInner::ProcessOptimizerInit() +{ + processOptimizerUBA_ = std::make_shared(nullptr); + bool isSuccess = processOptimizerUBA_->Init(); + if (!isSuccess) { + processOptimizerUBA_.reset(); + processOptimizerUBA_ = nullptr; + APP_LOGE("optimizer init is fail"); + return ERR_NO_INIT; + } + processOptimizerUBA_->AppSuspended = + std::bind(&AppMgrServiceInner::SuspendApplication, this, std::placeholders::_1); + // Register freeze callback function + processOptimizerUBA_->AppResumed = + std::bind(&AppMgrServiceInner::UnsuspendApplication, this, std::placeholders::_1); + // Register freeze recovery callback function + processOptimizerUBA_->AppLowMemoryAlert = + std::bind(&AppMgrServiceInner::LowMemoryApplicationAlert, this, std::placeholders::_1, std::placeholders::_2); + // Register low memory warning callback function + processOptimizerUBA_->GetAbilityOwnerApp = + std::bind(&AppMgrServiceInner::GetAbilityOwnerApp, this, std::placeholders::_1); + // Register to get the application record callback of ability + processOptimizerUBA_->GetAbilityByToken = + std::bind(&AppMgrServiceInner::GetAbilityRunningRecordByAbilityToken, this, std::placeholders::_1); + // Register to get the ability record through the token callback + APP_LOGI("optimizer init is success"); + return ERR_OK; +} + +void AppMgrServiceInner::OptimizerAbilityStateChanged( + const std::shared_ptr &ability, const AbilityState state) +{ + if (!processOptimizerUBA_) { + APP_LOGE("process optimizer is not init"); + return; + } + + if ((ability->GetAbilityInfo()->type == AbilityType::PAGE) || + (ability->GetAbilityInfo()->type == AbilityType::DATA)) { + if (ability->GetState() == AbilityState::ABILITY_STATE_CREATE) { + processOptimizerUBA_->OnAbilityStarted(ability); + APP_LOGI("optimizer OnAbilityStarted is called"); + } else if (ability->GetState() == AbilityState::ABILITY_STATE_TERMINATED) { + processOptimizerUBA_->OnAbilityRemoved(ability); + APP_LOGI("optimizer OnAbilityRemoved is called"); + } else { + processOptimizerUBA_->OnAbilityStateChanged(ability, state); + APP_LOGI("optimizer OnAbilityStateChanged is called"); + } + } else if (ability->GetAbilityInfo()->type == AbilityType::SERVICE) { + auto appRecord = GetAppRunningRecordByAbilityToken(ability->GetPreToken()); + if (!appRecord) { + APP_LOGE("app record is not exist for ability token"); + return; + } + auto targetAbility = appRecord->GetAbilityRunningRecordByToken(ability->GetPreToken()); + if (!targetAbility) { + APP_LOGE("ability record is not exist for ability previous token"); + return; + } + if (ability->GetConnectionState()) { + // connect + processOptimizerUBA_->OnAbilityConnected(ability, targetAbility); + APP_LOGI("optimizer OnAbilityConnected is called"); + } else { + // disconnect + processOptimizerUBA_->OnAbilityDisconnected(ability, targetAbility); + APP_LOGI("optimizer OnAbilityDisconnected is called"); + } + } else { + APP_LOGI("OptimizerAbilityStateChanged ability type is unknown"); + } + + if (ability->GetState() != state) { + processOptimizerUBA_->OnAbilityStateChanged(ability, state); + APP_LOGI("optimizer OnAbilityStateChanged is called"); + } +} + +void AppMgrServiceInner::OptimizerAppStateChanged( + const std::shared_ptr &appRecord, const ApplicationState state) +{ + if (!processOptimizerUBA_) { + APP_LOGE("process optimizer is not init"); + return; + } + if (appRecord->GetState() == ApplicationState::APP_STATE_CREATE) { + processOptimizerUBA_->OnAppAdded(appRecord); + APP_LOGI("optimizer OnAppAdded is called"); + } else if (appRecord->GetState() == ApplicationState::APP_STATE_TERMINATED) { + processOptimizerUBA_->OnAppRemoved(appRecord); + APP_LOGI("optimizer OnAppRemoved is called"); + } else { + processOptimizerUBA_->OnAppStateChanged(appRecord, state); + APP_LOGI("optimizer OnAppStateChanged is called"); + } +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/appmgr/src/app_process_manager.cpp b/services/appmgr/src/app_process_manager.cpp new file mode 100644 index 000000000..ad38b19e5 --- /dev/null +++ b/services/appmgr/src/app_process_manager.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 "app_process_manager.h" + +#include + +#include "app_log_wrapper.h" + +namespace OHOS { + +namespace AppExecFwk { + +AppProcessManager::AppProcessManager() +{} + +AppProcessManager::~AppProcessManager() +{} + +void AppProcessManager::RemoveAppFromRecentList(const std::shared_ptr &appTaskInfo) +{ + if (appTaskInfo) { + recentAppList_.remove(appTaskInfo); + } +} + +void AppProcessManager::ClearRecentAppList() +{ + recentAppList_.clear(); +} + +void AppProcessManager::AddAppToRecentList( + const std::string &appName, const std::string &processName, const pid_t pid, const int32_t recordId) +{ + auto appTaskInfo = std::make_shared(); + appTaskInfo->SetName(appName); + appTaskInfo->SetProcessName(processName); + appTaskInfo->SetPid(pid); + appTaskInfo->SetRecordId(recordId); + recentAppList_.push_front(appTaskInfo); +} + +const std::list> &AppProcessManager::GetRecentAppList() const +{ + return recentAppList_; +} + +void AppProcessManager::PushAppFront(const int32_t recordId) +{ + auto appTaskInfo = GetAppTaskInfoById(recordId); + if (appTaskInfo) { + recentAppList_.remove(appTaskInfo); + recentAppList_.push_front(appTaskInfo); + } +} + +void AppProcessManager::RemoveAppFromRecentListById(const int32_t recordId) +{ + auto appTaskInfo = GetAppTaskInfoById(recordId); + if (appTaskInfo) { + recentAppList_.remove(appTaskInfo); + } +} + +const std::shared_ptr AppProcessManager::GetAppTaskInfoById(const int32_t recordId) const +{ + const auto &iter = std::find_if(recentAppList_.begin(), recentAppList_.end(), [&recordId](const auto &appTaskInfo) { + return appTaskInfo ? (appTaskInfo->GetRecordId() == recordId) : false; + }); + return (iter == recentAppList_.end()) ? nullptr : (*iter); +} + +std::shared_ptr AppProcessManager::GetAppTaskInfoByProcessName( + const std::string &appName, const std::string &processName) const +{ + const auto &iter = + std::find_if(recentAppList_.begin(), recentAppList_.end(), [&appName, &processName](const auto &appTaskInfo) { + return ((appTaskInfo->GetName() == appName) && (appTaskInfo->GetProcessName() == processName)); + }); + return ((iter == recentAppList_.end()) ? nullptr : *iter); +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/appmgr/src/app_running_manager.cpp b/services/appmgr/src/app_running_manager.cpp new file mode 100644 index 000000000..0863043f2 --- /dev/null +++ b/services/appmgr/src/app_running_manager.cpp @@ -0,0 +1,167 @@ +/* + * 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_running_manager.h" + +#include "iremote_object.h" +#include "datetime_ex.h" + +#include "app_log_wrapper.h" +#include "perf_profile.h" +#include "appexecfwk_errors.h" + +namespace OHOS { + +namespace AppExecFwk { + +namespace { + +bool CheckUid(const int32_t uid) +{ + return uid >= 0 && uid < std::numeric_limits::max(); +} + +} // namespace + +AppRunningManager::AppRunningManager() +{} +AppRunningManager::~AppRunningManager() +{} + +std::shared_ptr AppRunningManager::GetOrCreateAppRunningRecord(const sptr &token, + const std::shared_ptr &appInfo, const std::shared_ptr &abilityInfo, + const std::string &processName, const int32_t uid, RecordQueryResult &result) +{ + result.Reset(); + if (!token || !appInfo || !abilityInfo) { + APP_LOGE("param error"); + result.error = ERR_INVALID_VALUE; + return nullptr; + } + if (!CheckUid(uid)) { + APP_LOGE("uid invalid"); + result.error = ERR_APPEXECFWK_INVALID_UID; + return nullptr; + } + if (processName.empty()) { + APP_LOGE("processName error"); + result.error = ERR_INVALID_VALUE; + return nullptr; + } + + auto record = GetAppRunningRecordByProcessName(appInfo->name, processName); + if (!record) { + APP_LOGI("no app record, create"); + auto recordId = AppRecordId::Create(); + record = std::make_shared(appInfo, recordId, processName); + appRunningRecordMap_.emplace(recordId, record); + } else { + result.appExists = true; + } + + result.appRecordId = record->GetRecordId(); + auto abilityRecord = record->GetAbilityRunningRecordByToken(token); + result.abilityExists = !!abilityRecord; + if (!abilityRecord) { + APP_LOGI("no ability record, create"); + abilityRecord = record->AddAbility(token, abilityInfo); + } + return record; +} + +std::shared_ptr AppRunningManager::GetAppRunningRecordByAppName(const std::string &appName) const +{ + auto iter = std::find_if(appRunningRecordMap_.begin(), appRunningRecordMap_.end(), [&appName](const auto &pair) { + return pair.second->GetName() == appName; + }); + return ((iter == appRunningRecordMap_.end()) ? nullptr : iter->second); +} + +std::shared_ptr AppRunningManager::GetAppRunningRecordByProcessName( + const std::string &appName, const std::string &processName) const +{ + auto iter = std::find_if( + appRunningRecordMap_.begin(), appRunningRecordMap_.end(), [&appName, &processName](const auto &pair) { + return ((pair.second->GetName() == appName) && (pair.second->GetProcessName() == processName)); + }); + return ((iter == appRunningRecordMap_.end()) ? nullptr : iter->second); +} + +std::shared_ptr AppRunningManager::GetAppRunningRecordByPid(const pid_t pid) const +{ + auto iter = std::find_if(appRunningRecordMap_.begin(), appRunningRecordMap_.end(), [&pid](const auto &pair) { + return pair.second->GetPriorityObject()->GetPid() == pid; + }); + return ((iter == appRunningRecordMap_.end()) ? nullptr : iter->second); +} + +std::shared_ptr AppRunningManager::GetAppRunningRecordByAbilityToken( + const sptr &abilityToken) const +{ + for (const auto &item : appRunningRecordMap_) { + const auto &appRecord = item.second; + if (appRecord && appRecord->GetAbilityRunningRecordByToken(abilityToken)) { + return appRecord; + } + } + return nullptr; +} + +std::shared_ptr AppRunningManager::OnRemoteDied(const wptr &remote) +{ + if (remote == nullptr) { + APP_LOGE("remote is null"); + return nullptr; + } + sptr object = remote.promote(); + if (!object) { + APP_LOGE("object is null"); + return nullptr; + } + const auto &iter = + std::find_if(appRunningRecordMap_.begin(), appRunningRecordMap_.end(), [&object](const auto &pair) { + if (pair.second && pair.second->GetApplicationClient() != nullptr) { + return pair.second->GetApplicationClient()->AsObject() == object; + } + return false; + }); + if (iter != appRunningRecordMap_.end()) { + auto appRecord = iter->second; + appRunningRecordMap_.erase(iter); + if (appRecord) { + return appRecord; + } + } + return nullptr; +} + +const std::map> &AppRunningManager::GetAppRunningRecordMap() + const +{ + return appRunningRecordMap_; +} + +void AppRunningManager::RemoveAppRunningRecordById(const int32_t recordId) +{ + appRunningRecordMap_.erase(recordId); +} + +void AppRunningManager::ClearAppRunningRecordMap() +{ + appRunningRecordMap_.clear(); +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/appmgr/src/app_running_record.cpp b/services/appmgr/src/app_running_record.cpp new file mode 100644 index 000000000..f6f32880b --- /dev/null +++ b/services/appmgr/src/app_running_record.cpp @@ -0,0 +1,415 @@ +/* + * 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_running_record.h" + +#include "ability_running_record.h" +#include "app_log_wrapper.h" +#include "app_mgr_service_inner.h" + +namespace OHOS { +namespace AppExecFwk { + +AppRunningRecord::AppRunningRecord( + const std::shared_ptr &info, const int32_t recordId, const std::string &processName) + : appInfo_(info), appRecordId_(recordId), processName_(processName) +{} + +void AppRunningRecord::SetApplicationClient(const sptr &thread) +{ + if (!appLifeCycleDeal_) { + appLifeCycleDeal_ = std::make_shared(); + } + appLifeCycleDeal_->SetApplicationClient(thread); +} + +std::string AppRunningRecord::GetBundleName() const +{ + return appInfo_->bundleName; +} + +int32_t AppRunningRecord::GetRecordId() const +{ + return appRecordId_; +} + +const std::string &AppRunningRecord::GetName() const +{ + return appInfo_->name; +} + +const std::string &AppRunningRecord::GetProcessName() const +{ + return processName_; +} + +int32_t AppRunningRecord::GetUid() const +{ + return uid_; +} + +void AppRunningRecord::SetUid(const int32_t uid) +{ + uid_ = uid; +} + +ApplicationState AppRunningRecord::GetState() const +{ + return curState_; +} + +void AppRunningRecord::SetState(const ApplicationState state) +{ + if (state >= ApplicationState::APP_STATE_END) { + APP_LOGE("Invalid application state"); + return; + } + curState_ = state; +} + +const std::map, std::shared_ptr> &AppRunningRecord::GetAbilities() const +{ + return abilities_; +} + +sptr AppRunningRecord::GetApplicationClient() const +{ + return (appLifeCycleDeal_ ? appLifeCycleDeal_->GetApplicationClient() : nullptr); +} + +std::shared_ptr AppRunningRecord::AddAbility( + const sptr &token, const std::shared_ptr &abilityInfo) +{ + if (!token || !abilityInfo) { + APP_LOGE("Param abilityInfo or token is null"); + return nullptr; + } + if (GetAbilityRunningRecordByToken(token)) { + APP_LOGE("AbilityRecord already exists and no need to add"); + return nullptr; + } + auto abilityRecord = std::make_shared(abilityInfo, token); + abilities_.emplace(token, abilityRecord); + return abilityRecord; +} + +std::shared_ptr AppRunningRecord::GetAbilityRunningRecord(const std::string &abilityName) const +{ + const auto &iter = std::find_if(abilities_.begin(), abilities_.end(), [&abilityName](const auto &pair) { + return pair.second->GetName() == abilityName; + }); + return ((iter == abilities_.end()) ? nullptr : iter->second); +} + +void AppRunningRecord::ClearAbility(const std::shared_ptr &record) +{ + if (!record) { + APP_LOGE("Param record is null"); + return; + } + if (!GetAbilityRunningRecordByToken(record->GetToken())) { + APP_LOGE("Param record is not exist"); + return; + } + abilities_.erase(record->GetToken()); +} + +void AppRunningRecord::ForceKillApp([[maybe_unused]] const std::string &reason) const +{} + +void AppRunningRecord::ScheduleAppCrash([[maybe_unused]] const std::string &description) const +{} + +void AppRunningRecord::LaunchApplication() +{ + if (!appInfo_ || !appLifeCycleDeal_->GetApplicationClient()) { + APP_LOGE("appInfo or appThread is null"); + return; + } + AppLaunchData launchData; + launchData.SetApplicationInfo(*appInfo_); + ProcessInfo processInfo(processName_, GetPriorityObject()->GetPid()); + launchData.SetProcessInfo(processInfo); + launchData.SetRecordId(appRecordId_); + launchData.SetUId(uid_); + APP_LOGI("ScheduleLaunchApplication app:%{public}s", GetName().c_str()); + appLifeCycleDeal_->LaunchApplication(launchData); +} + +void AppRunningRecord::LaunchAbility(const std::shared_ptr &ability) +{ + if (!ability || !ability->GetToken()) { + APP_LOGE("null abilityRecord or abilityToken"); + return; + } + const auto &iter = abilities_.find(ability->GetToken()); + if (iter != abilities_.end() && appLifeCycleDeal_->GetApplicationClient()) { + APP_LOGI("ScheduleLaunchAbility ability:%{public}s", ability->GetName().c_str()); + appLifeCycleDeal_->LaunchAbility(ability); + ability->SetState(AbilityState::ABILITY_STATE_READY); + OptimizerAbilityStateChanged(ability, AbilityState::ABILITY_STATE_CREATE); + } +} + +void AppRunningRecord::LaunchPendingAbilities() +{ + for (auto item : abilities_) { + if (item.second->GetState() == AbilityState::ABILITY_STATE_CREATE) { + LaunchAbility(item.second); + } + } +} + +void AppRunningRecord::ScheduleTerminate() +{ + appLifeCycleDeal_->ScheduleTerminate(); +} + +void AppRunningRecord::ScheduleForegroundRunning() +{ + appLifeCycleDeal_->ScheduleForegroundRunning(); +} + +void AppRunningRecord::ScheduleBackgroundRunning() +{ + appLifeCycleDeal_->ScheduleBackgroundRunning(); +} + +void AppRunningRecord::ScheduleProcessSecurityExit() +{ + appLifeCycleDeal_->ScheduleProcessSecurityExit(); +} + +void AppRunningRecord::ScheduleTrimMemory() +{ + appLifeCycleDeal_->ScheduleTrimMemory(priorityObject_->GetTimeLevel()); +} + +void AppRunningRecord::LowMemoryWarning() +{ + appLifeCycleDeal_->LowMemoryWarning(); +} + +void AppRunningRecord::OnAbilityStateChanged( + const std::shared_ptr &ability, const AbilityState state) +{ + if (!ability) { + APP_LOGE("ability is null"); + return; + } + AbilityState oldState = ability->GetState(); + ability->SetState(state); + OptimizerAbilityStateChanged(ability, oldState); + auto serviceInner = appMgrServiceInner_.lock(); + if (serviceInner) { + serviceInner->OnAbilityStateChanged(ability, state); + } +} + +std::shared_ptr AppRunningRecord::GetAbilityRunningRecordByToken( + const sptr &token) const +{ + if (!token) { + APP_LOGE("token is null"); + return nullptr; + } + const auto &iter = abilities_.find(token); + if (iter != abilities_.end()) { + return iter->second; + } + return nullptr; +} + +void AppRunningRecord::UpdateAbilityState(const sptr &token, const AbilityState state) +{ + APP_LOGD("state is :%{public}d", static_cast(state)); + auto abilityRecord = GetAbilityRunningRecordByToken(token); + if (!abilityRecord) { + APP_LOGE("can not find ability record"); + return; + } + if (state == abilityRecord->GetState()) { + APP_LOGE("current state is already, no need update"); + return; + } + + if (state == AbilityState::ABILITY_STATE_FOREGROUND) { + AbilityForeground(abilityRecord); + } else if (state == AbilityState::ABILITY_STATE_BACKGROUND) { + AbilityBackground(abilityRecord); + } else { + APP_LOGW("wrong state"); + } +} + +void AppRunningRecord::AbilityForeground(const std::shared_ptr &ability) +{ + if (!ability) { + APP_LOGE("ability is null"); + return; + } + AbilityState curAbilityState = ability->GetState(); + if (curAbilityState != AbilityState::ABILITY_STATE_READY && + curAbilityState != AbilityState::ABILITY_STATE_BACKGROUND) { + APP_LOGE("ability state(%{public}d) error", static_cast(curAbilityState)); + return; + } + + // We need schedule application to foregrounded when current application state is ready or background running. + if (curState_ == ApplicationState::APP_STATE_READY || curState_ == ApplicationState::APP_STATE_BACKGROUND) { + if (foregroundingAbilityTokens_.empty()) { + ScheduleForegroundRunning(); + } + foregroundingAbilityTokens_.push_back(ability->GetToken()); + return; + } else if (curState_ == ApplicationState::APP_STATE_FOREGROUND) { + // Just change ability to foreground if current application state is foreground. + OnAbilityStateChanged(ability, AbilityState::ABILITY_STATE_FOREGROUND); + } else { + APP_LOGW("wrong application state"); + } +} + +void AppRunningRecord::AbilityBackground(const std::shared_ptr &ability) +{ + if (!ability) { + APP_LOGE("ability is null"); + return; + } + if (ability->GetState() != AbilityState::ABILITY_STATE_FOREGROUND) { + APP_LOGE("ability state is not foreground"); + return; + } + + // First change ability to backgrounded. + OnAbilityStateChanged(ability, AbilityState::ABILITY_STATE_BACKGROUND); + + if (curState_ == ApplicationState::APP_STATE_FOREGROUND) { + int32_t foregroundSize = 0; + for (const auto &item : abilities_) { + const auto &abilityRecord = item.second; + if (abilityRecord && abilityRecord->GetState() == AbilityState::ABILITY_STATE_FOREGROUND) { + foregroundSize++; + break; + } + } + + // Then schedule application background when all ability is not foreground. + if (foregroundSize == 0) { + ScheduleBackgroundRunning(); + } + } else { + APP_LOGW("wrong application state"); + } +} + +void AppRunningRecord::OptimizerAbilityStateChanged( + const std::shared_ptr &ability, const AbilityState state) +{ + auto serviceInner = appMgrServiceInner_.lock(); + if (serviceInner) { + serviceInner->OptimizerAbilityStateChanged(ability, state); + } +} + +void AppRunningRecord::PopForegroundingAbilityTokens() +{ + APP_LOGD("size:%{public}d", static_cast(foregroundingAbilityTokens_.size())); + while (!foregroundingAbilityTokens_.empty()) { + const auto &token = foregroundingAbilityTokens_.front(); + auto ability = GetAbilityRunningRecordByToken(token); + OnAbilityStateChanged(ability, AbilityState::ABILITY_STATE_FOREGROUND); + foregroundingAbilityTokens_.pop_front(); + } +} + +void AppRunningRecord::TerminateAbility(const sptr &token) +{ + APP_LOGD("AppRunningRecord::TerminateAbility begin"); + auto abilityRecord = GetAbilityRunningRecordByToken(token); + if (!abilityRecord) { + APP_LOGE("AppRunningRecord::TerminateAbility can not find ability record"); + return; + } + auto curAbilityState = abilityRecord->GetState(); + if (curAbilityState != AbilityState::ABILITY_STATE_BACKGROUND) { + APP_LOGE("AppRunningRecord::TerminateAbility current state(%{public}d) error", + static_cast(curAbilityState)); + return; + } + + OptimizerAbilityStateChanged(abilityRecord, AbilityState::ABILITY_STATE_TERMINATED); + appLifeCycleDeal_->ScheduleCleanAbility(token); + + APP_LOGD("AppRunningRecord::TerminateAbility end"); +} + +void AppRunningRecord::AbilityTerminated(const sptr &token) +{ + if (!token) { + APP_LOGE("token is null"); + return; + } + abilities_.erase(token); + if (abilities_.empty()) { + ScheduleTerminate(); + } +} + +void AppRunningRecord::RegisterAppDeathRecipient() const +{ + if (!appLifeCycleDeal_->GetApplicationClient()) { + APP_LOGE("appThread is null"); + return; + } + auto object = appLifeCycleDeal_->GetApplicationClient()->AsObject(); + if (object) { + object->AddDeathRecipient(appDeathRecipient_); + } +} + +void AppRunningRecord::RemoveAppDeathRecipient() const +{ + if (!appLifeCycleDeal_->GetApplicationClient()) { + APP_LOGE("appThread is null"); + return; + } + auto object = appLifeCycleDeal_->GetApplicationClient()->AsObject(); + if (object) { + object->RemoveDeathRecipient(appDeathRecipient_); + } +} + +void AppRunningRecord::SetAppMgrServiceInner(const std::weak_ptr &inner) +{ + appMgrServiceInner_ = inner; +} + +void AppRunningRecord::SetAppDeathRecipient(const sptr &appDeathRecipient) +{ + appDeathRecipient_ = appDeathRecipient; +} + +std::shared_ptr AppRunningRecord::GetPriorityObject() +{ + if (!priorityObject_) { + priorityObject_ = std::make_shared(); + } + + return priorityObject_; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/appmgr/src/app_spawn_client.cpp b/services/appmgr/src/app_spawn_client.cpp new file mode 100644 index 000000000..889642cb7 --- /dev/null +++ b/services/appmgr/src/app_spawn_client.cpp @@ -0,0 +1,137 @@ +/* + * 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_spawn_client.h" + +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { +namespace { + +const int32_t CONNECT_RETRY_DELAY = 200 * 1000; // 200ms +const int32_t CONNECT_RETRY_MAX_TIMES = 15; + +} // namespace + +AppSpawnClient::AppSpawnClient() +{ + socket_ = std::make_shared(); + state_ = SpawnConnectionState::STATE_NOT_CONNECT; +} + +ErrCode AppSpawnClient::OpenConnection() +{ + if (!socket_) { + APP_LOGE("failed to open connection without socket!"); + return ERR_APPEXECFWK_BAD_APPSPAWN_SOCKET; + } + + int32_t retryCount = 1; + ErrCode errCode = socket_->OpenAppSpawnConnection(); + while (FAILED(errCode) && retryCount <= CONNECT_RETRY_MAX_TIMES) { + APP_LOGW("failed to OpenConnection, retry times %{public}d ...", retryCount); + usleep(CONNECT_RETRY_DELAY); + errCode = socket_->OpenAppSpawnConnection(); + retryCount++; + } + if (SUCCEEDED(errCode)) { + state_ = SpawnConnectionState::STATE_CONNECTED; + } else { + APP_LOGE("failed to openConnection, errorCode is %{public}08x", errCode); + state_ = SpawnConnectionState::STATE_CONNECT_FAILED; + } + return errCode; +} + +ErrCode AppSpawnClient::StartProcess(const AppSpawnStartMsg &startMsg, pid_t &pid) +{ + int32_t retryCount = 1; + ErrCode errCode = StartProcessImpl(startMsg, pid); + while (FAILED(errCode) && retryCount <= CONNECT_RETRY_MAX_TIMES) { + APP_LOGW("failed to StartProcess, retry times %{public}d ...", retryCount); + usleep(CONNECT_RETRY_DELAY); + errCode = StartProcessImpl(startMsg, pid); + retryCount++; + } + return errCode; +} + +ErrCode AppSpawnClient::StartProcessImpl(const AppSpawnStartMsg &startMsg, pid_t &pid) +{ + if (!socket_) { + APP_LOGE("failed to startProcess without socket!"); + return ERR_APPEXECFWK_BAD_APPSPAWN_SOCKET; + } + + ErrCode result = ERR_OK; + // openconnection failed, return fail + if (state_ != SpawnConnectionState::STATE_CONNECTED) { + result = OpenConnection(); + if (FAILED(result)) { + APP_LOGE("connect to appspawn failed!"); + return result; + } + } + std::unique_ptr autoCloseConnection( + this, [](AppSpawnClient *client) { client->CloseConnection(); }); + + AppSpawnMsgWrapper msgWrapper; + if (!msgWrapper.AssembleMsg(startMsg)) { + APP_LOGE("AssembleMsg failed!"); + return ERR_APPEXECFWK_ASSEMBLE_START_MSG_FAILED; + } + AppSpawnPidMsg pidMsg; + if (msgWrapper.IsValid()) { + result = socket_->WriteMessage(msgWrapper.GetMsgBuf(), msgWrapper.GetMsgLength()); + if (FAILED(result)) { + APP_LOGE("WriteMessage failed!"); + return result; + } + result = socket_->ReadMessage(reinterpret_cast(pidMsg.pidBuf), LEN_PID); + if (FAILED(result)) { + APP_LOGE("ReadMessage failed!"); + return result; + } + } + if (pidMsg.pid <= 0) { + APP_LOGE("invalid pid!"); + result = ERR_APPEXECFWK_INVALID_PID; + } else { + pid = pidMsg.pid; + } + return result; +} + +SpawnConnectionState AppSpawnClient::QueryConnectionState() const +{ + return state_; +} + +void AppSpawnClient::CloseConnection() +{ + if (socket_ && state_ == SpawnConnectionState::STATE_CONNECTED) { + socket_->CloseAppSpawnConnection(); + } + state_ = SpawnConnectionState::STATE_NOT_CONNECT; +} + +void AppSpawnClient::SetSocket(const std::shared_ptr socket) +{ + socket_ = socket; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/appmgr/src/app_spawn_msg_wrapper.cpp b/services/appmgr/src/app_spawn_msg_wrapper.cpp new file mode 100644 index 000000000..bd85457b4 --- /dev/null +++ b/services/appmgr/src/app_spawn_msg_wrapper.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 "app_spawn_msg_wrapper.h" + +#include "securec.h" + +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { + +AppSpawnMsgWrapper::~AppSpawnMsgWrapper() +{ + FreeMsg(); +} + +bool AppSpawnMsgWrapper::AssembleMsg(const AppSpawnStartMsg &startMsg) +{ + if (!VerifyMsg(startMsg)) { + return false; + } + FreeMsg(); + int32_t msgSize = sizeof(AppSpawnMsg) + 1; + msg_ = static_cast(malloc(msgSize)); + if (msg_ == nullptr) { + APP_LOGE("failed to malloc!"); + return false; + } + if (memset_s(msg_, msgSize, 0, msgSize) != EOK) { + APP_LOGE("failed to memset!"); + return false; + } + msg_->uid = startMsg.uid; + msg_->gid = startMsg.gid; + msg_->gidCount = startMsg.gids.size(); + for (uint32_t i = 0; i < msg_->gidCount; ++i) { + msg_->gidTable[i] = startMsg.gids[i]; + } + if (strcpy_s(msg_->processName, sizeof(msg_->processName), startMsg.procName.c_str()) != EOK) { + APP_LOGE("failed to transform procName!"); + return false; + } + if (strcpy_s(msg_->soPath, sizeof(msg_->soPath), startMsg.soPath.c_str()) != EOK) { + APP_LOGE("failed to transform soPath!"); + return false; + } + + isValid_ = true; + DumpMsg(); + return isValid_; +} + +bool AppSpawnMsgWrapper::VerifyMsg(const AppSpawnStartMsg &startMsg) const +{ + if (startMsg.uid < 0) { + APP_LOGE("invalid uid! [%{public}d]", startMsg.uid); + return false; + } + + if (startMsg.gid < 0) { + APP_LOGE("invalid gid! [%{public}d]", startMsg.gid); + return false; + } + + if (startMsg.gids.size() > AppSpawn::ClientSocket::MAX_GIDS) { + APP_LOGE("too many app gids!"); + return false; + } + + for (uint32_t i = 0; i < startMsg.gids.size(); ++i) { + if (startMsg.gids[i] < 0) { + APP_LOGE("invalid gids array! [%{public}d]", startMsg.gids[i]); + return false; + } + } + + if (startMsg.procName.empty() || startMsg.procName.size() >= AppSpawn::ClientSocket::LEN_PROC_NAME) { + APP_LOGE("invalid procName!"); + return false; + } + + return true; +} + +void AppSpawnMsgWrapper::DumpMsg() const +{ + if (!isValid_) { + return; + } + APP_LOGI("************AppSpawnMsg*************"); + APP_LOGI("uid: %{public}d", msg_->uid); + APP_LOGI("gid: %{public}d", msg_->gid); + for (uint32_t i = 0; i < msg_->gidCount; ++i) { + APP_LOGI("gidTable[%{public}d]: %{public}d", i, msg_->gidTable[i]); + } + APP_LOGI("procName: %{public}s", msg_->processName); + APP_LOGI("soPath: %{private}s", msg_->soPath); + APP_LOGI("************************************"); +} + +void AppSpawnMsgWrapper::FreeMsg() +{ + if (msg_ != nullptr) { + free(msg_); + msg_ = nullptr; + isValid_ = false; + } +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/appmgr/src/app_spawn_socket.cpp b/services/appmgr/src/app_spawn_socket.cpp new file mode 100644 index 000000000..546b114c0 --- /dev/null +++ b/services/appmgr/src/app_spawn_socket.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 "app_spawn_socket.h" + +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { + +// arg "AppSpawn" cannot be defined as string object since REGISTER_SYSTEM_ABILITY will +// firstly start without init this string object, which leads to error. + +AppSpawnSocket::AppSpawnSocket() : clientSocket_(std::make_unique("AppSpawn")) +{} + +AppSpawnSocket::~AppSpawnSocket() +{} + +ErrCode AppSpawnSocket::OpenAppSpawnConnection() +{ + APP_LOGD("ready to open connection"); + if (clientSocket_) { + if (clientSocket_->CreateClient() != ERR_OK) { + APP_LOGE("failed to create socketClient"); + return ERR_APPEXECFWK_BAD_APPSPAWN_CLIENT; + } + if (clientSocket_->ConnectSocket() != ERR_OK) { + APP_LOGE("failed to connect socket"); + return ERR_APPEXECFWK_CONNECT_APPSPAWN_FAILED; + } + APP_LOGD("connection has been opened"); + return ERR_OK; + } + APP_LOGE("failed to open connection without socket"); + return ERR_APPEXECFWK_BAD_APPSPAWN_SOCKET; +} + +void AppSpawnSocket::CloseAppSpawnConnection() +{ + if (clientSocket_) { + clientSocket_->CloseClient(); + } +} + +ErrCode AppSpawnSocket::WriteMessage(const void *buf, const int32_t len) +{ + APP_LOGD("ready to write message"); + if (len <= 0) { + APP_LOGE("failed to write message due to invalid length of message"); + return ERR_INVALID_VALUE; + } + if (buf == nullptr) { + APP_LOGE("failed to write message due to null buf"); + return ERR_INVALID_VALUE; + } + if (clientSocket_) { + if (clientSocket_->WriteSocketMessage(buf, len) != len) { + APP_LOGE("failed to write message due to invalid write length"); + return ERR_APPEXECFWK_SOCKET_WRITE_FAILED; + } + APP_LOGD("write message success"); + return ERR_OK; + } + + APP_LOGE("failed to write message without socket"); + return ERR_APPEXECFWK_BAD_APPSPAWN_SOCKET; +} + +ErrCode AppSpawnSocket::ReadMessage(void *buf, const int32_t len) +{ + APP_LOGD("ready to read message"); + if (len <= 0) { + APP_LOGE("failed to read message due to invalid length of cache"); + return ERR_INVALID_VALUE; + } + if (buf == nullptr) { + APP_LOGE("failed to read message due to null buf"); + return ERR_INVALID_VALUE; + } + if (clientSocket_) { + if (clientSocket_->ReadSocketMessage(buf, len) != len) { + APP_LOGE("failed to read message due to invalid read length"); + return ERR_APPEXECFWK_SOCKET_READ_FAILED; + } + APP_LOGD("read message success"); + return ERR_OK; + } + APP_LOGE("failed to read message without socket"); + return ERR_APPEXECFWK_BAD_APPSPAWN_CLIENT; +} + +void AppSpawnSocket::SetClientSocket(const std::shared_ptr clientSocket) +{ + clientSocket_ = clientSocket; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/appmgr/src/cgroup_manager.cpp b/services/appmgr/src/cgroup_manager.cpp new file mode 100644 index 000000000..fa7dd5d7f --- /dev/null +++ b/services/appmgr/src/cgroup_manager.cpp @@ -0,0 +1,438 @@ +/* + * 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 "cgroup_manager.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "app_log_wrapper.h" +#include "event_handler.h" +#include "securec.h" + +#define CG_DIR "/dev/cg" + +#define CG_CPU_DIR CG_DIR "/cpu" + +#define CG_CPU_DEFAULT_DIR CG_CPU_DIR +#define CG_CPU_DEFAULT_TASKS_PATH CG_CPU_DEFAULT_DIR "/tasks" + +#define CG_CPU_BACKGROUND_DIR CG_CPU_DIR "/background" +#define CG_CPU_BACKGROUND_TASKS_PATH CG_CPU_BACKGROUND_DIR "/tasks" + +#define CG_CPU_FREEZED_DIR CG_CPU_DIR "/freezer" +#define CG_CPU_FREEZED_TASKS_PATH CG_CPU_FREEZED_DIR "/tasks" + +#define CG_MEM_DIR CG_DIR "/mem" + +#define CG_MEM_OOMCTL_PATH CG_MEM_DIR "/memory.oom_control" +#define CG_MEM_EVTCTL_PATH CG_MEM_DIR "/cgroup.event_control" +#define CG_MEM_PRESSURE_LEVEL_PATH CG_MEM_DIR "/memory.pressure_level" + +namespace OHOS { +namespace AppExecFwk { + +namespace { + +class ScopeGuard final { +public: + using Function = std::function; + +public: + explicit ScopeGuard(Function fn) : fn_(fn), dismissed_(false) + {} + + ~ScopeGuard() + { + if (!dismissed_) { + fn_(); + } + } + +public: + void Dismiss() + { + dismissed_ = true; + } + +private: + Function fn_; + bool dismissed_ = false; +}; + +int WriteValue(int fd, std::string_view v) +{ + if (fd < 0) { + errno = EINVAL; + return -1; + } + + int ret = TEMP_FAILURE_RETRY(write(fd, v.data(), v.size())); + fsync(fd); + + return ret; +} + +int WriteValue(int fd, int v, bool newLine = true) +{ + if (fd < 0) { + errno = EINVAL; + return -1; + } + + char str[32] = {0}; + + int len = snprintf_s(str, sizeof(str), sizeof(str) - 1, newLine ? "%d\n" : "%d", v); + if (len < 1) { + return -1; + } + + return WriteValue(fd, str); +} + +} // namespace + +CgroupManager::CgroupManager() : memoryEventControlFd_(-1) +{ + for (int i = 0; i < SCHED_POLICY_MAX; ++i) { + cpuTasksFds_[i] = -1; + } + + for (int i = 0; i < LOW_MEMORY_LEVEL_MAX; ++i) { + memoryEventFds_[i] = -1; + memoryPressureFds_[i] = -1; + } +} + +CgroupManager::~CgroupManager() +{ + for (int i = 0; i < LOW_MEMORY_LEVEL_MAX; ++i) { + if (memoryEventFds_[i] >= 0) { + if (eventHandler_) { + eventHandler_->RemoveFileDescriptorListener(memoryEventFds_[i]); + } + close(memoryEventFds_[i]); + } + if (memoryPressureFds_[i] >= 0) { + close(memoryPressureFds_[i]); + } + } + + if (memoryEventControlFd_ >= 0) { + close(memoryEventControlFd_); + } + + for (int i = 0; i < SCHED_POLICY_MAX; ++i) { + if (cpuTasksFds_[i] >= 0) { + close(cpuTasksFds_[i]); + } + } +} + +bool CgroupManager::Init() +{ + if (IsInited()) { + APP_LOGE("%{public}s(%{public}d) already inited.", __func__, __LINE__); + return false; + } + + auto eventHandler = EventHandler::Current(); + if (!eventHandler) { + APP_LOGE("%{public}s(%{public}d) failed to get event handler.", __func__, __LINE__); + return false; + } + + UniqueFd cpuTasksFds[SCHED_POLICY_MAX]; + if (InitCpuTasksFds(cpuTasksFds, SCHED_POLICY_MAX)) { + return false; + } + + UniqueFd memoryEventControlFd; + if (InitMemoryEventControlFd(memoryEventControlFd)) { + return false; + } + + UniqueFd memoryEventFds[LOW_MEMORY_LEVEL_MAX]; + if (InitMemoryEventFds(memoryEventFds, LOW_MEMORY_LEVEL_MAX)) { + return false; + } + + UniqueFd memoryPressureFds[LOW_MEMORY_LEVEL_MAX]; + if (InitMemoryPressureFds(memoryPressureFds, LOW_MEMORY_LEVEL_MAX)) { + return false; + } + + if (!RegisterLowMemoryMonitor( + memoryEventFds_, memoryPressureFds_, memoryEventControlFd_, LOW_MEMORY_LEVEL_LOW, eventHandler)) { + return false; + } + + ScopeGuard lowLevelListenerGuard( + [&]() { eventHandler->RemoveFileDescriptorListener(memoryEventFds_[LOW_MEMORY_LEVEL_LOW]); }); + + if (!RegisterLowMemoryMonitor( + memoryEventFds_, memoryPressureFds_, memoryEventControlFd_, LOW_MEMORY_LEVEL_MEDIUM, eventHandler)) { + return false; + } + + ScopeGuard mediumLevelListenerGuard( + [&]() { eventHandler->RemoveFileDescriptorListener(memoryEventFds_[LOW_MEMORY_LEVEL_MEDIUM]); }); + + if (!RegisterLowMemoryMonitor( + memoryEventFds_, memoryPressureFds_, memoryEventControlFd_, LOW_MEMORY_LEVEL_CRITICAL, eventHandler)) { + return false; + } + + ScopeGuard criticalLevelListenerGuard( + [&]() { eventHandler->RemoveFileDescriptorListener(memoryEventFds_[LOW_MEMORY_LEVEL_CRITICAL]); }); + + eventHandler_ = eventHandler; + + lowLevelListenerGuard.Dismiss(); + mediumLevelListenerGuard.Dismiss(); + criticalLevelListenerGuard.Dismiss(); + + return true; +} + +bool CgroupManager::IsInited() const +{ + return bool(eventHandler_); +} + +bool CgroupManager::SetThreadSchedPolicy(int tid, SchedPolicy schedPolicy) +{ + if (!IsInited()) { + APP_LOGE("%{public}s(%{public}d) not inited.", __func__, __LINE__); + return false; + } + + if (tid < 1) { + APP_LOGE("%{public}s(%{public}d) invalid tid %{public}d.", __func__, __LINE__, tid); + return false; + } + + if (schedPolicy < 0 || schedPolicy >= SCHED_POLICY_MAX) { + APP_LOGE("%{public}s(%{public}d) invalid sched policy %{public}d.", __func__, __LINE__, schedPolicy); + return false; + } + + int fd = cpuTasksFds_[schedPolicy]; + if (fd < 0) { + APP_LOGE("%{public}s(%{public}d) invalid cgroup fd for policy %{public}d.", __func__, __LINE__, schedPolicy); + return false; + } + + int ret = WriteValue(fd, tid); + if (ret < 0) { + APP_LOGE("%{public}s(%{public}d) write cgroup tid failed %{public}d.", __func__, __LINE__, errno); + return false; + } + + return true; +} + +bool CgroupManager::SetProcessSchedPolicy(int pid, SchedPolicy schedPolicy) +{ + if (!IsInited()) { + APP_LOGE("%{public}s(%{public}d) not inited.", __func__, __LINE__); + return false; + } + + if (pid < 1) { + APP_LOGE("%{public}s(%{public}d) invalid pid %{public}d", __func__, __LINE__, pid); + return false; + } + + if (schedPolicy < 0 && schedPolicy >= SCHED_POLICY_MAX) { + APP_LOGE("%{public}s(%{public}d) invalid sched policy %{public}d", __func__, __LINE__, schedPolicy); + return false; + } + + // Set all threads's sched policy inside this process. + char taskDir[64]; + if (snprintf_s(taskDir, sizeof(taskDir), sizeof(taskDir) - 1, "/proc/%d/task", pid) < 0) { + return false; + } + + DIR *dir = opendir(taskDir); + if (dir == nullptr) { + APP_LOGE("%{public}s(%{public}d) invalid pid %{public}d", __func__, __LINE__, pid); + return false; + } + + struct dirent *dent; + + while ((dent = readdir(dir))) { + // Filter out '.' & '..' + if (dent->d_name[0] != '.') { + SetThreadSchedPolicy(atoi(dent->d_name), schedPolicy); + } + } + + closedir(dir); + + return true; +} + +void CgroupManager::OnReadable(int32_t fd) +{ + APP_LOGW("%{public}s(%{public}d) system low memory alert.", __func__, __LINE__); + + if (!LowMemoryAlert) { + APP_LOGE("%{public}s(%{public}d) 'LowMemoryAlert' not available.", __func__, __LINE__); + return; + } + + auto TryToRaiseLowMemoryAlert = [=](LowMemoryLevel level) { + if (fd == memoryEventFds_[level]) { + APP_LOGW("%{public}s(%{public}d) checking level %{public}d", __func__, __LINE__, level); + uint64_t count = 0; + int ret = TEMP_FAILURE_RETRY(read(fd, &count, sizeof(uint64_t))); + if (ret <= 0) { + APP_LOGW("%{public}s(%{public}d) failed to read eventfd %{public}d.", __func__, __LINE__, errno); + return false; + } + if (count < 1) { + #if __WORDSIZE == 64 + APP_LOGW("%{public}s(%{public}d) invalid eventfd count %{public}lu.", __func__, __LINE__, count); + #else + APP_LOGW("%{public}s(%{public}d) invalid eventfd count %{public}llu.", __func__, __LINE__, count); + #endif + + return false; + } + APP_LOGW( + "%{public}s(%{public}d) raising low memory alert for level %{public}d...", __func__, __LINE__, level); + LowMemoryAlert(level); + return true; + } + return false; + }; + + if (TryToRaiseLowMemoryAlert(LOW_MEMORY_LEVEL_LOW)) { + return; + } + + if (TryToRaiseLowMemoryAlert(LOW_MEMORY_LEVEL_MEDIUM)) { + return; + } + + if (TryToRaiseLowMemoryAlert(LOW_MEMORY_LEVEL_CRITICAL)) { + return; + } + + // Should not reach here! + APP_LOGE("%{public}s(%{public}d) Unknown fd %{public}d.", __func__, __LINE__, fd); +} + +bool CgroupManager::RegisterLowMemoryMonitor(const int memoryEventFds[LOW_MEMORY_LEVEL_MAX], + const int memoryPressureFds[LOW_MEMORY_LEVEL_MAX], const int memoryEventControlFd, const LowMemoryLevel level, + const std::shared_ptr &eventHandler) +{ + APP_LOGI("RegisterLowMemoryMonitor(%{public}d) registering low memory monitor %{public}d...", __LINE__, level); + + char buf[64] = {0}; + static const char *levelName[] = {"low", "medium", "critical"}; + + if (snprintf_s(buf, + sizeof(buf), + sizeof(buf) - 1, + "%d %d %s", + memoryEventFds[level], + memoryPressureFds[level], + levelName[level]) < 0) { + return false; + } + + int ret = TEMP_FAILURE_RETRY(write(memoryEventControlFd, buf, strlen(buf) + 1)); + if (ret < 0) { + APP_LOGI("RegisterLowMemoryMonitor(%{public}d) failed to write memory control %{public}d...", __LINE__, errno); + return false; + } + + eventHandler->AddFileDescriptorListener(memoryEventFds[level], FILE_DESCRIPTOR_INPUT_EVENT, shared_from_this()); + + return true; +} + +bool CgroupManager::InitCpuTasksFds(UniqueFd cpuTasksFds[SCHED_POLICY_MAX], size_t len) +{ + cpuTasksFds[SCHED_POLICY_DEFAULT] = UniqueFd(open(CG_CPU_DEFAULT_TASKS_PATH, O_RDWR)); + cpuTasksFds[SCHED_POLICY_BACKGROUND] = UniqueFd(open(CG_CPU_BACKGROUND_TASKS_PATH, O_RDWR)); + cpuTasksFds[SCHED_POLICY_FREEZED] = UniqueFd(open(CG_CPU_FREEZED_TASKS_PATH, O_RDWR)); + if (cpuTasksFds[SCHED_POLICY_DEFAULT].Get() < 0 || cpuTasksFds[SCHED_POLICY_BACKGROUND].Get() < 0 || + cpuTasksFds[SCHED_POLICY_FREEZED].Get() < 0) { + APP_LOGE("%{public}s(%{public}d) cannot open cpu cgroups %{public}d.", __func__, __LINE__, errno); + return false; + } + + cpuTasksFds_[SCHED_POLICY_DEFAULT] = cpuTasksFds[SCHED_POLICY_DEFAULT].Release(); + cpuTasksFds_[SCHED_POLICY_BACKGROUND] = cpuTasksFds[SCHED_POLICY_BACKGROUND].Release(); + cpuTasksFds_[SCHED_POLICY_FREEZED] = cpuTasksFds[SCHED_POLICY_FREEZED].Release(); + return true; +} + +bool CgroupManager::InitMemoryEventControlFd(UniqueFd &memoryEventControlFd) +{ + memoryEventControlFd = UniqueFd(open(CG_MEM_EVTCTL_PATH, O_WRONLY)); + if (memoryEventControlFd.Get() < 0) { + APP_LOGE( + "%{pubid}s(%{publid}d) failed to open memory event control node %{public}d.", __func__, __LINE__, errno); + return false; + } + + memoryEventControlFd_ = memoryEventControlFd.Release(); + return true; +} + +bool CgroupManager::InitMemoryEventFds(UniqueFd memoryEventFds[LOW_MEMORY_LEVEL_MAX], size_t len) +{ + memoryEventFds[LOW_MEMORY_LEVEL_LOW] = UniqueFd(eventfd(0, EFD_NONBLOCK)); + memoryEventFds[LOW_MEMORY_LEVEL_MEDIUM] = UniqueFd(eventfd(0, EFD_NONBLOCK)); + memoryEventFds[LOW_MEMORY_LEVEL_CRITICAL] = UniqueFd(eventfd(0, EFD_NONBLOCK)); + if (memoryEventFds[LOW_MEMORY_LEVEL_LOW].Get() < 0 || memoryEventFds[LOW_MEMORY_LEVEL_MEDIUM].Get() < 0 || + memoryEventFds[LOW_MEMORY_LEVEL_CRITICAL].Get() < 0) { + APP_LOGE("%{public}s(${public}d) failed to create memory eventfd %{public}d.", __func__, __LINE__, errno); + return false; + } + + memoryEventFds_[LOW_MEMORY_LEVEL_LOW] = memoryEventFds[LOW_MEMORY_LEVEL_LOW].Release(); + memoryEventFds_[LOW_MEMORY_LEVEL_MEDIUM] = memoryEventFds[LOW_MEMORY_LEVEL_MEDIUM].Release(); + memoryEventFds_[LOW_MEMORY_LEVEL_CRITICAL] = memoryEventFds[LOW_MEMORY_LEVEL_CRITICAL].Release(); + return true; +} + +bool CgroupManager::InitMemoryPressureFds(UniqueFd memoryPressureFds[LOW_MEMORY_LEVEL_MAX], size_t len) +{ + memoryPressureFds[LOW_MEMORY_LEVEL_LOW] = UniqueFd(open(CG_MEM_PRESSURE_LEVEL_PATH, O_RDONLY)); + memoryPressureFds[LOW_MEMORY_LEVEL_MEDIUM] = UniqueFd(open(CG_MEM_PRESSURE_LEVEL_PATH, O_RDONLY)); + memoryPressureFds[LOW_MEMORY_LEVEL_CRITICAL] = UniqueFd(open(CG_MEM_PRESSURE_LEVEL_PATH, O_RDONLY)); + if (memoryPressureFds[LOW_MEMORY_LEVEL_LOW].Get() < 0 || memoryPressureFds[LOW_MEMORY_LEVEL_MEDIUM].Get() < 0 || + memoryPressureFds[LOW_MEMORY_LEVEL_CRITICAL].Get() < 0) { + APP_LOGE("%{public}s(${public}d) failed to open memory pressure fd %{public}d.", __func__, __LINE__, errno); + return false; + } + + memoryPressureFds_[LOW_MEMORY_LEVEL_LOW] = memoryPressureFds[LOW_MEMORY_LEVEL_LOW].Release(); + memoryPressureFds_[LOW_MEMORY_LEVEL_MEDIUM] = memoryPressureFds[LOW_MEMORY_LEVEL_MEDIUM].Release(); + memoryPressureFds_[LOW_MEMORY_LEVEL_CRITICAL] = memoryPressureFds[LOW_MEMORY_LEVEL_CRITICAL].Release(); + return true; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/appmgr/src/lmk_util.cpp b/services/appmgr/src/lmk_util.cpp new file mode 100644 index 000000000..208a5b25e --- /dev/null +++ b/services/appmgr/src/lmk_util.cpp @@ -0,0 +1,231 @@ +/* + * 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 "lmk_util.h" + +#include +#include +#include + +#include "securec.h" + +#include "cgroup_manager.h" +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { + +namespace { +// pressure level low +constexpr int LMK_OOM_ADJ_LOW = 800; +// pressure level medium +constexpr int LMK_OOM_ADJ_MEDIUM = 600; +// pressure level critical +constexpr int LMK_OOM_ADJ_CRITICAL = 0; +constexpr int MemoryLevel[] = {LMK_OOM_ADJ_LOW, LMK_OOM_ADJ_MEDIUM, LMK_OOM_ADJ_CRITICAL}; + +constexpr int PROC_PATH_MAX = 256; +constexpr int PROC_LINE_MAX = 128; +} // namespace + +LmkUtil::LmkUtil() +{} + +LmkUtil::~LmkUtil() +{} + +std::string LmkUtil::GetProcName(pid_t pid) +{ + std::string name; + + if (pid < 1) { + APP_LOGW("%{public}s(%{public}d) invalid pid %{public}d.", __func__, __LINE__, pid); + return name; + } + + char path[PROC_PATH_MAX]; + char line[PROC_LINE_MAX]; + int fd = -1; + ssize_t ret = -1; + + if (memset_s(path, sizeof(path), 0x00, sizeof(path)) != EOK) { + APP_LOGE("%{public}s(%{public}d) failed to memset path", __func__, __LINE__); + return name; + } + + if (memset_s(line, sizeof(line), 0x00, sizeof(line)) != EOK) { + APP_LOGE("%{public}s(%{public}d) failed to memset line", __func__, __LINE__); + return name; + } + + if (snprintf_s(path, PROC_PATH_MAX, PROC_PATH_MAX - 1, "/proc/%d/cmdline", pid) < 0) { + return name; + } + + fd = open(path, O_RDONLY | O_CLOEXEC); + if (fd == -1) { + return name; + } + + ret = ReadAll(fd, line, sizeof(line) - 1); + close(fd); + if (ret < 0) { + return name; + } + + if (ret < PROC_LINE_MAX) { + line[ret] = '\0'; + } else { + line[PROC_LINE_MAX - 1] = '\0'; + } + // assign name + name = strchr(line, ' '); + + return name; +} + +int32_t LmkUtil::GetProcSize(pid_t pid) +{ + int rss = 0; + + if (pid <= 0) { + APP_LOGW("%{public}s(%{public}d) invalid pid %{public}d.", __func__, __LINE__, pid); + return rss; + } + + char path[PROC_PATH_MAX]; + char line[PROC_LINE_MAX]; + int fd = -1; + int total = -1; + ssize_t ret = -1; + + if (memset_s(path, sizeof(path), 0x00, sizeof(path)) != EOK) { + APP_LOGE("%{public}s(%{public}d) failed to memset path", __func__, __LINE__); + return -1; + } + + if (memset_s(line, sizeof(line), 0x00, sizeof(line)) != EOK) { + APP_LOGE("%{public}s(%{public}d) failed to memset line", __func__, __LINE__); + return -1; + } + + if (snprintf_s(path, PROC_PATH_MAX, PROC_PATH_MAX - 1, "/proc/%d/statm", pid) < 0) { + return rss; + } + + fd = open(path, O_RDONLY | O_CLOEXEC); + if (fd == -1) + return -1; + + ret = ReadAll(fd, line, sizeof(line) - 1); + if (ret < 0) { + close(fd); + return -1; + } + + if (ret < PROC_LINE_MAX) { + line[ret] = '\0'; + } else { + line[PROC_LINE_MAX - 1] = '\0'; + } + + if (sscanf_s(line, "%d %d ", &total, &rss) <= 0) { + close(fd); + return 0; + } + + close(fd); + return rss; +} + +int32_t LmkUtil::KillProcess(std::list &listApp, const CgroupManager::LowMemoryLevel level, int64_t &rss) +{ + int32_t killCnt = 0; + int64_t taskSize = 0; + std::list::iterator iter = listApp.begin(); + int killThreshold = LMK_OOM_ADJ_LOW; + + if (level < CgroupManager::LOW_MEMORY_LEVEL_MAX) { + killThreshold = MemoryLevel[level]; + } + + while (iter != listApp.end()) { + auto priorityObject = (*iter)->GetPriorityObject(); + if (priorityObject != nullptr && priorityObject->GetCurAdj() >= killThreshold) { + auto pid = priorityObject->GetPid(); + if (pid <= 0) { + APP_LOGE("%{public}s(%{public}d) pid %{public}d invalid", __func__, __LINE__, pid); + iter = listApp.erase(iter); + continue; + } + + auto procName = GetProcName(pid); + if (procName.empty()) { + APP_LOGW("%{public}s(%{public}d) pid %{public}d process name emptry", __func__, __LINE__, pid); + } + + auto procSize = GetProcSize(pid); + if (procSize <= 0) { + APP_LOGW("%{public}s(%{public}d) pid %{public}d process size error", __func__, __LINE__, pid); + } + + // kill process + int ret = kill(pid, SIGKILL); + if (ret) { + APP_LOGW("%{public}s(%{public}d) kill pid %{public}d error", __func__, __LINE__, pid); + } else { + APP_LOGI("%{public}s(%{public}d) pid %{public}d", __func__, __LINE__, pid); + + // inc count and rss + taskSize += procSize; + killCnt++; + + // remove app which pid been killed + iter = listApp.erase(iter); + continue; + } + } + iter++; + } + + // out rss size + rss = taskSize; + + return killCnt; +} + +ssize_t LmkUtil::ReadAll(int fd, char *buf, size_t maxLen) +{ + ssize_t ret = 0; + off_t offSet = 0; + + while (maxLen > 0) { + ssize_t rc = TEMP_FAILURE_RETRY(pread(fd, buf, maxLen, offSet)); + if (rc == 0) { + break; + } + if (rc == -1) { + return -1; + } + ret += rc; + buf += rc; + offSet += rc; + maxLen -= rc; + } + + return ret; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/appmgr/src/lmkd_client.cpp b/services/appmgr/src/lmkd_client.cpp new file mode 100644 index 000000000..d5a5645b4 --- /dev/null +++ b/services/appmgr/src/lmkd_client.cpp @@ -0,0 +1,231 @@ +/* + * 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 "lmkd_client.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "app_log_wrapper.h" +#include "event_handler.h" +#include "securec.h" +#include "unique_fd.h" + +namespace OHOS { +namespace AppExecFwk { + +namespace { +constexpr std::string_view LMKD_SOCKET_PATH("/dev/socket/lmkd"); +static_assert(LMKD_SOCKET_PATH.size() < UNIX_PATH_MAX); + +constexpr int LMKD_SOCKET_TIMEOUT = 3; + +constexpr size_t LMKD_MAX_TARGETS = 6; + +constexpr int LMKD_CMD_TARGET = 0; +constexpr int LMKD_CMD_PROCPRIO = 1; +constexpr int LMKD_CMD_PROCREMOVE = 2; +constexpr int LMKD_CMD_PROCPURGE = 3; + +constexpr int OOM_SCORE_ADJ_MIN = -1000; +constexpr int OOM_SCORE_ADJ_MAX = 1000; +} // namespace + +LmkdClient::LmkdClient() : socket_(-1) +{} + +LmkdClient::~LmkdClient() +{ + if (IsOpen()) { + Close(); + } +} + +int32_t LmkdClient::Open() +{ + APP_LOGI("%{public}s(%{public}d) connecting lmkd.", __func__, __LINE__); + + if (socket_ >= 0) { + APP_LOGE("%{public}s(%{public}d) already connected.", __func__, __LINE__); + return -1; + } + + UniqueFd sk(socket(PF_LOCAL, SOCK_SEQPACKET, 0)); + if (!sk) { + APP_LOGE("%{public}s(%{public}d) failed to create local socket %{public}d.", __func__, __LINE__, errno); + return (-errno); + } + + struct timeval timeOut = {.tv_sec = LMKD_SOCKET_TIMEOUT, .tv_usec = 0}; + int fd = sk.Get(); + if (fd < 0) { + APP_LOGE("%{public}s(%{public}d) fd is negative.", __func__, __LINE__); + return -1; + } + if ((setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeOut, sizeof(timeOut)) != 0) || + (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeOut, sizeof(timeOut)) != 0)) { + APP_LOGE("%{public}s(%{public}d) failed to set local socket timeout %{public}s.", + __func__, + __LINE__, + strerror(errno)); + return (-errno); + } + + struct sockaddr_un addr; + int32_t ret; + ret = memset_s(&addr, sizeof(addr), 0, sizeof(addr)); + if (ret != EOK) { + APP_LOGE("%{public}s(%{public}d) failed to clear local socket addr.", __func__, __LINE__); + return ret; + } + + ret = memcpy_s(addr.sun_path, UNIX_PATH_MAX, LMKD_SOCKET_PATH.data(), LMKD_SOCKET_PATH.size()); + if (ret != EOK) { + APP_LOGE("%{public}s(%{public}d) failed to make local socket path.", __func__, __LINE__); + return ret; + } + + addr.sun_family = AF_LOCAL; + socklen_t addrLen = offsetof(struct sockaddr_un, sun_path) + LMKD_SOCKET_PATH.size() + 1; + if (connect(sk, reinterpret_cast(&addr), addrLen) < 0) { + APP_LOGE("%{public}s(%{public}d) failed to connect to lmkd %{public}s.", __func__, __LINE__, strerror(errno)); + return (-errno); + } + + socket_ = sk.Release(); + + return ERR_OK; +} + +void LmkdClient::Close() +{ + APP_LOGI("%{public}s(%{public}d) closing lmkd.", __func__, __LINE__); + + if (socket_ < 0) { + APP_LOGE("%{public}s(%{public}d) not connected.", __func__, __LINE__); + return; + } + + close(socket_); + socket_ = -1; +} + +bool LmkdClient::IsOpen() const +{ + return socket_ >= 0; +} + +int32_t LmkdClient::Target(const Targets &targets) +{ + if (targets.empty() || targets.size() > LMKD_MAX_TARGETS) { + APP_LOGE( + "%{public}s(%{public}d) empty target or too many targets. %{public}zu", __func__, __LINE__, targets.size()); + return (-EINVAL); + } + + int i = 0; + int32_t buf[1 + 2 * LMKD_MAX_TARGETS]; + buf[i++] = LMKD_CMD_TARGET; + + for (auto target : targets) { + if (target.first < 0 || !CheckOomAdj(target.second)) { + APP_LOGE("%{public}s(%{public}d) invalid target: %{public}d %{public}d", + __func__, + __LINE__, + target.first, + target.second); + return (-EINVAL); + } + buf[i++] = target.first; + buf[i++] = target.second; + } + + return Write(buf, i * sizeof(int32_t)) ? ERR_OK : -1; +} + +int32_t LmkdClient::ProcPrio(pid_t pid, uid_t uid, int oomAdj) +{ + if (pid < 0 || uid < 0 || !CheckOomAdj(oomAdj)) { + APP_LOGE("%{public}s(%{public}d) invalid parameter: %{public}d %{public}d %{public}d.", + __func__, + __LINE__, + pid, + uid, + oomAdj); + return (-EINVAL); + } + + int32_t buf[4] = {LMKD_CMD_PROCPRIO, pid, uid, oomAdj}; + + return Write(buf, sizeof(buf)) ? ERR_OK : -1; +} + +int32_t LmkdClient::ProcRemove(pid_t pid) +{ + if (pid < 1) { + APP_LOGE("%{public}s(%{public}d) invalid pid %{public}d.", __func__, __LINE__, pid); + return (-EINVAL); + } + + int32_t buf[2] = {LMKD_CMD_PROCREMOVE, pid}; + + return Write(buf, sizeof(buf)) ? ERR_OK : -1; +} + +bool LmkdClient::ProcPurge() +{ + int32_t cmd = LMKD_CMD_PROCPURGE; + + return Write(reinterpret_cast(&cmd), sizeof(cmd)); +} + +bool LmkdClient::CheckOomAdj(int v) +{ + return (OOM_SCORE_ADJ_MIN <= v && v <= OOM_SCORE_ADJ_MAX); +} + +bool LmkdClient::Write(const void *buf, size_t len) +{ + if (buf == nullptr || len < 1) { + APP_LOGE("%{public}s(%{public}d) invalid parameter.", __func__, __LINE__); + return false; + } + + constexpr int retryTimes = 5; + for (int i = 0; i < retryTimes; ++i) { + if (socket_ < 0 && !Open()) { + std::this_thread::yield(); + continue; + } + int ret = TEMP_FAILURE_RETRY(send(socket_, buf, len, 0)); + if (ret <= 0) { + APP_LOGE("%{public}s(%{public}d) failed to send data to lmkd %{public}d.", __func__, __LINE__, errno); + Close(); + std::this_thread::yield(); + } else { + return true; + } + } + + return false; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/appmgr/src/process_optimizer.cpp b/services/appmgr/src/process_optimizer.cpp new file mode 100644 index 000000000..2abffbd83 --- /dev/null +++ b/services/appmgr/src/process_optimizer.cpp @@ -0,0 +1,680 @@ +/* + * 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 "process_optimizer.h" + +#include +#include +#include + +#include "app_log_wrapper.h" + +#define LMK_UTIL +#define APP_SUSPEND_TIMER_NAME_PREFIX "AppSuspendTimer" + +namespace OHOS { +namespace AppExecFwk { + +using namespace std::placeholders; + +namespace { +// constexpr int APP_OOM_ADJ_SYSTEM = -1; +// foreground process oom_adj +constexpr int APP_OOM_ADJ_FOREGROUND = 0; + +// visible process oom_adj +constexpr int APP_OOM_ADJ_VISIBLE_MIN = 1; +constexpr int APP_OOM_ADJ_VISIBLE_MAX = 199; +constexpr int APP_OOM_ADJ_VISIBLE_MAX_VALUE = 1 * 1024; + +// preceptible process oom_adj +constexpr int APP_OOM_ADJ_PERCEPTIBLE_MIN = 200; +constexpr int APP_OOM_ADJ_PERCEPTIBLE_MAX = 399; +constexpr int APP_OOM_ADJ_PERCEPTIBLE_MAX_VALUE = 4 * 1024; + +// background process oom_adj +constexpr int APP_OOM_ADJ_BACKGROUND_MIN = 400; +constexpr int APP_OOM_ADJ_BACKGROUND_MAX = 599; +constexpr int APP_OOM_ADJ_BACKGROUND_MAX_VALUE = 16 * 1024; + +// suspend process oom_adj +constexpr int APP_OOM_ADJ_SUSPEND_MIN = 600; +constexpr int APP_OOM_ADJ_SUSPEND_MAX = 799; +constexpr int APP_OOM_ADJ_SUSPEND_MAX_VALUE = 24 * 1024; + +// empty process oom_adj +// constexpr int APP_OOM_ADJ_EMPTY_MIN = 800; +constexpr int APP_OOM_ADJ_EMPTY_MAX = 999; +constexpr int APP_OOM_ADJ_EMPTY_MAX_VALUE = 32 * 1024; + +constexpr int APP_OOM_ADJ_UNKNOWN = 1000; +constexpr int APP_OOM_ADJ_UNKNOWN_VALUE = 64 * 1024; +} // namespace + +ProcessOptimizer::ProcessOptimizer(const LmkdClientPtr &lmkdClient, int suspendTimeout) + : lmkdClient_(lmkdClient), suspendTimeout_(suspendTimeout) +{ + APP_LOGI("%{public}s(%{public}d) constructed.", __func__, __LINE__); +} + +ProcessOptimizer::~ProcessOptimizer() +{ + if (lmkdClient_) { + lmkdClient_->ProcPurge(); + } + + APP_LOGI("%{public}s(%{public}d) destructed.", __func__, __LINE__); +} + +bool ProcessOptimizer::Init() +{ + APP_LOGI("%{public}s(%{public}d) initializing...", __func__, __LINE__); + + if (suspendTimeout_ < 0) { + APP_LOGE("%{public}s(%{public}d) invalid suspend timeout.", __func__, __LINE__); + return false; + } + + if (eventHandler_) { + APP_LOGE("%{public}s(%{public}d) already inited.", __func__, __LINE__); + return false; + } + +#ifdef LMK_UTIL + // create lmkManager + if (!lmkUtil_) { + lmkUtil_ = std::make_unique(); + } +#endif + + // Initializing cgroup manager. + if (!DelayedSingleton::GetInstance()->IsInited()) { + APP_LOGW("%{public}s(%{public}d) cgroup manager not inited.", __func__, __LINE__); + if (DelayedSingleton::GetInstance()->Init()) { + APP_LOGE("%{public}s(%{public}d) cannot init cgroup manager.", __func__, __LINE__); + return false; + } + } + + if (DelayedSingleton::GetInstance()->LowMemoryAlert) { + APP_LOGW("%{public}s(%{public}d) cgroup manager 'LowMemoryWarning' already registered.", __func__, __LINE__); + } + + DelayedSingleton::GetInstance()->LowMemoryAlert = + std::bind(&ProcessOptimizer::OnLowMemoryAlert, this, _1); + + // Initializing lmkd. + LmkdClientPtr lmkdClientLocal; + lmkdClientLocal.swap(lmkdClient_); + if (!lmkdClientLocal) { + lmkdClientLocal = std::make_shared(); + if (!lmkdClientLocal) { + APP_LOGE("%{public}s(%{public}d) failed to create lmkd client.", __func__, __LINE__); + return false; + } + } + + if (!lmkdClientLocal->IsOpen()) { + if (!lmkdClientLocal->Open()) { + APP_LOGE("%{public}s(%{public}d) cannot open lmkd connection.", __func__, __LINE__); + return false; + } + } + + LmkdClient::Targets targets = { + {APP_OOM_ADJ_VISIBLE_MAX_VALUE, APP_OOM_ADJ_VISIBLE_MAX}, + {APP_OOM_ADJ_PERCEPTIBLE_MAX_VALUE, APP_OOM_ADJ_PERCEPTIBLE_MAX}, + {APP_OOM_ADJ_BACKGROUND_MAX_VALUE, APP_OOM_ADJ_BACKGROUND_MAX}, + {APP_OOM_ADJ_SUSPEND_MAX_VALUE, APP_OOM_ADJ_SUSPEND_MAX}, + {APP_OOM_ADJ_EMPTY_MAX_VALUE, APP_OOM_ADJ_EMPTY_MAX}, + {APP_OOM_ADJ_UNKNOWN_VALUE, APP_OOM_ADJ_UNKNOWN}, + }; + + if (!lmkdClientLocal->Target(targets)) { + APP_LOGE("%{public}s(%{public}d) cannot init lmkd.", __func__, __LINE__); + return false; + } + + // Save initialized states. + auto eventHandler = EventHandler::Current(); + if (!eventHandler) { + APP_LOGE("%{public}s(%{public}d) no available event handler for current thread.", __func__, __LINE__); + return false; + } + + eventHandler_ = eventHandler; + lmkdClient_ = lmkdClientLocal; + + return true; +} + +void ProcessOptimizer::OnAppAdded(const AppPtr &app) +{ + if (!app) { + APP_LOGE("%{public}s(%{public}d) invalid app.", __func__, __LINE__); + return; + } + + if (app != appLru_.front()) { + auto it = std::find(appLru_.begin(), appLru_.end(), app); + if (it != appLru_.end()) { + APP_LOGE( + "%{public}s(%{public}d) app '%{public}s' already existed.", __func__, __LINE__, app->GetName().c_str()); + appLru_.erase(it); + } + if (app->GetState() == ApplicationState::APP_STATE_FOREGROUND) { + appLru_.push_front(app); + } else { + appLru_.push_back(app); + } + } + // Initial sched policy has been already set by appspawn. + UpdateAppOomAdj(app); +} + +void ProcessOptimizer::OnAppRemoved(const AppPtr &app) +{ + if (!app) { + APP_LOGE("%{public}s(%{public}d) invalid app.", __func__, __LINE__); + return; + } + + if (!lmkdClient_) { + APP_LOGE("%{public}s(%{public}d) invalid lmkd client.", __func__, __LINE__); + return; + } + + // remove timer + StopAppSuspendTimer(app); + + auto it = std::find(appLru_.begin(), appLru_.end(), app); + if (it != appLru_.end()) { + appLru_.erase(it); + } else { + APP_LOGE("%{pulbid}s(%{publid}d) app '%{public}s' is not existed.", __func__, __LINE__, app->GetName().c_str()); + } + + auto priorityObject = app->GetPriorityObject(); + if (!priorityObject) { + APP_LOGE("%{public}s(%{public}d) invalid priority object.", __func__, __LINE__); + return; + } + + if (lmkdClient_->ProcRemove(priorityObject->GetPid()) != ERR_OK) { + APP_LOGE("%{public}s(%{public}d) failed to remove app '%{public}s'(%{publid}d) from lmkd.", + __func__, + __LINE__, + app->GetName().c_str(), + priorityObject->GetPid()); + } +} + +void ProcessOptimizer::OnAppStateChanged(const AppPtr &app, const ApplicationState oldState) +{ + if (!app) { + APP_LOGE("%{public}s(%{public}d) invalid app.", __func__, __LINE__); + return; + } + + auto priorityObject = app->GetPriorityObject(); + if (!priorityObject) { + APP_LOGE("%{public}s(%{public}d) invalid priority object.", __func__, __LINE__); + return; + } + + auto curState = app->GetState(); + APP_LOGD("%{public}s(%{pubic}d) ability state changed to %{public}d.", __func__, __LINE__, curState); + if (curState == oldState) { + APP_LOGW("%{public}s(%{public}d) no change.", __func__, __LINE__); + return; + } + + if (curState == ApplicationState::APP_STATE_FOREGROUND) { + if (app != appLru_.front()) { + auto it = std::find(appLru_.begin(), appLru_.end(), app); + if (it != appLru_.end()) { + appLru_.erase(it); + } else { + APP_LOGE("%{pulbid}s(%{publid}d) app '%{public}s' is not existed.", + __func__, + __LINE__, + app->GetName().c_str()); + } + appLru_.push_front(app); + } + } + + UpdateAppSchedPolicy(app); + UpdateAppOomAdj(app); + + // only background also no visible and no preceptible can freezer + if (curState == ApplicationState::APP_STATE_BACKGROUND && + (!priorityObject->GetVisibleStatus() && !priorityObject->GetPerceptibleStatus())) { + StartAppSuspendTimer(app); + } + + if (oldState == ApplicationState::APP_STATE_BACKGROUND && curState != ApplicationState::APP_STATE_SUSPENDED) { + StopAppSuspendTimer(app); + } +} + +void ProcessOptimizer::OnAbilityStarted(const AbilityPtr &ability) +{ + if (!ability) { + APP_LOGE("%{public}s(%{public}d) invalid ability.", __func__, __LINE__); + return; + } + + APP_LOGI("%{public}s(%{public}d) OnAbilityStarted.", __func__, __LINE__); +} + +void ProcessOptimizer::OnAbilityConnected(const AbilityPtr &ability, const AbilityPtr &targetAbility) +{ + if (!ability) { + APP_LOGE("%{public}s(%{public}d) invalid ability.", __func__, __LINE__); + return; + } + + if (!targetAbility) { + APP_LOGE("%{public}s(%{public}d) invalid targetAbility.", __func__, __LINE__); + return; + } + + APP_LOGI("%{public}s(%{public}d) OnAbilityConnected.", __func__, __LINE__); +} + +void ProcessOptimizer::OnAbilityDisconnected(const AbilityPtr &ability, const AbilityPtr &targetAbility) +{ + if (!ability) { + APP_LOGE("%{public}s(%{public}d) invalid ability.", __func__, __LINE__); + return; + } + + if (!targetAbility) { + APP_LOGE("%{public}s(%{public}d) invalid targetAbility.", __func__, __LINE__); + return; + } + + APP_LOGI("%{public}s(%{public}d) OnAbilityDisconnected.", __func__, __LINE__); +} + +void ProcessOptimizer::OnAbilityStateChanged(const AbilityPtr &ability, const AbilityState oldState) +{ + if (!ability) { + APP_LOGE("%{public}s(%{public}d) invalid ability.", __func__, __LINE__); + return; + } + + APP_LOGI("%{public}s(%{public}d) OnAbilityStateChanged.", __func__, __LINE__); +} + +void ProcessOptimizer::OnAbilityVisibleChanged(const AbilityPtr &ability) +{ + if (!ability) { + APP_LOGE("%{public}s(%{public}d) invalid ability.", __func__, __LINE__); + return; + } + + APP_LOGI("%{public}s(%{public}d) OnAbilityVisibleChanged.", __func__, __LINE__); +} + +void ProcessOptimizer::OnAbilityPerceptibleChanged(const AbilityPtr &ability) +{ + if (!ability) { + APP_LOGE("%{public}s(%{public}d) invalid ability.", __func__, __LINE__); + } + + APP_LOGI("%{public}s(%{public}d) OnAbilityPerceptibleChanged.", __func__, __LINE__); +} + +void ProcessOptimizer::OnAbilityRemoved(const AbilityPtr &ability) +{ + if (!ability) { + APP_LOGE("%{public}s(%{public}d) invalid ability.", __func__, __LINE__); + return; + } + + APP_LOGI("%{public}s(%{public}d) OnAbilityRemoved.", __func__, __LINE__); +} + +bool ProcessOptimizer::SetAppOomAdj(const AppPtr &app, int oomAdj) +{ + if (!app) { + APP_LOGE("%{public}s(%{public}d) invalid app.", __func__, __LINE__); + return false; + } + + if (!LmkdClient::CheckOomAdj(oomAdj)) { + APP_LOGE("%{public}s(%{public}d) invalid oom adj %{public}d.", __func__, __LINE__, oomAdj); + return false; + } + + if (!lmkdClient_) { + APP_LOGE("%{public}s(%{public}d) invalid lmkd client.", __func__, __LINE__); + return false; + } + + auto priorityObject = app->GetPriorityObject(); + if (!priorityObject) { + APP_LOGE("%{public}s(%{public}d) invalid priority object.", __func__, __LINE__); + return false; + } + + if (priorityObject->GetCurAdj() == oomAdj) { + APP_LOGW("%{public}s(%{public}d) oom adj has no change.", __func__, __LINE__); + return true; + } + + if (lmkdClient_->ProcPrio(priorityObject->GetPid(), app->GetUid(), oomAdj) != ERR_OK) { + APP_LOGE("%{public}s(%{public}d) lmkd proc prio failed.", __func__, __LINE__); + return false; + } + + priorityObject->SetCurAdj(oomAdj); + + return true; +} + +bool ProcessOptimizer::SetAppSchedPolicy(const AppPtr &app, const CgroupManager::SchedPolicy schedPolicy) +{ + if (!app) { + APP_LOGE("%{public}s(%{public}d) invalid app.", __func__, __LINE__); + return false; + } + + auto priorityObject = app->GetPriorityObject(); + if (!priorityObject) { + APP_LOGE("%{public}s(%{public}d) invalid priority object.", __func__, __LINE__); + return false; + } + + auto oldSchedPolicy = priorityObject->GetCurCgroup(); + if (oldSchedPolicy == schedPolicy) { + APP_LOGW("%{public}s(%{public}d) no change.", __func__, __LINE__); + return true; + } + + bool result = + DelayedSingleton::GetInstance()->SetProcessSchedPolicy(priorityObject->GetPid(), schedPolicy); + if (result) { + priorityObject->SetCurCgroup(schedPolicy); + if (schedPolicy == CgroupManager::SCHED_POLICY_FREEZED) { + if (AppSuspended) { + AppSuspended(app); + } + } else if (oldSchedPolicy == CgroupManager::SCHED_POLICY_FREEZED) { + if (AppResumed) { + AppResumed(app); + } + } + } + + return result; +} + +void ProcessOptimizer::OnLowMemoryAlert(const CgroupManager::LowMemoryLevel level) +{ + // Find the oldest background app. + for (auto it(appLru_.rbegin()); it != appLru_.rend(); ++it) { + if ((*it)->GetState() == ApplicationState::APP_STATE_BACKGROUND) { + AppLowMemoryAlert(*it, level); + break; + } + } + + // kill process + if (lmkUtil_) { + int32_t proc_cnt = 0; + int64_t free_rss = 0; + + // kill process and free memory by oom_adj. the function will remove app object in appLru + proc_cnt = lmkUtil_->KillProcess(appLru_, level, free_rss); + #if __WORDSIZE == 64 + APP_LOGI("%{public}s(%{public}d) free memory proc count %{public}d rss %{public}ld", + __func__, + __LINE__, + proc_cnt, + free_rss); + #else + APP_LOGI("%{public}s(%{public}d) free memory proc count %{public}d rss %{public}lld", + __func__, + __LINE__, + proc_cnt, + free_rss); + #endif + + } +} + +bool ProcessOptimizer::UpdateAppOomAdj(const AppPtr &app) +{ + if (!app) { + APP_LOGE("%{public}s(%{public}d) invalid app.", __func__, __LINE__); + return false; + } + + auto priorityObject = app->GetPriorityObject(); + if (!priorityObject) { + APP_LOGE("%{public}s(%{public}d) invalid priority object.", __func__, __LINE__); + return false; + } + + auto state = app->GetState(); + + if (state == ApplicationState::APP_STATE_FOREGROUND || state == ApplicationState::APP_STATE_CREATE || + state == ApplicationState::APP_STATE_READY) { + return SetAppOomAdj(app, APP_OOM_ADJ_FOREGROUND); + } + + int oomAdj; + int oomAdjMax; + + switch (state) { + case ApplicationState::APP_STATE_BACKGROUND: + oomAdj = APP_OOM_ADJ_BACKGROUND_MIN; + oomAdjMax = APP_OOM_ADJ_BACKGROUND_MAX; + + // perceptible oom_adj + if (priorityObject->GetPerceptibleStatus()) { + oomAdj = APP_OOM_ADJ_PERCEPTIBLE_MIN; + oomAdjMax = APP_OOM_ADJ_PERCEPTIBLE_MAX; + } + + // visible oom_adj + if (priorityObject->GetVisibleStatus()) { + oomAdj = APP_OOM_ADJ_VISIBLE_MIN; + oomAdjMax = APP_OOM_ADJ_VISIBLE_MAX; + } + break; + case ApplicationState::APP_STATE_SUSPENDED: + oomAdj = APP_OOM_ADJ_SUSPEND_MIN; + oomAdjMax = APP_OOM_ADJ_SUSPEND_MAX; + break; + default: + oomAdj = APP_OOM_ADJ_UNKNOWN; + oomAdjMax = APP_OOM_ADJ_UNKNOWN; + break; + } + + for (auto curApp : appLru_) { + if (curApp->GetState() != state) { + continue; + } + SetAppOomAdj(curApp, oomAdj); + if (oomAdj < oomAdjMax) { + oomAdj += 1; + } + } + + return true; +} + +bool ProcessOptimizer::UpdateAppSchedPolicy(const AppPtr &app) +{ + if (!app) { + APP_LOGE("%{public}s(%{public}d) invalid app.", __func__, __LINE__); + return false; + } + + bool ret = false; + + switch (app->GetState()) { + case ApplicationState::APP_STATE_CREATE: + case ApplicationState::APP_STATE_READY: + case ApplicationState::APP_STATE_FOREGROUND: + ret = SetAppSchedPolicy(app, CgroupManager::SCHED_POLICY_DEFAULT); + break; + case ApplicationState::APP_STATE_BACKGROUND: + ret = SetAppSchedPolicy(app, CgroupManager::SCHED_POLICY_BACKGROUND); + break; + case ApplicationState::APP_STATE_SUSPENDED: + // SUSPEND state should be set in 'ProcessOptimizer::SuspendApp()' (to be specific, + // in 'AppSuspended' callback), and the sched policy has been set in it, so do nothing here. + ret = true; + break; + default: + ret = true; + break; + } + + return ret; +} + +void ProcessOptimizer::StartAppSuspendTimer(const AppPtr &app) +{ + if (!app) { + APP_LOGE("%{public}s(%{public}d) invalid app.", __func__, __LINE__); + return; + } + + APP_LOGI("%{public}s(%{public}d) starting suspend timer for app '%{public}s'...", + __func__, + __LINE__, + app->GetName().c_str()); + + if (!eventHandler_) { + APP_LOGE("%{public}s(%{public}d) invalid event handler.", __func__, __LINE__); + return; + } + + auto timerName = GetAppSuspendTimerName(app); + if (timerName.empty()) { + APP_LOGE("%{public}s(%{public}d) invalid suspend timer name.", __func__, __LINE__); + return; + } + + auto it = suspendTimers_.find(timerName); + if (it != suspendTimers_.end()) { + APP_LOGW("%{public}s(%{public}d) app '%{public}s' suspend timer already started.", + __func__, + __LINE__, + app->GetName().c_str()); + return; + } + + suspendTimers_.emplace(timerName); + + eventHandler_->PostTask( + [=]() { + auto it = suspendTimers_.find(timerName); + if (it != suspendTimers_.end()) { + APP_LOGD("%{public}s(%{public}d) removing app '%{public}s' suspend timer name...", + timerName.c_str(), + __LINE__, + app->GetName().c_str()); + suspendTimers_.erase(it); + } else { + APP_LOGE("%{public}s(%{public}d) invalid suspend timer for app '%{public}s'.", + timerName.c_str(), + __LINE__, + app->GetName().c_str()); + } + SuspendApp(app); + }, + timerName, + suspendTimeout_); +} + +void ProcessOptimizer::StopAppSuspendTimer(const AppPtr &app) +{ + if (!app) { + APP_LOGE("%{public}s(%{public}d) invalid app.", __func__, __LINE__); + return; + } + + APP_LOGI("%{public}s(%{public}d) stopping suspend timer for app '%{public}s'...", + __func__, + __LINE__, + app->GetName().c_str()); + + if (!eventHandler_) { + APP_LOGE("%{public}s(%{public}d) invalid event handler.", __func__, __LINE__); + return; + } + + auto timerName = GetAppSuspendTimerName(app); + if (timerName.empty()) { + APP_LOGE("%{public}s(%{public}d) invalid suspend timer name.", __func__, __LINE__); + return; + } + + auto it = suspendTimers_.find(timerName); + if (it == suspendTimers_.end()) { + APP_LOGW("%{public}s(%{public}d) app '%{public}s' suspend timer not started.", + __func__, + __LINE__, + app->GetName().c_str()); + return; + } + + suspendTimers_.erase(it); + eventHandler_->RemoveTask(timerName); +} + +void ProcessOptimizer::SuspendApp(const AppPtr &app) +{ + if (!app) { + APP_LOGE("%{public}s(%{public}d) invalid app.", __func__, __LINE__); + return; + } + + APP_LOGI("%{public}s(%{public}d) suspending app '%{public}s'...", __func__, __LINE__, app->GetName().c_str()); + + if (app->GetState() == ApplicationState::APP_STATE_SUSPENDED) { + APP_LOGE( + "%{public}s(%{public}d) app '%{public}s' already suspended.", __func__, __LINE__, app->GetName().c_str()); + return; + } + + if (!SetAppSchedPolicy(app, CgroupManager::SCHED_POLICY_FREEZED)) { + APP_LOGE("%{public}s(%{public}d) failed to suspend app '%s'.", __func__, __LINE__, app->GetName().c_str()); + } +} + +std::string ProcessOptimizer::GetAppSuspendTimerName(const AppPtr &app) +{ + std::string ret; + + if (app) { + auto priorityObject = app->GetPriorityObject(); + if (priorityObject) { + ret = APP_SUSPEND_TIMER_NAME_PREFIX + std::to_string(priorityObject->GetPid()); + } + } + + return ret; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/appmgr/src/process_optimizer_uba.cpp b/services/appmgr/src/process_optimizer_uba.cpp new file mode 100644 index 000000000..6921a2305 --- /dev/null +++ b/services/appmgr/src/process_optimizer_uba.cpp @@ -0,0 +1,371 @@ +/* + * 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 "process_optimizer_uba.h" +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { + +ProcessOptimizerUBA::BaseAbilityAction::BaseAbilityAction(const AbilityPtr &ability) + : time_(Clock::now()), name_(ability->GetName()) +{} + +ProcessOptimizerUBA::TimePoint ProcessOptimizerUBA::BaseAbilityAction::GetTime() const +{ + return time_; +} + +std::string ProcessOptimizerUBA::BaseAbilityAction::GetTimeString() const +{ + std::time_t tmp = Clock::to_time_t(time_); + char *pTime = std::ctime(&tmp); + return pTime == nullptr ? "" : std::string(pTime); +} + +const std::string &ProcessOptimizerUBA::BaseAbilityAction::GetName() const +{ + return name_; +} + +ProcessOptimizerUBA::StartAbilityAction::StartAbilityAction(const AbilityPtr &ability, const AbilityPtr &preAbility) + : BaseAbilityAction(ability), preName_(preAbility ? preAbility->GetName() : std::string()) +{} + +const std::string &ProcessOptimizerUBA::StartAbilityAction::GetPreName() const +{ + return preName_; +} + +ProcessOptimizerUBA::ConnectAbilityAction::ConnectAbilityAction( + const AbilityPtr &ability, const AbilityPtr &targetAbility) + : BaseAbilityAction(ability), targetName_(targetAbility->GetName()) +{} + +const std::string &ProcessOptimizerUBA::ConnectAbilityAction::GetTargetName() const +{ + return targetName_; +} + +ProcessOptimizerUBA::DisconnectAbilityAction::DisconnectAbilityAction( + const AbilityPtr &ability, const AbilityPtr &targetAbility) + : BaseAbilityAction(ability), targetName_(targetAbility->GetName()) +{} + +const std::string &ProcessOptimizerUBA::DisconnectAbilityAction::GetTargetName() const +{ + return targetName_; +} + +ProcessOptimizerUBA::ChangeAbilityStateAction::ChangeAbilityStateAction( + const AbilityPtr &ability, const AbilityState oldState) + : BaseAbilityAction(ability), oldState_(oldState), newState_(ability->GetState()) +{} + +AbilityState ProcessOptimizerUBA::ChangeAbilityStateAction::GetOldState() const +{ + return oldState_; +} + +AbilityState ProcessOptimizerUBA::ChangeAbilityStateAction::GetNewState() const +{ + return newState_; +} + +ProcessOptimizerUBA::ChangeAbilityVisible::ChangeAbilityVisible(const AbilityPtr &ability) + : BaseAbilityAction(ability){}; + +ProcessOptimizerUBA::ChangeAbilityPerceptible::ChangeAbilityPerceptible(const AbilityPtr &ability) + : BaseAbilityAction(ability){}; + +ProcessOptimizerUBA::RemoveAbilityAction::RemoveAbilityAction(const AbilityPtr &ability) : BaseAbilityAction(ability) +{} + +ProcessOptimizerUBA::ProcessOptimizerUBA( + const UbaServicePtr &ubaService, const LmkdClientPtr &lmkdClient, int suspendTimeout) + : ProcessOptimizer(lmkdClient, suspendTimeout), ubaService_(ubaService), abilityActionCount_(0) +{ + APP_LOGI("%{public}s(%{public}d) constructed.", __func__, __LINE__); +} + +ProcessOptimizerUBA::~ProcessOptimizerUBA() +{ + if (abilityActionCount_ > 0) { + CommitAbilityActions(); + } + + APP_LOGI("%{public}s(%{public}d) destructed.", __func__, __LINE__); +} + +void ProcessOptimizerUBA::OnAppAdded(const AppPtr &app) +{ + auto ubaService = GetUbaService(); + if (!ubaService) { + APP_LOGD("%{public}s(%{public}d) ubaService implement.", __func__, __LINE__); + } else { + ProcessOptimizer::OnAppAdded(app); + } +} + +void ProcessOptimizerUBA::OnAppRemoved(const AppPtr &app) +{ + auto ubaService = GetUbaService(); + if (!ubaService) { + APP_LOGD("%{public}s(%{public}d) ubaService implement.", __func__, __LINE__); + } else { + ProcessOptimizer::OnAppRemoved(app); + } +} + +void ProcessOptimizerUBA::OnAppStateChanged(const AppPtr &app, const ApplicationState oldState) +{ + auto ubaService = GetUbaService(); + if (!ubaService) { + APP_LOGD("%{public}s(%{public}d) ubaService implement.", __func__, __LINE__); + } else { + ProcessOptimizer::OnAppStateChanged(app, oldState); + } +} + +void ProcessOptimizerUBA::OnAbilityStarted(const AbilityPtr &ability) +{ + if (!ability) { + APP_LOGE("%{public}s(%{public}d) invalid ability.", __func__, __LINE__); + return; + } + + AbilityPtr preAbility; + auto preToken = ability->GetPreToken(); + + if (GetAbilityByToken) { + // 'preAbility' can be a nullptr. + preAbility = GetAbilityByToken(preToken); + } else { + APP_LOGW("%{public}s(%{public}d) 'GetAbilityByToken' is not registered.", __func__, __LINE__); + } + + RecordAbilityAction(ability, preAbility); + + auto ubaService = GetUbaService(); + if (!ubaService) { + APP_LOGD("%{public}s(%{public}d) ubaService implement.", __func__, __LINE__); + } else { + ProcessOptimizer::OnAbilityStarted(ability); + } +} + +void ProcessOptimizerUBA::OnAbilityConnected(const AbilityPtr &ability, const AbilityPtr &targetAbility) +{ + if (!ability) { + APP_LOGE("%{public}s(%{public}d) invalid ability.", __func__, __LINE__); + return; + } + + if (!targetAbility) { + APP_LOGE("%{public}s(%{public}d) invalid targetAbility.", __func__, __LINE__); + return; + } + + RecordAbilityAction(ability, targetAbility); + + auto ubaService = GetUbaService(); + if (!ubaService) { + APP_LOGD("%{public}s(%{public}d) ubaService implement.", __func__, __LINE__); + } else { + ProcessOptimizer::OnAbilityConnected(ability, targetAbility); + } +} + +void ProcessOptimizerUBA::OnAbilityDisconnected(const AbilityPtr &ability, const AbilityPtr &targetAbility) +{ + if (!ability) { + APP_LOGE("%{public}s(%{public}d) invalid ability.", __func__, __LINE__); + return; + } + + if (!targetAbility) { + APP_LOGE("%{public}s(%{public}d) invalid targetAbility.", __func__, __LINE__); + return; + } + + RecordAbilityAction(ability, targetAbility); + + auto ubaService = GetUbaService(); + if (!ubaService) { + APP_LOGD("%{public}s(%{public}d) ubaService implement.", __func__, __LINE__); + } else { + ProcessOptimizer::OnAbilityDisconnected(ability, targetAbility); + } +} + +void ProcessOptimizerUBA::OnAbilityStateChanged(const AbilityPtr &ability, const AbilityState oldState) +{ + if (!ability) { + APP_LOGE("%{public}s(%{public}d) invalid ability.", __func__, __LINE__); + return; + } + + RecordAbilityAction(ability, oldState); + auto ubaService = GetUbaService(); + if (!ubaService) { + APP_LOGD("%{public}s(%{public}d) ubaService implement.", __func__, __LINE__); + } else { + ProcessOptimizer::OnAbilityStateChanged(ability, oldState); + } +} + +void ProcessOptimizerUBA::OnAbilityVisibleChanged(const AbilityPtr &ability) +{ + if (!ability) { + APP_LOGE("%{public}s(%{public}d) invalid ability.", __func__, __LINE__); + return; + } + + RecordAbilityAction(ability); + auto ubaService = GetUbaService(); + if (!ubaService) { + APP_LOGD("%{public}s(%{public}d) ubaService implement.", __func__, __LINE__); + } else { + ProcessOptimizer::OnAbilityVisibleChanged(ability); + } +} + +void ProcessOptimizerUBA::OnAbilityPerceptibleChanged(const AbilityPtr &ability) +{ + if (!ability) { + APP_LOGE("%{public}s(%{public}d) invalid ability.", __func__, __LINE__); + return; + } + + RecordAbilityAction(ability); + auto ubaService = GetUbaService(); + if (!ubaService) { + APP_LOGD("%{public}s(%{public}d) ubaService implement.", __func__, __LINE__); + } else { + ProcessOptimizer::OnAbilityPerceptibleChanged(ability); + } +} + +void ProcessOptimizerUBA::OnAbilityRemoved(const AbilityPtr &ability) +{ + if (!ability) { + APP_LOGE("%{public}s(%{public}d) invalid ability.", __func__, __LINE__); + return; + } + + RecordAbilityAction(ability); + + auto ubaService = GetUbaService(); + if (!ubaService) { + APP_LOGD("%{public}s(%{public}d) ubaService implement.", __func__, __LINE__); + } else { + ProcessOptimizer::OnAbilityRemoved(ability); + } +} + +void ProcessOptimizerUBA::OnLowMemoryAlert(const CgroupManager::LowMemoryLevel level) +{ + auto ubaService = GetUbaService(); + if (!ubaService) { + APP_LOGD("%{public}s(%{public}d) ubaService implement.", __func__, __LINE__); + } else { + ProcessOptimizer::OnLowMemoryAlert(level); + } +} + +void ProcessOptimizerUBA::CommitAbilityActions() +{ + auto n = abilityActionCount_; + abilityActionCount_ = 0; + + auto ubaService = GetUbaService(); + if (!ubaService) { + APP_LOGE("%{public}s(%{pubic}d) uba is not available.", __func__, __LINE__); + return; + } + + APP_LOGI("%{public}s(%{pubic}d) committing %{public}zu actions...", __func__, __LINE__, n); + + for (size_t i = 0; i < n; ++i) { + auto &abilityAction = abilityActionCache_[i]; + + auto startAbilityAction = std::get_if(&abilityAction); + if (startAbilityAction) { + APP_LOGD(" [%{public}zu] %{public}s ability '%{public}s' starts '%{public}s'", + i, + startAbilityAction->GetTimeString().c_str(), + startAbilityAction->GetPreName().c_str(), + startAbilityAction->GetName().c_str()); + // commit action + continue; + } + + auto connectAbilityAction = std::get_if(&abilityAction); + if (connectAbilityAction) { + APP_LOGD(" [%{public}zu] %{public}s ability '%{public}s' connect to '%{public}s'", + i, + connectAbilityAction->GetTimeString().c_str(), + connectAbilityAction->GetName().c_str(), + connectAbilityAction->GetTargetName().c_str()); + // commit action + continue; + } + + auto disconnectAbilityAction = std::get_if(&abilityAction); + if (disconnectAbilityAction) { + APP_LOGD(" [%{public}zu] %{public}s '%{public}s' ability disconnect with '%{public}s'", + i, + disconnectAbilityAction->GetTimeString().c_str(), + disconnectAbilityAction->GetName().c_str(), + disconnectAbilityAction->GetTargetName().c_str()); + // commit action + continue; + } + + auto changedAbilityStateAction = std::get_if(&abilityAction); + if (changedAbilityStateAction) { + APP_LOGD(" [%{public}zu] %{public}s ability '%{public}s' state changed from %{public}d to %{public}d.", + i, + changedAbilityStateAction->GetTimeString().c_str(), + changedAbilityStateAction->GetName().c_str(), + changedAbilityStateAction->GetOldState(), + changedAbilityStateAction->GetNewState()); + // commit action + continue; + } + + auto removeAbilityAction = std::get_if(&abilityAction); + if (removeAbilityAction) { + APP_LOGD(" [%{public}zu] %{public}s '%{public}s' removed.", + i, + removeAbilityAction->GetTimeString().c_str(), + removeAbilityAction->GetName().c_str()); + // commit action + continue; + } + } +} + +UbaServicePtr ProcessOptimizerUBA::GetUbaService() +{ + if (ubaService_) { + return ubaService_; + } + + // try to get uba service here. + return nullptr; +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/appmgr/src/remote_client_manager.cpp b/services/appmgr/src/remote_client_manager.cpp new file mode 100644 index 000000000..ac024d0e8 --- /dev/null +++ b/services/appmgr/src/remote_client_manager.cpp @@ -0,0 +1,66 @@ +/* + * 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 "remote_client_manager.h" + +#include "iservice_registry.h" +#include "system_ability_definition.h" + +#include "app_log_wrapper.h" + +namespace OHOS { + +namespace AppExecFwk { + +RemoteClientManager::RemoteClientManager() : appSpawnClient_(std::make_shared()) +{} + +RemoteClientManager::~RemoteClientManager() +{} + +std::shared_ptr RemoteClientManager::GetSpawnClient() +{ + if (appSpawnClient_) { + return appSpawnClient_; + } + return nullptr; +} + +void RemoteClientManager::SetSpawnClient(const std::shared_ptr &appSpawnClient) +{ + appSpawnClient_ = appSpawnClient; +} + +sptr RemoteClientManager::GetBundleManager() +{ + if (bundleManager_ == nullptr) { + sptr systemManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (systemManager != nullptr) { + bundleManager_ = + iface_cast(systemManager->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID)); + } else { + APP_LOGE("AppMgrServiceInner::GetBundleManager fail to get SAMGR"); + } + } + return bundleManager_; +} + +void RemoteClientManager::SetBundleManager(sptr bundleManager) +{ + bundleManager_ = bundleManager; +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/appmgr/src/start_via_asan.cpp b/services/appmgr/src/start_via_asan.cpp new file mode 100644 index 000000000..decc6438e --- /dev/null +++ b/services/appmgr/src/start_via_asan.cpp @@ -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. + */ + +#include "start_via_asan.h" + +#include "properties.h" + +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { + +StartViaAsan::StartViaAsan() +{} + +StartViaAsan::~StartViaAsan() +{} + +bool StartViaAsan::IsAsanVersion(const std::string &name) const +{ + if (name.empty()) { + return false; + } + + std::string defaultWrapValue = ""; + std::string wrapAppName = "wrap." + name; + std::string propValue = GetProperty(wrapAppName, defaultWrapValue); + if (propValue != defaultWrapValue) { + APP_LOGI("%{public}s system prop set, value is %{public}s", wrapAppName.c_str(), propValue.c_str()); + return true; + } + APP_LOGI("%{public}s system prop not set", wrapAppName.c_str()); + return false; +} + +void StartViaAsan::GetAsanStartMsg(AppSpawnStartMsg &startMsg) const +{ + if (startMsg.arg.empty()) { + startMsg.arg = "wrap." + startMsg.procName; + } else { + startMsg.arg += " wrap." + startMsg.procName; + } + startMsg.argsNum++; +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/appmgr/test/BUILD.gn b/services/appmgr/test/BUILD.gn new file mode 100644 index 000000000..8b13ad4ad --- /dev/null +++ b/services/appmgr/test/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("appmgr_test_config") { + configs = [ + "${services_path}/appmgr:appmgr_config", + "${services_path}/test:services_mock_ams_config", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appmgr_sdk_config", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:bundlemgr_sdk_config", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base_sdk_config", + ] + + defines = [ + "APP_LOG_TAG = \"AppMgrService\"", + "LOG_DOMAIN = 0xD00111E", + ] + + include_dirs = [ "${services_path}/appmgr/test/mock/include" ] +} + +ohos_source_set("appmgr_test_source") { + testonly = true + + sources = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base/src/ability_info.cpp", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base/src/app_process_info.cpp", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base/src/application_info.cpp", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base/src/bundle_info.cpp", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base/src/element_name.cpp", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base/src/running_process_info.cpp", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core/src/appmgr/app_launch_data.cpp", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core/src/appmgr/app_mgr_proxy.cpp", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core/src/appmgr/app_mgr_stub.cpp", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core/src/appmgr/app_process_data.cpp", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core/src/appmgr/app_record_id.cpp", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core/src/appmgr/app_scheduler_host.cpp", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core/src/appmgr/app_scheduler_proxy.cpp", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core/src/appmgr/app_state_callback_host.cpp", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core/src/appmgr/app_state_callback_proxy.cpp", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core/src/appmgr/app_task_info.cpp", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core/src/appmgr/dummy_configuration.cpp", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core/src/appmgr/process_info.cpp", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core/src/appmgr/profile.cpp", + ] + + include_dirs = [ "//third_party/json/include" ] + + public_configs = [ + ":appmgr_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", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ + "unittest/ams_ability_running_record_test:unittest", + "unittest/ams_app_death_recipient_test:unittest", + "unittest/ams_app_life_cycle_test:unittest", + "unittest/ams_app_mgr_client_test:unittest", + "unittest/ams_app_running_record_test:unittest", + "unittest/ams_app_state_callback_test:unittest", + "unittest/ams_app_workflow_test:unittest", + "unittest/ams_ipc_interface_test:unittest", + "unittest/ams_mgr_scheduler_test:unittest", + "unittest/ams_recent_app_list_test:unittest", + "unittest/ams_service_app_spawn_client_test:unittest", + "unittest/ams_service_app_spawn_msg_wrapper_test:unittest", + "unittest/ams_service_app_spawn_socket_test:unittest", + "unittest/ams_service_event_drive_test:unittest", + "unittest/ams_service_load_ability_process_test:unittest", + "unittest/ams_service_startup_test:unittest", + "unittest/app_mgr_service_event_handler_test:unittest", + ] +} diff --git a/services/appmgr/test/mock/include/mock_ability_token.h b/services/appmgr/test/mock/include/mock_ability_token.h new file mode 100644 index 000000000..ffee93df5 --- /dev/null +++ b/services/appmgr/test/mock/include/mock_ability_token.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_APPMGR_TEST_UT_MOCK_ABILITY_TOKEN_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_TEST_UT_MOCK_ABILITY_TOKEN_H + +#include "nocopyable.h" +#include "iremote_broker.h" +#include "iremote_object.h" +#include "iremote_proxy.h" +#include "iremote_stub.h" + +namespace OHOS { +namespace AppExecFwk { + +class IAbilityToken : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.appexecfwk.AbilityToken"); +}; + +class MockAbilityToken : public IRemoteStub { +public: + MockAbilityToken() = default; + virtual ~MockAbilityToken() = default; + + virtual int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) + { + return 0; + } + +private: + DISALLOW_COPY_AND_MOVE(MockAbilityToken); +}; + +class AbilityTokenProxy : public IRemoteProxy { +public: + explicit AbilityTokenProxy(const sptr &impl) : IRemoteProxy(impl) + {} + + virtual ~AbilityTokenProxy() = default; + +private: + DISALLOW_COPY_AND_MOVE(AbilityTokenProxy); +}; + +DECLARE_INTERFACE_DESCRIPTOR(u"IAbilityToken"); + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_APPMGR_TEST_UT_MOCK_ABILITY_TOKEN_H diff --git a/services/appmgr/test/mock/include/mock_ams_mgr_scheduler.h b/services/appmgr/test/mock/include/mock_ams_mgr_scheduler.h new file mode 100644 index 000000000..9622d9a6b --- /dev/null +++ b/services/appmgr/test/mock/include/mock_ams_mgr_scheduler.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_APPMGR_TEST_UNITEST_MOCK_AMS_MGR_SCHEDULER_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_TEST_UNITEST_MOCK_AMS_MGR_SCHEDULER_H + +#include "gmock/gmock.h" +#include "ams_mgr_scheduler.h" + +namespace OHOS { +namespace AppExecFwk { + +class MockAmsMgrScheduler : public AmsMgrStub { + +public: + MOCK_METHOD4(LoadAbility, + void(const sptr &token, const sptr &preToken, + const std::shared_ptr &abilityInfo, const std::shared_ptr &appInfo)); + + MOCK_METHOD5(AbilityBehaviorAnalysis, + void(const sptr &token, const sptr &preToken, + const int32_t visibility, const int32_t perceptibility, const int32_t connectionState)); + + MOCK_METHOD1(TerminateAbility, void(const sptr &token)); + MOCK_METHOD2(UpdateAbilityState, void(const sptr &token, const AbilityState state)); + MOCK_METHOD0(Reset, void()); + MOCK_METHOD1(KillProcessByAbilityToken, void(const sptr &token)); + MOCK_METHOD1(KillApplication, int32_t(const std::string &bundleName)); + MOCK_METHOD0(IsReady, bool()); + + MockAmsMgrScheduler() : AmsMgrStub(){}; + virtual ~MockAmsMgrScheduler(){}; + + virtual void RegisterAppStateCallback(const sptr &callback) override + { + callback->OnAbilityRequestDone(nullptr, AbilityState::ABILITY_STATE_BACKGROUND); + AppProcessData appProcessData; + callback->OnAppStateChanged(appProcessData); + } +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/services/appmgr/test/mock/include/mock_app_mgr_service.h b/services/appmgr/test/mock/include/mock_app_mgr_service.h new file mode 100644 index 000000000..572193df3 --- /dev/null +++ b/services/appmgr/test/mock/include/mock_app_mgr_service.h @@ -0,0 +1,104 @@ +/* + * 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_COMMON_TEST_MOCK_MOCK_APP_MGR_SERVICE_H +#define FOUNDATION_APPEXECFWK_SERVICES_COMMON_TEST_MOCK_MOCK_APP_MGR_SERVICE_H + +#include "gmock/gmock.h" +#include "semaphore_ex.h" +#include "app_mgr_stub.h" + +namespace OHOS { +namespace AppExecFwk { +class MockAppMgrService : public AppMgrStub { +public: + MOCK_METHOD4(LoadAbility, + void(const sptr &token, const sptr &preToken, + const std::shared_ptr &abilityInfo, const std::shared_ptr &appInfo)); + MOCK_METHOD1(TerminateAbility, void(const sptr &token)); + MOCK_METHOD2(UpdateAbilityState, void(const sptr &token, const AbilityState state)); + MOCK_METHOD1(AttachApplication, void(const sptr &app)); + MOCK_METHOD1(ApplicationForegrounded, void(const int32_t recordId)); + MOCK_METHOD1(ApplicationBackgrounded, void(const int32_t recordId)); + MOCK_METHOD1(ApplicationTerminated, void(const int32_t recordId)); + MOCK_METHOD2(CheckPermission, int32_t(const int32_t recordId, const std::string &permission)); + MOCK_METHOD1(AbilityCleaned, void(const sptr &token)); + MOCK_METHOD1(KillApplication, int32_t(const std::string &appName)); + MOCK_METHOD1(ClearUpApplicationData, void(const std::string &bundleName)); + MOCK_METHOD1(IsBackgroundRunningRestricted, int(const std::string &bundleName)); + MOCK_METHOD1(GetAllRunningProcesses, int(std::shared_ptr &runningProcessInfo)); + MOCK_METHOD0(GetAmsMgr, sptr()); + + virtual void RegisterAppStateCallback(const sptr &callback) + { + callback_ = callback; + } + + int32_t CheckPermissionImpl([[maybe_unused]] const int32_t recordId, const std::string &data) + { + data_ = data; + return 0; + } + + void KillApplicationImpl(const std::string &data) + { + data_ = data; + } + + const std::string &GetData() const + { + return data_; + } + + void Wait() + { + sem_.Wait(); + } + + void Post() + { + sem_.Post(); + } + + void UpdateState() const + { + if (!callback_) { + return; + } + AppProcessData processData; + processData.appName = ""; + processData.pid = 1; + processData.appState = ApplicationState::APP_STATE_BEGIN; + callback_->OnAppStateChanged(processData); + } + + void Terminate(const sptr &token) const + { + if (!callback_) { + return; + } + AbilityState st = AbilityState::ABILITY_STATE_BEGIN; + callback_->OnAbilityRequestDone(token, st); + } + +private: + Semaphore sem_; + std::string data_; + sptr callback_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_COMMON_TEST_MOCK_MOCK_APP_MGR_SERVICE_H \ No newline at end of file diff --git a/services/appmgr/test/mock/include/mock_app_mgr_service_inner.h b/services/appmgr/test/mock/include/mock_app_mgr_service_inner.h new file mode 100644 index 000000000..9ad3cb0d5 --- /dev/null +++ b/services/appmgr/test/mock/include/mock_app_mgr_service_inner.h @@ -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. + */ + +#ifndef FOUNDATION_APPEXECFWK_SERVICES_APPMGR_TEST_MOCK_APP_MGR_SERVICE_INNER_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_TEST_MOCK_APP_MGR_SERVICE_INNER_H + +#include "gmock/gmock.h" +#include "app_log_wrapper.h" + +#include "semaphore_ex.h" +#include "app_mgr_service_inner.h" + +namespace OHOS { +namespace AppExecFwk { + +class MockAppMgrServiceInner : public AppMgrServiceInner { +public: + MockAppMgrServiceInner() : lock_(0) + {} + virtual ~MockAppMgrServiceInner() + {} + + MOCK_METHOD4(LoadAbility, + void(const sptr &token, const sptr &preToken, + const std::shared_ptr &abilityInfo, const std::shared_ptr &appInfo)); + MOCK_METHOD2(AttachApplication, void(const pid_t pid, const sptr &app)); + MOCK_METHOD1(ApplicationForegrounded, void(const int32_t recordId)); + MOCK_METHOD1(ApplicationBackgrounded, void(const int32_t recordId)); + MOCK_METHOD1(ApplicationTerminated, void(const int32_t recordId)); + MOCK_METHOD2(UpdateAbilityState, void(const sptr &token, const AbilityState state)); + MOCK_METHOD1(TerminateAbility, void(const sptr &token)); + MOCK_METHOD1(KillApplication, int32_t(const std::string &bundleName)); + MOCK_METHOD1(AbilityTerminated, void(const sptr &token)); + MOCK_METHOD3(ClearUpApplicationData, void(const std::string &, const int32_t, const pid_t)); + MOCK_METHOD1(IsBackgroundRunningRestricted, int32_t(const std::string &)); + MOCK_METHOD1(GetAllRunningProcesses, int32_t(std::shared_ptr &)); + MOCK_METHOD1(RegisterAppStateCallback, void(const sptr &callback)); + MOCK_METHOD0(StopAllProcess, void()); + MOCK_CONST_METHOD0(QueryAppSpawnConnectionState, SpawnConnectionState()); + MOCK_CONST_METHOD2(AddAppDeathRecipient, void(const pid_t pid, const sptr &appDeathRecipient)); + MOCK_METHOD1(KillProcessByAbilityToken, void(const sptr &token)); + + MOCK_METHOD5(AbilityBehaviorAnalysis, + void(const sptr &token, const sptr &preToken, const int32_t visibility, + const int32_t perceptibility, const int32_t connectionState)); + MOCK_METHOD2(OptimizerAbilityStateChanged, + void(const std::shared_ptr &ability, const AbilityState state)); + + void Post() + { + if (currentCount_ > 1) { + currentCount_--; + } else { + lock_.Post(); + currentCount_ = count_; + } + } + + // for mock function return int32_t + int32_t Post4Int() + { + if (currentCount_ > 1) { + currentCount_--; + } else { + lock_.Post(); + currentCount_ = count_; + } + return 0; + } + + void Wait() + { + lock_.Wait(); + } + + void SetWaitCount(const int waitCount) + { + count_ = waitCount; + currentCount_ = waitCount; + } + + int32_t OpenAppSpawnConnection() override + { + return 0; + } + +private: + Semaphore lock_; + int32_t count_ = 1; + int32_t currentCount_ = 1; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_APPMGR_TEST_MOCK_APP_MGR_SERVICE_INNER_H diff --git a/services/appmgr/test/mock/include/mock_app_scheduler.h b/services/appmgr/test/mock/include/mock_app_scheduler.h new file mode 100644 index 000000000..c1873d422 --- /dev/null +++ b/services/appmgr/test/mock/include/mock_app_scheduler.h @@ -0,0 +1,47 @@ +/* + * 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_APPMGR_TEST_UNITEST_AMS_APP_LIFE_CYCLE_TEST_MOCK_APP_SCHEDULER_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_TEST_UNITEST_AMS_APP_LIFE_CYCLE_TEST_MOCK_APP_SCHEDULER_H + +#include "gmock/gmock.h" +#include "refbase.h" +#include "iremote_object.h" +#include "app_scheduler_host.h" +#include "app_launch_data.h" + +namespace OHOS { +namespace AppExecFwk { + +class MockAppScheduler : public AppSchedulerHost { +public: + MockAppScheduler(){}; + virtual ~MockAppScheduler(){}; + + MOCK_METHOD0(ScheduleForegroundApplication, void()); + MOCK_METHOD0(ScheduleBackgroundApplication, void()); + MOCK_METHOD0(ScheduleTerminateApplication, void()); + MOCK_METHOD1(ScheduleLaunchApplication, void(const AppLaunchData &)); + MOCK_METHOD2(ScheduleLaunchAbility, void(const AbilityInfo &, const sptr &)); + MOCK_METHOD1(ScheduleCleanAbility, void(const sptr &)); + MOCK_METHOD1(ScheduleProfileChanged, void(const Profile &)); + MOCK_METHOD1(ScheduleConfigurationUpdated, void(const Configuration &config)); + MOCK_METHOD1(ScheduleShrinkMemory, void(const int)); + MOCK_METHOD0(ScheduleLowMemory, void()); + MOCK_METHOD0(ScheduleProcessSecurityExit, void()); +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_APPMGR_TEST_UNITEST_AMS_APP_LIFE_CYCLE_TEST_MOCK_APP_SCHEDULER_CLIENT_H diff --git a/services/appmgr/test/mock/include/mock_app_service_mgr.h b/services/appmgr/test/mock/include/mock_app_service_mgr.h new file mode 100644 index 000000000..16a281468 --- /dev/null +++ b/services/appmgr/test/mock/include/mock_app_service_mgr.h @@ -0,0 +1,42 @@ +/* + * 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_APPMGR_TEST_MOCK_APP_SERVICE_MGR_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_TEST_MOCK_APP_SERVICE_MGR_H + +#include "iremote_object.h" + +#include "app_log_wrapper.h" +#include "app_service_manager.h" +#include "mock_app_mgr_service.h" + +namespace OHOS { +namespace AppExecFwk { + +class MockAppServiceMgr : public AppServiceManager { +public: + MockAppServiceMgr() = default; + virtual ~MockAppServiceMgr() = default; + + virtual sptr GetAppMgrService() const override + { + APP_LOGD("Mock MockAppServiceMgr GetAppMgrService called"); + return new MockAppMgrService(); + } +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_APPMGR_TEST_MOCK_APP_SERVICE_MGR_H \ No newline at end of file diff --git a/services/appmgr/test/mock/include/mock_app_spawn_client.h b/services/appmgr/test/mock/include/mock_app_spawn_client.h new file mode 100644 index 000000000..9ca532126 --- /dev/null +++ b/services/appmgr/test/mock/include/mock_app_spawn_client.h @@ -0,0 +1,35 @@ +/* + * 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_APPMGR_TEST_UT_MOCK_APP_SPAWN_CLIENT_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_TEST_UT_MOCK_APP_SPAWN_CLIENT_H + +#include "gmock/gmock.h" + +namespace OHOS { +namespace AppExecFwk { + +class MockAppSpawnClient : public AppSpawnClient { +public: + MockAppSpawnClient() + {} + virtual ~MockAppSpawnClient() + {} + MOCK_METHOD2(StartProcess, ErrCode(const AppSpawnStartMsg &startMsg, pid_t &pid)); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_APPMGR_TEST_UT_MOCK_APP_SPAWN_CLIENT_H diff --git a/services/appmgr/test/mock/include/mock_app_spawn_socket.h b/services/appmgr/test/mock/include/mock_app_spawn_socket.h new file mode 100644 index 000000000..e2f66ae17 --- /dev/null +++ b/services/appmgr/test/mock/include/mock_app_spawn_socket.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_APPMGR_TEST_UT_MOCK_APP_SPAWN_SOCKET_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_TEST_UT_MOCK_APP_SPAWN_SOCKET_H + +#include "gmock/gmock.h" +#include "app_spawn_socket.h" +#include "app_spawn_msg_wrapper.h" +#include "securec.h" +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { + +class MockAppSpawnSocket : public AppSpawnSocket { +public: + MockAppSpawnSocket() = default; + virtual ~MockAppSpawnSocket() = default; + + MOCK_METHOD0(OpenAppSpawnConnection, ErrCode()); + MOCK_METHOD0(CloseAppSpawnConnection, void()); + MOCK_METHOD2(WriteMessage, ErrCode(const void *buf, const int32_t len)); + MOCK_METHOD2(ReadMessage, ErrCode(void *buf, int32_t len)); + + ErrCode ReadImpl(void *buf, [[maybe_unused]] int32_t len) + { + if (buf == nullptr) { + return ERR_NO_MEMORY; + } + AppSpawnPidMsg msg; + msg.pid = expectPid_; + if (memcpy_s(buf, sizeof(msg), msg.pidBuf, sizeof(msg)) != 0) { + return ERR_APPEXECFWK_ASSEMBLE_START_MSG_FAILED; + } + return ERR_OK; + } + + void SetExpectPid(int32_t expectPid) + { + expectPid_ = expectPid; + } + +private: + int32_t expectPid_ = 0; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_APPMGR_TEST_UT_MOCK_APP_SPAWN_SOCKET_H diff --git a/services/appmgr/test/mock/include/mock_application.h b/services/appmgr/test/mock/include/mock_application.h new file mode 100644 index 000000000..52b560dbd --- /dev/null +++ b/services/appmgr/test/mock/include/mock_application.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_SERVICES_APPMGR_TEST_MOCK_APPLICATION_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_TEST_MOCK_APPLICATION_H + +#include "gmock/gmock.h" +#include "semaphore_ex.h" + +#include "app_scheduler_host.h" + +namespace OHOS { +namespace AppExecFwk { + +class MockApplication : public AppSchedulerHost { +public: + MOCK_METHOD0(ScheduleForegroundApplication, void()); + MOCK_METHOD0(ScheduleBackgroundApplication, void()); + MOCK_METHOD0(ScheduleTerminateApplication, void()); + MOCK_METHOD1(ScheduleShrinkMemory, void(const int)); + MOCK_METHOD0(ScheduleLowMemory, void()); + MOCK_METHOD1(ScheduleLaunchApplication, void(const AppLaunchData &)); + MOCK_METHOD2(ScheduleLaunchAbility, void(const AbilityInfo &, const sptr &)); + MOCK_METHOD1(ScheduleCleanAbility, void(const sptr &)); + MOCK_METHOD1(ScheduleProfileChanged, void(const Profile &)); + MOCK_METHOD1(ScheduleConfigurationUpdated, void(const Configuration &)); + MOCK_METHOD0(ScheduleProcessSecurityExit, void()); + + void Post() + { + lock_.Post(); + } + + void Wait() + { + lock_.Wait(); + } + + void ShrinkMemory(const int level) + { + shrinkLevel_ = level; + lock_.Post(); + } + + int GetShrinkLevel() const + { + return shrinkLevel_; + } + + void LaunchApplication(const AppLaunchData &launchData) + { + launchData_ = launchData; + lock_.Post(); + } + + bool CompareAppLaunchData(const AppLaunchData &launchData) const + { + if (launchData_.GetApplicationInfo().name != launchData.GetApplicationInfo().name) { + return false; + } + if (launchData_.GetProfile().GetName() != launchData.GetProfile().GetName()) { + return false; + } + if (launchData_.GetProcessInfo().GetProcessName() != launchData.GetProcessInfo().GetProcessName()) { + return false; + } + return true; + } + + void LaunchAbility(const AbilityInfo &info, const sptr &) + { + abilityInfo_ = info; + lock_.Post(); + } + + bool CompareAbilityInfo(const AbilityInfo &info) const + { + return (info.name == abilityInfo_.name); + } + + void ProfileChanged(const Profile &profile) + { + profile_ = profile; + lock_.Post(); + } + + bool CompareProfile(const Profile &profile) const + { + return (profile.GetName() == profile_.GetName()); + } + +private: + Semaphore lock_; + volatile int shrinkLevel_ = 0; + AppLaunchData launchData_; + AbilityInfo abilityInfo_; + Profile profile_; + // Configuration configuration_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_APPMGR_TEST_MOCK_APPLICATION_H diff --git a/services/appmgr/test/mock/include/mock_bundle_manager.h b/services/appmgr/test/mock/include/mock_bundle_manager.h new file mode 100644 index 000000000..2fcce5bc4 --- /dev/null +++ b/services/appmgr/test/mock/include/mock_bundle_manager.h @@ -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. + */ + +#ifndef OHOS_AAFWK_ABILITY_MOCK_BUNDLE_MANAGER_H +#define OHOS_AAFWK_ABILITY_MOCK_BUNDLE_MANAGER_H + +#include + +#include "gmock/gmock.h" +#include "ability_info.h" +#include "application_info.h" +#include "ohos/aafwk/content/want.h" +#include "iremote_proxy.h" +#include "iremote_stub.h" +#include "bundle_mgr_interface.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)); + 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 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 + { + 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 + { + return 0; + }; + virtual bool GetBundleNameForUid(const int uid, std::string &bundleName) override + { + 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 GetHapModuleInfo(const AbilityInfo &abilityInfo, HapModuleInfo &hapModuleInfo) override; + + 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; + }; +}; + +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(GetUidByBundleName, int(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)); + + 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 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 + { + 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); + // 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 + { + return true; + }; + virtual bool SetApplicationEnabled(const std::string &bundleName, bool isEnable) override + { + return true; + }; +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // OHOS_AAFWK_ABILITY_MOCK_BUNDLE_MANAGER_H diff --git a/services/appmgr/test/mock/include/mock_iapp_state_callback.h b/services/appmgr/test/mock/include/mock_iapp_state_callback.h new file mode 100644 index 000000000..44f80d093 --- /dev/null +++ b/services/appmgr/test/mock/include/mock_iapp_state_callback.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_COMMON_TEST_MOCK_IAPP_STATE_CALLBACK_H +#define FOUNDATION_APPEXECFWK_SERVICES_COMMON_TEST_MOCK_IAPP_STATE_CALLBACK_H + +#include "gmock/gmock.h" +#include "app_mgr_constants.h" +#include "app_state_callback_host.h" +#include "app_process_data.h" + +namespace OHOS { +namespace AppExecFwk { + +class MockAppStateCallback : public AppStateCallbackHost { +public: + MockAppStateCallback() + {} + virtual ~MockAppStateCallback() + {} + + MOCK_METHOD1(OnAppStateChanged, void(const AppProcessData &)); + MOCK_METHOD2(OnAbilityRequestDone, void(const sptr &, const AbilityState)); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_COMMON_TEST_MOCK_IAPP_STATE_CALLBACK_H \ No newline at end of file diff --git a/services/appmgr/test/mock/include/sys_mgr_client.h b/services/appmgr/test/mock/include/sys_mgr_client.h new file mode 100644 index 000000000..45a85087c --- /dev/null +++ b/services/appmgr/test/mock/include/sys_mgr_client.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 OHOS_OS_AAFWK_SYS_MRG_CLIENT_H +#define OHOS_OS_AAFWK_SYS_MRG_CLIENT_H + +#include +#include +#include +#include + +#include "if_system_ability_manager.h" +#include "iremote_object.h" +#include "singleton.h" + +namespace OHOS { +namespace AppExecFwk { + +class SysMrgClient { + DECLARE_DELAYED_SINGLETON(SysMrgClient) +public: + /** + * + * Get the systemAbility by ID. + * + * @param systemAbilityId The ID of systemAbility which want to get. + */ + sptr GetSystemAbility(const int32_t systemAbilityId); + + /** + * + * Register the systemAbility by ID. + * + * @param systemAbilityId The ID of systemAbility which want to register. + * @param broker The systemAbility which want to be registered. + */ + void RegisterSystemAbility(const int32_t systemAbilityId, sptr broker); + + /** + * + * Unregister the systemAbility by ID. + * + * @param systemAbilityId The ID of systemAbility which want to unregister. + */ + void UnregisterSystemAbility(const int32_t systemAbilityId); + +private: + OHOS::sptr sm_; + std::mutex saMutex_; + std::unordered_map> servicesMap_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // OHOS_OS_AAFWK_SYS_MRG_CLIENT_H diff --git a/services/appmgr/test/mock/include/system_ability.h b/services/appmgr/test/mock/include/system_ability.h new file mode 100644 index 000000000..f850c8c9c --- /dev/null +++ b/services/appmgr/test/mock/include/system_ability.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_SERVICES_APPMGR_TEST_MOCK_SYSTEM_ABILITY_H +#define FOUNDATION_APPEXECFWK_SERVICES_APPMGR_TEST_MOCK_SYSTEM_ABILITY_H + +#include "hilog/log.h" +#include "iremote_object.h" + +namespace OHOS { + +#define REGISTER_SYSTEM_ABILITY_BY_ID(a, b, c) +#define REGISTER_SYSTEM_ABILITY(abilityClassName, abilityId, runOnCreate) +#define DECLEAR_SYSTEM_ABILITY(className) + +static constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, 0xD001100, "MockSystemAbility"}; + +class SystemAbility { +protected: + virtual void OnStart() + { + HiviewDFX::HiLog::Debug(LABEL, "Mock SystemAbility OnStart called"); + } + + virtual void OnStop() + { + HiviewDFX::HiLog::Debug(LABEL, "Mock SystemAbility OnStop called"); + } + + bool Publish(sptr systemAbility) + { + HiviewDFX::HiLog::Debug(LABEL, "Mock SystemAbility Publish called"); + systemAbility.ForceSetRefPtr(nullptr); + // For test just mock to return true + return true; + } + + SystemAbility(bool runOnCreate = false) + { + HiviewDFX::HiLog::Debug(LABEL, "Mock SystemAbility default Creator called %d", runOnCreate); + } + + SystemAbility(const int32_t serviceId, bool runOnCreate = false) + { + HiviewDFX::HiLog::Debug(LABEL, "Mock SystemAbility Creator called %d", runOnCreate); + } + + virtual ~SystemAbility() + { + HiviewDFX::HiLog::Debug(LABEL, "Mock SystemAbility Destructor called"); + } +}; + +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_APPMGR_TEST_MOCK_SYSTEM_ABILITY_H diff --git a/services/appmgr/test/mock/src/mock_bundle_manager.cpp b/services/appmgr/test/mock/src/mock_bundle_manager.cpp new file mode 100644 index 000000000..7befaaed6 --- /dev/null +++ b/services/appmgr/test/mock/src/mock_bundle_manager.cpp @@ -0,0 +1,140 @@ +/* + * 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" + +namespace OHOS { +namespace AppExecFwk { + +bool BundleMgrProxy::QueryAbilityInfo(const AAFwk::Want &want, AbilityInfo &abilityInfo) +{ + ElementName eleName = want.GetElement(); + if (eleName.GetBundleName().empty()) { + return false; + } + abilityInfo.name = eleName.GetAbilityName(); + abilityInfo.bundleName = eleName.GetBundleName(); + abilityInfo.applicationName = "Helloworld"; + return true; +} + +bool BundleMgrProxy::QueryAbilityInfoByUri(const std::string &uri, AbilityInfo &abilityInfo) +{ + return false; +} + +bool BundleMgrProxy::GetApplicationInfo( + const std::string &appName, const ApplicationFlag flag, const int userId, ApplicationInfo &appInfo) +{ + if (appName.empty()) { + return false; + } + appInfo.name = "Helloworld"; + appInfo.bundleName = "com.ohos.hiworld"; + return true; +} + +std::string BundleMgrProxy::GetAppType(const std::string &bundleName) +{ + GTEST_LOG_(INFO) << " BundleMgrProxy::GetAppTyp"; + return "system"; +} + +int BundleMgrStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + return 0; +} + +bool BundleMgrService::QueryAbilityInfo(const AAFwk::Want &want, AbilityInfo &abilityInfo) +{ + ElementName elementName = want.GetElement(); + if (elementName.GetBundleName().empty()) { + return false; + } + if (std::string::npos != elementName.GetBundleName().find("service")) { + abilityInfo.type = AppExecFwk::AbilityType::SERVICE; + } + abilityInfo.name = elementName.GetAbilityName(); + abilityInfo.bundleName = elementName.GetBundleName(); + abilityInfo.applicationName = elementName.GetBundleName(); + if (want.HasEntity(Want::ENTITY_HOME) && want.GetAction() == Want::ACTION_HOME) { + abilityInfo.applicationInfo.isLauncherApp = true; + } else { + abilityInfo.applicationInfo.isLauncherApp = false; + } + 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) +{ + if (appName.empty()) { + return false; + } + appInfo.name = "Helloworld"; + appInfo.bundleName = "com.ohos.hiworld"; + return true; +} + +std::string BundleMgrService::GetAppType(const std::string &bundleName) +{ + GTEST_LOG_(INFO) << " BundleMgrService::GetAppType"; + return "system"; +} + +bool BundleMgrService::GetHapModuleInfo(const AbilityInfo &abilityInfo, HapModuleInfo &hapModuleInfo) +{ + GTEST_LOG_(INFO) << " BundleMgrService::GetHapModuleInfo"; + hapModuleInfo.name = "Captain"; + return true; +} + +bool BundleMgrProxy::GetHapModuleInfo(const AbilityInfo &abilityInfo, HapModuleInfo &hapModuleInfo) +{ + GTEST_LOG_(INFO) << " BundleMgrService::GetHapModuleInfo"; + hapModuleInfo.name = "Captain"; + return true; +} + +bool BundleMgrService::GetBundleInfo(const std::string &bundleName, const BundleFlag flag, BundleInfo &bundleInfo) +{ + int32_t userUid = 10001; + int32_t userGid = 10001; + bundleInfo.uid = userUid; + bundleInfo.gid = userGid; + return true; +} +bool BundleMgrService::GetBundleGids(const std::string &bundleName, std::vector &gids) +{ + int32_t userGid1 = 10001; + int32_t userGid2 = 10002; + int32_t userGid3 = 10003; + gids.push_back(userGid1); + gids.push_back(userGid2); + gids.push_back(userGid3); + return true; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/appmgr/test/mock/src/sys_mgr_client_mock.cpp b/services/appmgr/test/mock/src/sys_mgr_client_mock.cpp new file mode 100644 index 000000000..2d342890c --- /dev/null +++ b/services/appmgr/test/mock/src/sys_mgr_client_mock.cpp @@ -0,0 +1,47 @@ +/* + * 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 "sys_mgr_client.h" +#include "hilog_wrapper.h" +#include "if_system_ability_manager.h" +#include "iservice_registry.h" +#include "ipc_skeleton.h" +#include "string_ex.h" + +namespace OHOS { +namespace AppExecFwk { + +sptr SysMrgClient::GetSystemAbility(const int32_t systemAbilityId) +{ + if (servicesMap_[systemAbilityId] == nullptr) { + OHOS::sptr systemAbilityManager = + SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (systemAbilityManager == nullptr) { + HILOG_ERROR("%s:fail to get Registry", __func__); + return nullptr; + } + OHOS::sptr object = systemAbilityManager->GetSystemAbility(systemAbilityId); + servicesMap_[systemAbilityId] = object; + } + return servicesMap_[systemAbilityId]; +} + +void SysMrgClient::RegisterSystemAbility(const int32_t systemAbilityId, sptr broker) +{ + servicesMap_[systemAbilityId] = broker; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/appmgr/test/unittest/ams_ability_running_record_test/BUILD.gn b/services/appmgr/test/unittest/ams_ability_running_record_test/BUILD.gn new file mode 100644 index 000000000..071ad5c5b --- /dev/null +++ b/services/appmgr/test/unittest/ams_ability_running_record_test/BUILD.gn @@ -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. + +import("//build/test.gni") +import("//foundation/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/appmgrservice" + +ohos_unittest("AmsAbilityRunningRecordTest") { + module_out_path = module_output_path + + include_dirs = [ + "//foundation/aafwk/standard/interfaces/innerkits/base/include", + "//foundation/aafwk/standard/interfaces/innerkits/want/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include", + "//foundation/distributedschedule/dmsfwk/services/dtbschedmgr/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "//foundation/distributedschedule/samgr/adapter/interfaces/innerkits/include/", + ] + + sources = [ + "${services_path}/appmgr/src/ability_running_record.cpp", + "${services_path}/appmgr/src/app_mgr_service_inner.cpp", + "${services_path}/appmgr/src/app_running_record.cpp", + "${services_path}/appmgr/src/app_spawn_client.cpp", + "${services_path}/appmgr/src/app_spawn_msg_wrapper.cpp", + "${services_path}/appmgr/src/app_spawn_socket.cpp", + ] + + sources += [ "ams_ability_running_record_test.cpp" ] + + configs = [ + "${services_path}/appmgr/test:appmgr_test_config", + "${libs_path}/libeventhandler:libeventhandler_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${libs_path}/libeventhandler:libeventhandler_target", + "${services_path}/appmgr/test:appmgr_test_source", + "//base/startup/appspawn_standard:appspawn_socket_client", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "//foundation/appexecfwk/standard/services/appmgr:libams", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":AmsAbilityRunningRecordTest" ] +} 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 new file mode 100644 index 000000000..438b928a7 --- /dev/null +++ b/services/appmgr/test/unittest/ams_ability_running_record_test/ams_ability_running_record_test.cpp @@ -0,0 +1,529 @@ +/* + * 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_running_record.h" +#include +#include "app_running_record.h" +#include "app_scheduler_host.h" +#include "app_log_wrapper.h" +#include "mock_ability_token.h" +#include "mock_application.h" + +using namespace testing::ext; +using testing::_; +namespace OHOS { +namespace AppExecFwk { +class AmsAbilityRunningRecordTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + +protected: + static const std::string GetTestAppName() + { + return "test_app_name"; + } + static const std::string GetTestAbilityName() + { + return "test_ability_name"; + } + static const std::string GetAnotherTestAbilityName() + { + return "another_test_ability_name"; + } + static const std::string GetProcessName() + { + return "AmsAbilityRunningRecordTest"; + } + + std::shared_ptr GetTestAppRunningRecord(); + sptr GetMockedAppSchedulerClient(); + +protected: + sptr client_; + sptr mockedAppClient_; + std::shared_ptr testAppRecord_; +}; + +void AmsAbilityRunningRecordTest::SetUpTestCase() +{} + +void AmsAbilityRunningRecordTest::TearDownTestCase() +{} + +void AmsAbilityRunningRecordTest::SetUp() +{ + mockedAppClient_ = new MockApplication(); +} + +void AmsAbilityRunningRecordTest::TearDown() +{ + testAppRecord_.reset(); +} + +sptr AmsAbilityRunningRecordTest::GetMockedAppSchedulerClient() +{ + if (!client_) { + client_ = iface_cast(mockedAppClient_.GetRefPtr()); + } + return client_; +} + +std::shared_ptr AmsAbilityRunningRecordTest::GetTestAppRunningRecord() +{ + if (!testAppRecord_) { + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + testAppRecord_ = std::make_shared(appInfo, AppRecordId::Create(), GetProcessName()); + testAppRecord_->SetApplicationClient(GetMockedAppSchedulerClient()); + } + return testAppRecord_; +} + +/* + * Feature: AMS + * Function: AbilityRunningRecord + * SubFunction: NA + * FunctionPoints: Create AbilityRunningRecord using correct args. + * EnvConditions: NA + * CaseDescription: Verify the function AddAbility can create AbilityRunningRecord add add to AppRunningRecord. + */ +HWTEST_F(AmsAbilityRunningRecordTest, CreateAbilityRunningRecord_001, TestSize.Level0) +{ + APP_LOGD("CreateAbilityRunningRecord_001 start."); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + auto appRunningRecord = GetTestAppRunningRecord(); + sptr token = new MockAbilityToken(); + auto abilityRunningRecord = appRunningRecord->AddAbility(token, abilityInfo); + + EXPECT_TRUE(abilityRunningRecord != nullptr); + EXPECT_EQ(abilityRunningRecord, appRunningRecord->GetAbilityRunningRecordByToken(token)); + APP_LOGD("CreateAbilityRunningRecord_001 end."); +} + +/* + * Feature: AMS + * Function: AbilityRunningRecord + * SubFunction: NA + * FunctionPoints: Create AbilityRunningRecord using null args. + * EnvConditions: NA + * CaseDescription: Verify the function AddAbility works but does not take effect using nullptr parameter. + */ +HWTEST_F(AmsAbilityRunningRecordTest, CreateAbilityRunningRecord_002, TestSize.Level0) +{ + APP_LOGD("CreateAbilityRunningRecord_002 start."); + auto appRunningRecord = GetTestAppRunningRecord(); + sptr token = new MockAbilityToken(); + auto abilityRunningRecord = appRunningRecord->AddAbility(token, nullptr); + EXPECT_TRUE(abilityRunningRecord == nullptr); + APP_LOGD("CreateAbilityRunningRecord_002 end."); +} + +/* + * Feature: AMS + * Function: AbilityRunningRecord + * SubFunction: NA + * FunctionPoints: Create AbilityRunningRecord that already exists. + * EnvConditions: NA + * CaseDescription: Verify the function AddAbility does not take effect when abilityRunningRecord already exists. + */ +HWTEST_F(AmsAbilityRunningRecordTest, CreateAbilityRunningRecord_003, TestSize.Level0) +{ + APP_LOGD("CreateAbilityRunningRecord_003 start."); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + auto appRunningRecord = GetTestAppRunningRecord(); + sptr token = new MockAbilityToken(); + + auto abilityRunningRecordFirst = appRunningRecord->AddAbility(token, abilityInfo); + EXPECT_TRUE(abilityRunningRecordFirst != nullptr); + EXPECT_EQ(abilityRunningRecordFirst, appRunningRecord->GetAbilityRunningRecordByToken(token)); + + auto abilityRunningRecordSecond = appRunningRecord->AddAbility(token, abilityInfo); + EXPECT_TRUE(abilityRunningRecordSecond == nullptr); + APP_LOGD("CreateAbilityRunningRecord_003 end."); +} + +/* + * Feature: AMS + * Function: AbilityRunningRecord + * SubFunction: NA + * FunctionPoints: Update the state of AbilityRunningRecord using correct args. + * EnvConditions: NA + * CaseDescription: Verify the function UpdateAbilityState can update the state of AbilityRunningRecord correctly. + */ +HWTEST_F(AmsAbilityRunningRecordTest, UpdateAbilityRunningRecord_001, TestSize.Level0) +{ + APP_LOGD("UpdateAbilityRunningRecord_001 start."); + auto appRunningRecord = GetTestAppRunningRecord(); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + sptr token = new MockAbilityToken(); + + auto abilityRunningRecord = appRunningRecord->AddAbility(token, abilityInfo); + ASSERT_TRUE(abilityRunningRecord != nullptr); + abilityRunningRecord->SetState(AbilityState::ABILITY_STATE_READY); + appRunningRecord->SetState(ApplicationState::APP_STATE_READY); + + EXPECT_CALL(*mockedAppClient_, ScheduleForegroundApplication()).Times(1); + appRunningRecord->UpdateAbilityState(token, AbilityState::ABILITY_STATE_FOREGROUND); + appRunningRecord->PopForegroundingAbilityTokens(); + EXPECT_EQ(abilityRunningRecord->GetState(), AbilityState::ABILITY_STATE_FOREGROUND) << "execute fail!"; + + appRunningRecord->SetState(ApplicationState::APP_STATE_FOREGROUND); + EXPECT_CALL(*mockedAppClient_, ScheduleBackgroundApplication()).Times(1); + appRunningRecord->UpdateAbilityState(token, AbilityState::ABILITY_STATE_BACKGROUND); + EXPECT_EQ(abilityRunningRecord->GetState(), AbilityState::ABILITY_STATE_BACKGROUND) << "execute fail!"; + APP_LOGD("UpdateAbilityRunningRecord_001 end."); +} + +/* + * Feature: AMS + * Function: AbilityRunningRecord + * SubFunction: NA + * FunctionPoints: Update the state of AbilityRunningRecord using incorrect args. + * EnvConditions: NA + * CaseDescription: Verify the function UpdateAbilityState works but does not take effect using incorrect value. + */ +HWTEST_F(AmsAbilityRunningRecordTest, UpdateAbilityRunningRecord_002, TestSize.Level0) +{ + APP_LOGD("UpdateAbilityRunningRecord_002 start."); + auto appRunningRecord = GetTestAppRunningRecord(); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + sptr token = new MockAbilityToken(); + + auto abilityRunningRecord = appRunningRecord->AddAbility(token, abilityInfo); + ASSERT_TRUE(abilityRunningRecord != nullptr); + + AbilityState state = abilityRunningRecord->GetState(); + appRunningRecord->UpdateAbilityState(token, AbilityState::ABILITY_STATE_END); + EXPECT_EQ(abilityRunningRecord->GetState(), state); + EXPECT_NE(abilityRunningRecord->GetState(), AbilityState::ABILITY_STATE_END); + APP_LOGD("UpdateAbilityRunningRecord_002 end."); +} + +/* + * Feature: AMS + * Function: AbilityRunningRecord + * SubFunction: NA + * FunctionPoints: Update the state of AbilityRunningRecord using nullptr. + * EnvConditions: NA + * CaseDescription: Verify the function UpdateAbilityState works but does not take effect using nullptr parameter. + */ +HWTEST_F(AmsAbilityRunningRecordTest, UpdateAbilityRunningRecord_003, TestSize.Level0) +{ + APP_LOGD("UpdateAbilityRunningRecord_003 start."); + auto appRunningRecord = GetTestAppRunningRecord(); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + sptr token = new MockAbilityToken(); + auto abilityRunningRecord = appRunningRecord->AddAbility(token, abilityInfo); + ASSERT_TRUE(abilityRunningRecord != nullptr); + + AbilityState state = abilityRunningRecord->GetState(); + + appRunningRecord->UpdateAbilityState(nullptr, AbilityState::ABILITY_STATE_FOREGROUND); + EXPECT_EQ(abilityRunningRecord->GetState(), state); + APP_LOGD("UpdateAbilityRunningRecord_003 end."); +} + +/* + * Feature: AMS + * Function: AbilityRunningRecord + * SubFunction: NA + * FunctionPoints: Update the state of AbilityRunningRecord that does not exist. + * EnvConditions: NA + * CaseDescription: Verify the function UpdateAbilityState cannot change the state of AbilityRunningRecord + * that does not exist. + */ +HWTEST_F(AmsAbilityRunningRecordTest, UpdateAbilityRunningRecord_004, TestSize.Level0) +{ + APP_LOGD("UpdateAbilityRunningRecord_004 start."); + auto appRunningRecord = GetTestAppRunningRecord(); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + sptr token = new MockAbilityToken(); + + auto anotherAbilityInfo = std::make_shared(); + anotherAbilityInfo->name = GetAnotherTestAbilityName(); + sptr token2 = new MockAbilityToken(); + + auto abilityRunningRecord = appRunningRecord->AddAbility(token, abilityInfo); + ASSERT_TRUE(abilityRunningRecord != nullptr); + + AbilityState state = abilityRunningRecord->GetState(); + EXPECT_TRUE(appRunningRecord->GetAbilityRunningRecordByToken(token2) == nullptr); + appRunningRecord->UpdateAbilityState(token2, AbilityState::ABILITY_STATE_FOREGROUND); + EXPECT_EQ(abilityRunningRecord->GetState(), state); + APP_LOGD("UpdateAbilityRunningRecord_004 end."); +} + +/* + * Feature: AMS + * Function: AbilityRunningRecord + * SubFunction: NA + * FunctionPoints: Update one state of AbilityRunningRecords as foreground. + * EnvConditions: NA + * CaseDescription: Verify if there is at least one state of AbilityRunningRecords is foreground, + * the state of application should be changed to foreground. + */ +HWTEST_F(AmsAbilityRunningRecordTest, UpdateAbilityRunningRecord_005, TestSize.Level0) +{ + APP_LOGD("UpdateAbilityRunningRecord_005 start."); + auto appRunningRecord = GetTestAppRunningRecord(); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + auto anotherAbilityInfo = std::make_shared(); + anotherAbilityInfo->name = GetAnotherTestAbilityName(); + sptr token = new MockAbilityToken(); + sptr anotherToken = new MockAbilityToken(); + + auto abilityRunningRecord = appRunningRecord->AddAbility(token, abilityInfo); + auto anotherAbilityRunningRecord = appRunningRecord->AddAbility(anotherToken, anotherAbilityInfo); + + ASSERT_TRUE(abilityRunningRecord != nullptr); + ASSERT_TRUE(anotherAbilityRunningRecord != nullptr); + anotherAbilityRunningRecord->SetState(AbilityState::ABILITY_STATE_BACKGROUND); + appRunningRecord->SetState(ApplicationState::APP_STATE_BACKGROUND); + + EXPECT_CALL(*mockedAppClient_, ScheduleForegroundApplication()).Times(1); + appRunningRecord->UpdateAbilityState(anotherToken, AbilityState::ABILITY_STATE_FOREGROUND); + APP_LOGD("UpdateAbilityRunningRecord_005 end."); +} + +/* + * Feature: AMS + * Function: AbilityRunningRecord + * SubFunction: NA + * FunctionPoints: Update all states of AbilityRunningRecords as background. + * EnvConditions: NA + * CaseDescription: Verify if all states of AbilityRunningRecords are background, the state of application should be + * changed to background. + */ +HWTEST_F(AmsAbilityRunningRecordTest, UpdateAbilityRunningRecord_006, TestSize.Level0) +{ + APP_LOGD("UpdateAbilityRunningRecord_006 start."); + auto appRunningRecord = GetTestAppRunningRecord(); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + auto anotherAbilityInfo = std::make_shared(); + anotherAbilityInfo->name = GetAnotherTestAbilityName(); + sptr token = new MockAbilityToken(); + sptr anotherToken = new MockAbilityToken(); + auto abilityRunningRecord = appRunningRecord->AddAbility(token, abilityInfo); + auto anotherAbilityRunningRecord = appRunningRecord->AddAbility(anotherToken, anotherAbilityInfo); + EXPECT_TRUE(abilityRunningRecord != nullptr); + EXPECT_TRUE(anotherAbilityRunningRecord != nullptr); + anotherAbilityRunningRecord->SetState(AbilityState::ABILITY_STATE_FOREGROUND); + appRunningRecord->SetState(ApplicationState::APP_STATE_FOREGROUND); + abilityRunningRecord->SetState(AbilityState::ABILITY_STATE_FOREGROUND); + + EXPECT_CALL(*mockedAppClient_, ScheduleBackgroundApplication()).Times(1); + appRunningRecord->UpdateAbilityState(anotherToken, AbilityState::ABILITY_STATE_FOREGROUND); + + auto abilities = appRunningRecord->GetAbilities(); + for (auto iter = abilities.begin(); iter != abilities.end(); iter++) { + appRunningRecord->UpdateAbilityState(iter->second->GetToken(), AbilityState::ABILITY_STATE_BACKGROUND); + } + APP_LOGD("UpdateAbilityRunningRecord_006 end."); +} + +/* + * Feature: AMS + * Function: AbilityRunningRecord + * SubFunction: NA + * FunctionPoints: Update all states of AbilityRunningRecords as terminate. + * EnvConditions: NA + * CaseDescription: Verify if all states of AbilityRunningRecords are terminate, the state of application should be + * changed to terminate. + */ +HWTEST_F(AmsAbilityRunningRecordTest, UpdateAbilityRunningRecord_007, TestSize.Level0) +{ + APP_LOGD("UpdateAbilityRunningRecord_007 start."); + auto appRunningRecord = GetTestAppRunningRecord(); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + auto anotherAbilityInfo = std::make_shared(); + anotherAbilityInfo->name = GetAnotherTestAbilityName(); + sptr token = new MockAbilityToken(); + sptr anotherToken = new MockAbilityToken(); + auto abilityRunningRecord = appRunningRecord->AddAbility(token, abilityInfo); + auto anotherAbilityRunningRecord = appRunningRecord->AddAbility(anotherToken, anotherAbilityInfo); + EXPECT_TRUE(abilityRunningRecord != nullptr); + ASSERT_TRUE(anotherAbilityRunningRecord != nullptr); + anotherAbilityRunningRecord->SetState(AbilityState::ABILITY_STATE_BACKGROUND); + appRunningRecord->SetState(ApplicationState::APP_STATE_BACKGROUND); + abilityRunningRecord->SetState(AbilityState::ABILITY_STATE_BACKGROUND); + + EXPECT_CALL(*mockedAppClient_, ScheduleTerminateApplication()).Times(1); + EXPECT_CALL(*mockedAppClient_, ScheduleCleanAbility(_)).Times(2); + auto abilities = appRunningRecord->GetAbilities(); + for (auto iter = abilities.begin(); iter != abilities.end(); iter++) { + appRunningRecord->TerminateAbility(iter->second->GetToken()); + appRunningRecord->AbilityTerminated(iter->second->GetToken()); + } + APP_LOGD("UpdateAbilityRunningRecord_007 end."); +} + +/* + * Feature: AMS + * Function: AbilityRunningRecord + * SubFunction: NA + * FunctionPoints: Delete AbilityRunningRecord using correct args. + * EnvConditions: NA + * CaseDescription: Verify the function ClearAbility can delete AbilityRunningRecord. + */ +HWTEST_F(AmsAbilityRunningRecordTest, DeleteAbilityRunningRecord_001, TestSize.Level0) +{ + APP_LOGD("DeleteAbilityRunningRecord_001 start."); + auto appRunningRecord = GetTestAppRunningRecord(); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + sptr token = new MockAbilityToken(); + auto abilityRunningRecord = appRunningRecord->AddAbility(token, abilityInfo); + + EXPECT_TRUE(abilityRunningRecord != nullptr); + ASSERT_TRUE(appRunningRecord->GetAbilityRunningRecordByToken(token) != nullptr); + + appRunningRecord->ClearAbility(abilityRunningRecord); + EXPECT_TRUE(appRunningRecord->GetAbilityRunningRecordByToken(token) == nullptr); + APP_LOGD("DeleteAbilityRunningRecord_001 end."); +} + +/* + * Feature: AMS + * Function: AbilityRunningRecord + * SubFunction: NA + * FunctionPoints: Delete AbilityRunningRecord using null args. + * EnvConditions: NA + * CaseDescription: Verify the function ClearAbility works but does not take effect using nullptr parameter. + */ +HWTEST_F(AmsAbilityRunningRecordTest, DeleteAbilityRunningRecord_002, TestSize.Level0) +{ + APP_LOGD("DeleteAbilityRunningRecord_002 start."); + auto appRunningRecord = GetTestAppRunningRecord(); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + sptr token = new MockAbilityToken(); + auto abilityRunnningRecord = appRunningRecord->AddAbility(token, abilityInfo); + + EXPECT_TRUE(abilityRunnningRecord != nullptr); + ASSERT_TRUE(appRunningRecord->GetAbilityRunningRecordByToken(token) != nullptr); + + appRunningRecord->ClearAbility(nullptr); + EXPECT_TRUE(appRunningRecord->GetAbilityRunningRecordByToken(token) != nullptr); + APP_LOGD("DeleteAbilityRunningRecord_002 end."); +} + +/* + * Feature: AMS + * Function: AbilityRunningRecord + * SubFunction: NA + * FunctionPoints: Delete AbilityRunningRecord that does not exist. + * EnvConditions: NA + * CaseDescription: Verify the function ClearAbility cannot delete AbilityRunningRecord that does not exist. + */ +HWTEST_F(AmsAbilityRunningRecordTest, DeleteAbilityRunningRecord_003, TestSize.Level0) +{ + APP_LOGD("DeleteAbilityRunningRecord_003 start."); + auto appRunningRecord = GetTestAppRunningRecord(); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + auto anotherAbilityInfo = std::make_shared(); + anotherAbilityInfo->name = GetAnotherTestAbilityName(); + sptr token = new MockAbilityToken(); + sptr anotherToken = new MockAbilityToken(); + auto abilityRunningRecord = appRunningRecord->AddAbility(token, abilityInfo); + auto anotherAbilityRunningRecord = appRunningRecord->AddAbility(anotherToken, anotherAbilityInfo); + + EXPECT_TRUE(abilityRunningRecord != nullptr); + EXPECT_TRUE(anotherAbilityRunningRecord != nullptr); + EXPECT_TRUE(appRunningRecord->GetAbilityRunningRecordByToken(token) != nullptr); + EXPECT_TRUE(appRunningRecord->GetAbilityRunningRecordByToken(anotherToken) != nullptr); + + appRunningRecord->ClearAbility(anotherAbilityRunningRecord); + EXPECT_TRUE(appRunningRecord->GetAbilityRunningRecordByToken(token) != nullptr); + EXPECT_TRUE(appRunningRecord->GetAbilityRunningRecordByToken(anotherToken) == nullptr); + + appRunningRecord->ClearAbility(anotherAbilityRunningRecord); + EXPECT_TRUE(appRunningRecord->GetAbilityRunningRecordByToken(token) != nullptr); + EXPECT_TRUE(appRunningRecord->GetAbilityRunningRecordByToken(anotherToken) == nullptr); + APP_LOGD("DeleteAbilityRunningRecord_003 end."); +} + +/* + * Feature: AMS + * Function: AbilityRunningRecord + * SubFunction: IsSameState + * FunctionPoints: Check state is same or different. + * EnvConditions: NA + * CaseDescription: Verify the function IsSameState judge the exact state value. + */ +HWTEST_F(AmsAbilityRunningRecordTest, IsSameState_001, TestSize.Level0) +{ + APP_LOGD("IsSameState_001 start."); + + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + sptr token = new MockAbilityToken(); + std::shared_ptr abilityRunningRecord = + std::make_shared(abilityInfo, token); + + abilityRunningRecord->SetState(AbilityState::ABILITY_STATE_FOREGROUND); + EXPECT_EQ(false, abilityRunningRecord->IsSameState(AbilityState::ABILITY_STATE_BACKGROUND)); + EXPECT_EQ(true, abilityRunningRecord->IsSameState(AbilityState::ABILITY_STATE_FOREGROUND)); + + APP_LOGD("IsSameState_001 end."); +} + +/* + * Feature: AMS + * Function: AbilityRunningRecord + * SubFunction: NA + * FunctionPoints: Create AbilityRunningRecord using correct args. + * EnvConditions: NA + * CaseDescription: Verify the function AddAbility can create AbilityRunningRecord add add to AppRunningRecord. + */ +HWTEST_F(AmsAbilityRunningRecordTest, SetGetAbilityRecord_001, TestSize.Level0) +{ + APP_LOGD("SetGetAbilityRecord_001 start."); + + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + auto appRunningRecord = GetTestAppRunningRecord(); + sptr token = new MockAbilityToken(); + auto abilityRunningRecord = appRunningRecord->AddAbility(token, abilityInfo); + + ASSERT_TRUE(abilityRunningRecord != nullptr); + abilityRunningRecord->SetVisibility(1); + abilityRunningRecord->SetPerceptibility(1); + abilityRunningRecord->SetConnectionState(1); + + EXPECT_EQ(abilityRunningRecord, appRunningRecord->GetAbilityRunningRecordByToken(token)); + + auto testRecord = appRunningRecord->GetAbilityRunningRecordByToken(token); + EXPECT_EQ(1, testRecord->GetVisibility()); + EXPECT_EQ(1, testRecord->GetPerceptibility()); + EXPECT_EQ(1, testRecord->GetConnectionState()); + + APP_LOGD("SetGetAbilityRecord_001 end."); +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/appmgr/test/unittest/ams_app_death_recipient_test/BUILD.gn b/services/appmgr/test/unittest/ams_app_death_recipient_test/BUILD.gn new file mode 100644 index 000000000..4b34c94c1 --- /dev/null +++ b/services/appmgr/test/unittest/ams_app_death_recipient_test/BUILD.gn @@ -0,0 +1,77 @@ +# 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/appmgrservice" + +ohos_unittest("AppDeathRecipientTest") { + module_out_path = module_output_path + + sources = [ + "${services_path}/appmgr/src/ability_running_record.cpp", + "${services_path}/appmgr/src/app_death_recipient.cpp", + "${services_path}/appmgr/src/app_lifecycle_deal.cpp", + "${services_path}/appmgr/src/app_mgr_service_event_handler.cpp", + "${services_path}/appmgr/src/app_mgr_service_inner.cpp", + "${services_path}/appmgr/src/app_process_manager.cpp", + "${services_path}/appmgr/src/app_running_manager.cpp", + "${services_path}/appmgr/src/app_running_record.cpp", + "${services_path}/appmgr/src/app_spawn_client.cpp", + "${services_path}/appmgr/src/app_spawn_msg_wrapper.cpp", + "${services_path}/appmgr/src/app_spawn_socket.cpp", + "${services_path}/appmgr/src/cgroup_manager.cpp", + "${services_path}/appmgr/src/lmk_util.cpp", + "${services_path}/appmgr/src/lmkd_client.cpp", + "${services_path}/appmgr/src/process_optimizer.cpp", + "${services_path}/appmgr/src/process_optimizer_uba.cpp", + "${services_path}/appmgr/src/remote_client_manager.cpp", + "${services_path}/appmgr/test/mock/src/mock_bundle_manager.cpp", + ] + + sources += [ "ams_app_death_recipient_test.cpp" ] + + configs = [ + "${services_path}/appmgr/test:appmgr_test_config", + "${libs_path}/libeventhandler:libeventhandler_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${libs_path}/libeventhandler:libeventhandler_target", + "${services_path}/appmgr/test:appmgr_test_source", + "//base/startup/appspawn_standard:appspawn_socket_client", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler:libeventhandler", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/googletest:gtest_main", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":AppDeathRecipientTest" ] +} diff --git a/services/appmgr/test/unittest/ams_app_death_recipient_test/ams_app_death_recipient_test.cpp b/services/appmgr/test/unittest/ams_app_death_recipient_test/ams_app_death_recipient_test.cpp new file mode 100644 index 000000000..3e5165ba4 --- /dev/null +++ b/services/appmgr/test/unittest/ams_app_death_recipient_test/ams_app_death_recipient_test.cpp @@ -0,0 +1,205 @@ +/* + * 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. + */ + +#define private public +#include "app_death_recipient.h" +#include "app_mgr_service_inner.h" +#undef private +#include +#include "app_log_wrapper.h" +#include "app_mgr_service_inner.h" +#include "mock_ability_token.h" +#include "mock_app_scheduler.h" +#include "mock_app_spawn_client.h" +#include "iremote_object.h" +#include "mock_bundle_manager.h" + +using namespace testing::ext; +using testing::_; +using testing::Return; +using testing::SetArgReferee; + +namespace OHOS { +namespace AppExecFwk { + +class AppDeathRecipientTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + +public: + const std::shared_ptr GetAbilityInfoByIndex(const int32_t index) const; + const std::shared_ptr GetApplicationByIndex(const int32_t index) const; + const std::shared_ptr GetAppRunningRecordByIndex(const int32_t index) const; + sptr GetApp(int32_t pid, int size); + +public: + std::shared_ptr handler_; + std::shared_ptr appMgrServiceInner_; + sptr appDeathRecipientObject_; + OHOS::sptr mockToken_; + OHOS::sptr mockBundleMgr; +}; + +static void WaitUntilTaskFinished(std::shared_ptr handler) +{ + if (!handler) { + return; + } + + const uint32_t MAX_RETRY_COUNT = 1000; + const uint32_t SLEEP_TIME = 1000; + uint32_t count = 0; + std::atomic taskCalled(false); + auto f = [&taskCalled]() { taskCalled.store(true); }; + if (handler->PostTask(f)) { + while (!taskCalled.load()) { + ++count; + // if delay more than 1 second, break + if (count >= MAX_RETRY_COUNT) { + break; + } + + usleep(SLEEP_TIME); + } + } +} + +void AppDeathRecipientTest::SetUpTestCase() +{} + +void AppDeathRecipientTest::TearDownTestCase() +{} + +void AppDeathRecipientTest::SetUp() +{ + + auto runner = EventRunner::Create("AppDeathRecipientTest"); + appMgrServiceInner_ = std::make_shared(); + + handler_ = std::make_shared(runner, appMgrServiceInner_); + + appDeathRecipientObject_ = new (std::nothrow) AppDeathRecipient(); + + mockBundleMgr = new (std::nothrow) BundleMgrService(); + appMgrServiceInner_->SetBundleManager(mockBundleMgr); +} + +void AppDeathRecipientTest::TearDown() +{} + +const std::shared_ptr AppDeathRecipientTest::GetAbilityInfoByIndex(const int32_t index) const +{ + std::shared_ptr abilityInfo = std::make_shared(); + abilityInfo->name = "AppDeathRecipientTest_ability" + std::to_string(index); + abilityInfo->applicationName = "AppDeathRecipientTest" + std::to_string(index); + return abilityInfo; +} + +const std::shared_ptr AppDeathRecipientTest::GetApplicationByIndex(const int32_t index) const +{ + std::shared_ptr appInfo = std::make_shared(); + appInfo->name = "AppDeathRecipientTest" + std::to_string(index); + appInfo->bundleName = "AppDeathRecipientTest" + std::to_string(index); + return appInfo; +} + +const std::shared_ptr AppDeathRecipientTest::GetAppRunningRecordByIndex(const int32_t index) const +{ + auto appInfo = GetApplicationByIndex(index); + auto appRecord = appMgrServiceInner_->GetAppRunningRecordByAppName(appInfo->name); + EXPECT_NE(nullptr, appRecord); + return appRecord; +} + +sptr AppDeathRecipientTest::GetApp(int32_t pid, int size) +{ + auto abilityInfo = GetAbilityInfoByIndex(pid); + auto appInfo = GetApplicationByIndex(pid); + sptr token = new MockAbilityToken(); + + std::shared_ptr mockClientPtr = std::make_shared(); + EXPECT_CALL(*mockClientPtr, StartProcess(_, _)).Times(1).WillOnce(DoAll(SetArgReferee<1>(pid), Return(ERR_OK))); + std::shared_ptr mockClientstr(mockClientPtr); + appMgrServiceInner_->SetAppSpawnClient(mockClientstr); + + appMgrServiceInner_->LoadAbility(token, nullptr, abilityInfo, appInfo); + + auto appRecord = GetAppRunningRecordByIndex(pid); + + EXPECT_EQ(size, static_cast(appMgrServiceInner_->GetRecentAppList().size())); + + sptr mockAppScheduler = new (std::nothrow) MockAppScheduler(); + sptr client = iface_cast(mockAppScheduler.GetRefPtr()); + appRecord->SetApplicationClient(client); + + return client->AsObject(); +} + +/* + * Feature: Ams + * Function: SetEventHandler ande SetAppMgrServiceInner. + * SubFunction: AppDeathRecipient + * FunctionPoints: initialization + * EnvConditions: have to an application + * CaseDescription: How to set parameters + */ + +HWTEST_F(AppDeathRecipientTest, AppDeathRecipient_001, TestSize.Level1) +{ + APP_LOGI("AppDeathRecipient_001 start"); + appDeathRecipientObject_->SetEventHandler(handler_); + EXPECT_TRUE(appDeathRecipientObject_->handler_.lock() != nullptr); + + appDeathRecipientObject_->SetAppMgrServiceInner(appMgrServiceInner_); + EXPECT_TRUE(appDeathRecipientObject_->appMgrServiceInner_.lock() != nullptr); + APP_LOGI("AppDeathRecipient_001 end"); +} + +/* + * Feature: Ams + * Function: OnRemoteDied + * SubFunction: AppDeathRecipient + * FunctionPoints: Applied death notification + * EnvConditions: have to an application + * CaseDescription: Call back the death notification of the notification application + */ +HWTEST_F(AppDeathRecipientTest, AppDeathRecipient_002, TestSize.Level1) +{ + pid_t pid1 = 1024; + pid_t pid2 = 1025; + + sptr appOne = GetApp(pid1, 1); + + sptr appTwo = GetApp(pid2, 2); + + appDeathRecipientObject_->SetEventHandler(handler_); + appDeathRecipientObject_->SetAppMgrServiceInner(appMgrServiceInner_); + appDeathRecipientObject_->OnRemoteDied(appOne); + + WaitUntilTaskFinished(handler_); + EXPECT_EQ(1, static_cast(appDeathRecipientObject_->appMgrServiceInner_.lock()->GetRecentAppList().size())); + + appDeathRecipientObject_->OnRemoteDied(appTwo); + + WaitUntilTaskFinished(handler_); + EXPECT_EQ(0, static_cast(appDeathRecipientObject_->appMgrServiceInner_.lock()->GetRecentAppList().size())); + APP_LOGI("AppDeathRecipient_002 start"); +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/appmgr/test/unittest/ams_app_life_cycle_test/BUILD.gn b/services/appmgr/test/unittest/ams_app_life_cycle_test/BUILD.gn new file mode 100644 index 000000000..2e5479828 --- /dev/null +++ b/services/appmgr/test/unittest/ams_app_life_cycle_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/appmgrservice" + +ohos_unittest("AmsAppLifeCycleTest") { + module_out_path = module_output_path + + include_dirs = [ + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include/", + "//foundation/distributedschedule/samgr/adapter/interfaces/innerkits/include/", + ] + + sources = [ + "${services_path}/appmgr/src/ability_running_record.cpp", + "${services_path}/appmgr/src/app_lifecycle_deal.cpp", + "${services_path}/appmgr/src/app_mgr_service_inner.cpp", + "${services_path}/appmgr/src/app_process_manager.cpp", + "${services_path}/appmgr/src/app_running_manager.cpp", + "${services_path}/appmgr/src/app_running_record.cpp", + "${services_path}/appmgr/src/app_spawn_client.cpp", + "${services_path}/appmgr/src/app_spawn_msg_wrapper.cpp", + "${services_path}/appmgr/src/app_spawn_socket.cpp", + "${services_path}/appmgr/src/cgroup_manager.cpp", + "${services_path}/appmgr/src/lmk_util.cpp", + "${services_path}/appmgr/src/lmkd_client.cpp", + "${services_path}/appmgr/src/process_optimizer.cpp", + "${services_path}/appmgr/src/process_optimizer_uba.cpp", + "${services_path}/appmgr/src/remote_client_manager.cpp", + "${services_path}/appmgr/test/mock/src/mock_bundle_manager.cpp", + ] + + sources += [ "ams_app_life_cycle_test.cpp" ] + + configs = [ "${libs_path}/libeventhandler:libeventhandler_config" ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${libs_path}/libeventhandler:libeventhandler_target", + "${services_path}/appmgr/test:appmgr_test_source", + "//base/startup/appspawn_standard:appspawn_socket_client", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler:libeventhandler", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":AmsAppLifeCycleTest" ] +} diff --git a/services/appmgr/test/unittest/ams_app_life_cycle_test/ams_app_life_cycle_test.cpp b/services/appmgr/test/unittest/ams_app_life_cycle_test/ams_app_life_cycle_test.cpp new file mode 100644 index 000000000..64d4dbab6 --- /dev/null +++ b/services/appmgr/test/unittest/ams_app_life_cycle_test/ams_app_life_cycle_test.cpp @@ -0,0 +1,2023 @@ +/* + * 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. + */ +#define private public +#include "app_mgr_service_inner.h" +#undef private + +#include +#include +#include "iremote_object.h" +#include "refbase.h" +#include "app_launch_data.h" +#include "mock_ability_token.h" +#include "mock_app_scheduler.h" +#include "mock_app_spawn_client.h" +#include "mock_app_spawn_socket.h" +#include "mock_iapp_state_callback.h" +#include "mock_bundle_manager.h" + +using namespace testing::ext; +using testing::_; +using testing::Return; +using testing::SetArgReferee; +namespace OHOS { +namespace AppExecFwk { +struct TestApplicationPreRecord { + TestApplicationPreRecord(const std::shared_ptr &firstAbilityRecord, + const std::shared_ptr &appRecord, const sptr &mockAppScheduler) + : firstAbilityRecord_(firstAbilityRecord), appRecord_(appRecord), mockAppScheduler_(mockAppScheduler) + {} + virtual ~TestApplicationPreRecord() + {} + + std::shared_ptr firstAbilityRecord_; + std::shared_ptr appRecord_; + sptr mockAppScheduler_ = nullptr; +}; +class AmsAppLifeCycleTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + +protected: + std::shared_ptr StartProcessAndLoadAbility(const sptr &token, + const sptr &preToken, const std::shared_ptr &abilityInfo, + const std::shared_ptr &appInfo, const pid_t newPid) const; + + std::shared_ptr LoadTestAbility(const sptr &token, + const sptr &preToken, const std::shared_ptr &abilityInfo, + const std::shared_ptr &appInfo); + + sptr GetMockToken() const; + std::shared_ptr GetAbilityInfoByIndex(const std::string &index) const; + std::shared_ptr GetApplication() const; + TestApplicationPreRecord PrepareLoadTestAbilityAndApp(const ApplicationState currentAppState) const; + TestApplicationPreRecord CreateTestApplicationRecord( + const AbilityState abilityState, const ApplicationState appState) const; + std::shared_ptr CreateTestApplicationAndSetState(const ApplicationState appState) const; + sptr AddApplicationClient(const std::shared_ptr &appRecord) const; + void TestUpdateAbilityStateWhenAbilityIsUnLoaded(const AbilityState changingState) const; + void TestUpdateAbilityStateWhenAbilityIsCreate( + const AbilityState changingState, const ApplicationState curAppState) const; + void TestUpdateAbilityStateToBackgroundWhenAbilityIsReady(const ApplicationState curAppState) const; + void TestUpdateAbilityStateToBackgroundWhenAbilityIsBackground(const ApplicationState curAppState); + void TestTerminateAbilityWhenAbilityIsNotBackground( + const AbilityState curAbilityState, const ApplicationState curAppState) const; + std::shared_ptr AddNewAbility( + const std::shared_ptr &appRecord, const std::string &index) const; + +protected: + std::unique_ptr serviceInner_; + sptr mock_token_ = nullptr; + sptr mockBundleMgr = nullptr; +}; + +void AmsAppLifeCycleTest::SetUpTestCase() +{} + +void AmsAppLifeCycleTest::TearDownTestCase() +{} + +void AmsAppLifeCycleTest::SetUp() +{ + serviceInner_.reset(new (std::nothrow) AppMgrServiceInner()); + mock_token_ = new (std::nothrow) MockAbilityToken(); + mockBundleMgr = new (std::nothrow) BundleMgrService(); + serviceInner_->SetBundleManager(mockBundleMgr); +} + +void AmsAppLifeCycleTest::TearDown() +{} + +std::shared_ptr AmsAppLifeCycleTest::StartProcessAndLoadAbility(const sptr &token, + const sptr &preToken, const std::shared_ptr &abilityInfo, + const std::shared_ptr &appInfo, const pid_t newPid) const +{ + std::shared_ptr mockClientPtr = std::make_shared(); + EXPECT_CALL(*mockClientPtr, StartProcess(_, _)).Times(1).WillOnce(DoAll(SetArgReferee<1>(newPid), Return(ERR_OK))); + + serviceInner_->SetAppSpawnClient(mockClientPtr); + + serviceInner_->LoadAbility(token, preToken, abilityInfo, appInfo); + std::shared_ptr record = serviceInner_->GetAppRunningRecordByAppName(appInfo->name); + EXPECT_EQ(record->GetPriorityObject()->GetPid(), newPid); + return record; +} + +sptr AmsAppLifeCycleTest::GetMockToken() const +{ + return mock_token_; +} + +std::shared_ptr AmsAppLifeCycleTest::GetAbilityInfoByIndex(const std::string &index) const +{ + auto abilityInfo = std::make_shared(); + abilityInfo->name = "test_ability" + index; + abilityInfo->applicationName = "test_app"; + abilityInfo->process = "test_app"; + return abilityInfo; +} + +std::shared_ptr AmsAppLifeCycleTest::GetApplication() const +{ + auto appInfo = std::make_shared(); + appInfo->name = "test_app"; + appInfo->bundleName = "test_app"; + return appInfo; +} + +// load the first ability and create his parent app, then set app a state +TestApplicationPreRecord AmsAppLifeCycleTest::PrepareLoadTestAbilityAndApp(const ApplicationState currentAppState) const +{ + const pid_t NEW_PID = 123; + auto abilityInfo = GetAbilityInfoByIndex("0"); + auto appInfo = GetApplication(); + sptr token = GetMockToken(); + auto appRecord = StartProcessAndLoadAbility(token, nullptr, abilityInfo, appInfo, NEW_PID); + EXPECT_NE(appRecord, nullptr); + auto abilityRecord = appRecord->GetAbilityRunningRecordByToken(token); + EXPECT_NE(abilityRecord, nullptr); + EXPECT_EQ(AbilityState::ABILITY_STATE_CREATE, abilityRecord->GetState()); + appRecord->SetState(currentAppState); + sptr mockAppScheduler = new (std::nothrow) MockAppScheduler(); + sptr client = iface_cast(mockAppScheduler.GetRefPtr()); + appRecord->SetApplicationClient(client); + TestApplicationPreRecord testAppPreRecord(abilityRecord, appRecord, mockAppScheduler); + return testAppPreRecord; +} + +// create one application that include one ability, and set state +TestApplicationPreRecord AmsAppLifeCycleTest::CreateTestApplicationRecord( + const AbilityState abilityState, const ApplicationState appState) const +{ + RecordQueryResult result; + auto abilityInfo = GetAbilityInfoByIndex("0"); + auto appInfo = GetApplication(); + sptr token = GetMockToken(); + + auto appRecord = serviceInner_->GetOrCreateAppRunningRecord(token, appInfo, abilityInfo, "test_app", 0, result); + EXPECT_NE(appRecord, nullptr); + auto abilityRecord = appRecord->GetAbilityRunningRecordByToken(GetMockToken()); + EXPECT_NE(abilityRecord, nullptr); + abilityRecord->SetState(abilityState); + appRecord->SetState(appState); + sptr mockAppScheduler = AddApplicationClient(appRecord); + + TestApplicationPreRecord testAppPreRecord(abilityRecord, appRecord, mockAppScheduler); + return testAppPreRecord; +} + +std::shared_ptr AmsAppLifeCycleTest::CreateTestApplicationAndSetState( + const ApplicationState appState) const +{ + RecordQueryResult result; + auto abilityInfo = GetAbilityInfoByIndex("0"); + auto appInfo = GetApplication(); + sptr token = GetMockToken(); + auto appRecord = + serviceInner_->GetOrCreateAppRunningRecord(token, appInfo, abilityInfo, "AmsAppLifeCycleTest", 0, result); + EXPECT_NE(appRecord, nullptr); + EXPECT_EQ(appRecord->GetRecordId(), result.appRecordId); + appRecord->SetState(appState); + return appRecord; +} + +sptr AmsAppLifeCycleTest::AddApplicationClient( + const std::shared_ptr &appRecord) const +{ + sptr mockAppScheduler = new MockAppScheduler(); + sptr client = iface_cast(mockAppScheduler.GetRefPtr()); + appRecord->SetApplicationClient(client); + return mockAppScheduler; +} + +void AmsAppLifeCycleTest::TestUpdateAbilityStateWhenAbilityIsUnLoaded(const AbilityState changingState) const +{ + sptr token = GetMockToken(); + serviceInner_->UpdateAbilityState(token, changingState); + auto appRecord = serviceInner_->GetAppRunningRecordByAbilityToken(token); + EXPECT_EQ(appRecord, nullptr); +} + +void AmsAppLifeCycleTest::TestUpdateAbilityStateWhenAbilityIsCreate( + const AbilityState changingState, const ApplicationState curAppState) const +{ + auto testAppPreRecord = CreateTestApplicationRecord(AbilityState::ABILITY_STATE_CREATE, curAppState); + auto abilityState = testAppPreRecord.firstAbilityRecord_->GetState(); + + serviceInner_->UpdateAbilityState(GetMockToken(), changingState); + EXPECT_EQ(abilityState, testAppPreRecord.firstAbilityRecord_->GetState()); + EXPECT_EQ(curAppState, testAppPreRecord.appRecord_->GetState()); +} + +void AmsAppLifeCycleTest::TestUpdateAbilityStateToBackgroundWhenAbilityIsReady(const ApplicationState curAppState) const +{ + auto testAppPreRecord = CreateTestApplicationRecord(AbilityState::ABILITY_STATE_READY, curAppState); + + serviceInner_->UpdateAbilityState(GetMockToken(), AbilityState::ABILITY_STATE_BACKGROUND); + EXPECT_EQ(AbilityState::ABILITY_STATE_READY, testAppPreRecord.firstAbilityRecord_->GetState()); + EXPECT_EQ(curAppState, testAppPreRecord.appRecord_->GetState()); +} + +void AmsAppLifeCycleTest::TestUpdateAbilityStateToBackgroundWhenAbilityIsBackground(const ApplicationState curAppState) +{ + auto testAppPreRecord = CreateTestApplicationRecord(AbilityState::ABILITY_STATE_BACKGROUND, curAppState); + + serviceInner_->UpdateAbilityState(GetMockToken(), AbilityState::ABILITY_STATE_BACKGROUND); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, testAppPreRecord.firstAbilityRecord_->GetState()); + EXPECT_EQ(curAppState, testAppPreRecord.appRecord_->GetState()); +} + +void AmsAppLifeCycleTest::TestTerminateAbilityWhenAbilityIsNotBackground( + const AbilityState curAbilityState, const ApplicationState curAppState) const +{ + auto testAppPreRecord = CreateTestApplicationRecord(curAbilityState, curAppState); + + serviceInner_->TerminateAbility(GetMockToken()); + EXPECT_EQ(curAbilityState, testAppPreRecord.firstAbilityRecord_->GetState()); + EXPECT_EQ(curAppState, testAppPreRecord.appRecord_->GetState()); +} + +std::shared_ptr AmsAppLifeCycleTest::AddNewAbility( + const std::shared_ptr &appRecord, const std::string &index) const +{ + auto newAbilityInfo = GetAbilityInfoByIndex(index); + sptr newToken = new (std::nothrow) MockAbilityToken(); + serviceInner_->LoadAbility(newToken, nullptr, newAbilityInfo, GetApplication()); + auto newAbilityRecord = appRecord->GetAbilityRunningRecordByToken(newToken); + EXPECT_NE(newAbilityRecord, nullptr); + return newAbilityRecord; +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Init + * FunctionPoints: Init + * CaseDescription: test application init process + */ +HWTEST_F(AmsAppLifeCycleTest, Init_001, TestSize.Level0) +{ + const pid_t NEW_PID = 123; + auto abilityInfo = GetAbilityInfoByIndex("0"); + auto appInfo = GetApplication(); + sptr token = GetMockToken(); + auto record = StartProcessAndLoadAbility(token, nullptr, abilityInfo, appInfo, NEW_PID); + + sptr mockAppScheduler = new MockAppScheduler(); + sptr client = iface_cast(mockAppScheduler.GetRefPtr()); + EXPECT_CALL(*mockAppScheduler, ScheduleLaunchApplication(_)).Times(1); + EXPECT_CALL(*mockAppScheduler, ScheduleLaunchAbility(_, _)).Times(1); + + serviceInner_->AttachApplication(NEW_PID, client); + EXPECT_NE(record->GetApplicationClient(), nullptr); + EXPECT_EQ(ApplicationState::APP_STATE_READY, record->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: LoadAbility + * CaseDescription: LoadAbility when ability is loaded. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_001, TestSize.Level0) +{ + const pid_t NEW_PID = 123; + auto abilityInfo = GetAbilityInfoByIndex("0"); + auto appInfo = GetApplication(); + sptr token = GetMockToken(); + auto appRecord = StartProcessAndLoadAbility(token, nullptr, abilityInfo, appInfo, NEW_PID); + EXPECT_NE(appRecord, nullptr); + auto abilityRecord = appRecord->GetAbilityRunningRecordByToken(token); + EXPECT_NE(abilityRecord, nullptr); + AbilityState abilityState = abilityRecord->GetState(); + ApplicationState appState = appRecord->GetState(); + + serviceInner_->LoadAbility(token, nullptr, abilityInfo, appInfo); + EXPECT_EQ(abilityState, abilityRecord->GetState()); + EXPECT_EQ(appState, appRecord->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: LoadAbility + * CaseDescription: LoadAbility when ability and application is not created. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_002, TestSize.Level0) +{ + const pid_t NEW_PID = 123; + auto abilityInfo = GetAbilityInfoByIndex("0"); + auto appInfo = GetApplication(); + sptr token = GetMockToken(); + auto appRecord = StartProcessAndLoadAbility(token, nullptr, abilityInfo, appInfo, NEW_PID); + EXPECT_NE(appRecord, nullptr); + auto abilityRecord = appRecord->GetAbilityRunningRecordByToken(token); + EXPECT_NE(abilityRecord, nullptr); + sptr mockAppScheduler = new MockAppScheduler(); + sptr client = iface_cast(mockAppScheduler.GetRefPtr()); + + EXPECT_CALL(*mockAppScheduler, ScheduleLaunchApplication(_)).Times(1); + EXPECT_CALL(*mockAppScheduler, ScheduleLaunchAbility(_, _)).Times(1); + + serviceInner_->AttachApplication(NEW_PID, client); + EXPECT_EQ(AbilityState::ABILITY_STATE_READY, abilityRecord->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_READY, appRecord->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: LoadAbility + * CaseDescription: Load ability when ability is not created but application is create. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_003, TestSize.Level0) +{ + TestApplicationPreRecord testAppRecord = PrepareLoadTestAbilityAndApp(ApplicationState::APP_STATE_CREATE); + + auto newAbilityRecord = AddNewAbility(testAppRecord.appRecord_, "1"); + EXPECT_EQ(AbilityState::ABILITY_STATE_CREATE, newAbilityRecord->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_CREATE, testAppRecord.appRecord_->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: LoadAbility + * CaseDescription: Load ability when ability is not created but application is ready. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_004, TestSize.Level0) +{ + TestApplicationPreRecord testAppRecord = PrepareLoadTestAbilityAndApp(ApplicationState::APP_STATE_READY); + + EXPECT_CALL(*(testAppRecord.mockAppScheduler_), ScheduleLaunchAbility(_, _)).Times(1); + auto newAbilityRecord = AddNewAbility(testAppRecord.appRecord_, "1"); + EXPECT_EQ(AbilityState::ABILITY_STATE_READY, newAbilityRecord->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_READY, testAppRecord.appRecord_->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: LoadAbility + * CaseDescription: Load ability when ability is not created but application is foreground. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_005, TestSize.Level0) +{ + TestApplicationPreRecord testAppRecord = PrepareLoadTestAbilityAndApp(ApplicationState::APP_STATE_FOREGROUND); + + EXPECT_CALL(*(testAppRecord.mockAppScheduler_), ScheduleLaunchAbility(_, _)).Times(1); + auto newAbilityRecord = AddNewAbility(testAppRecord.appRecord_, "1"); + EXPECT_EQ(AbilityState::ABILITY_STATE_READY, newAbilityRecord->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testAppRecord.appRecord_->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: LoadAbility + * CaseDescription: Load ability when ability is not created but application is background. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_006, TestSize.Level0) +{ + TestApplicationPreRecord testAppRecord = PrepareLoadTestAbilityAndApp(ApplicationState::APP_STATE_BACKGROUND); + EXPECT_CALL(*(testAppRecord.mockAppScheduler_), ScheduleLaunchAbility(_, _)).Times(1); + + auto newAbilityRecord = AddNewAbility(testAppRecord.appRecord_, "1"); + EXPECT_EQ(AbilityState::ABILITY_STATE_READY, newAbilityRecord->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_BACKGROUND, testAppRecord.appRecord_->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: LoadAbility + * CaseDescription: Load ability when ability is not created but application is suspended. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_007, TestSize.Level0) +{ + TestApplicationPreRecord testAppRecord = PrepareLoadTestAbilityAndApp(ApplicationState::APP_STATE_SUSPENDED); + + EXPECT_CALL(*(testAppRecord.mockAppScheduler_), ScheduleLaunchAbility(_, _)).Times(1); + auto newAbilityRecord = AddNewAbility(testAppRecord.appRecord_, "1"); + EXPECT_EQ(AbilityState::ABILITY_STATE_READY, newAbilityRecord->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_BACKGROUND, testAppRecord.appRecord_->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Update ability state to foreground + * CaseDescription: Update ability state to foreground when ability is not loaded. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_008, TestSize.Level0) +{ + TestUpdateAbilityStateWhenAbilityIsUnLoaded(AbilityState::ABILITY_STATE_FOREGROUND); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Update ability state to foreground + * CaseDescription: Update ability state to foreground when ability and app is create. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_009, TestSize.Level0) +{ + TestUpdateAbilityStateWhenAbilityIsCreate( + AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_CREATE); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Update ability state to foreground + * CaseDescription: Update ability state to foreground when ability is create but app is ready. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_010, TestSize.Level0) +{ + TestUpdateAbilityStateWhenAbilityIsCreate( + AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_READY); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Update ability state to foreground + * CaseDescription: Update ability state to foreground when ability is create but app is foreground. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_011, TestSize.Level0) +{ + TestUpdateAbilityStateWhenAbilityIsCreate( + AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Update ability state to foreground + * CaseDescription: Update ability state to foreground when ability is create but app is background. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_012, TestSize.Level0) +{ + TestUpdateAbilityStateWhenAbilityIsCreate( + AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_BACKGROUND); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Update ability state to foreground + * CaseDescription: Update ability state to foreground when ability and app is ready. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_013, TestSize.Level0) +{ + auto testAppPreRecord = + CreateTestApplicationRecord(AbilityState::ABILITY_STATE_READY, ApplicationState::APP_STATE_READY); + + EXPECT_CALL(*(testAppPreRecord.mockAppScheduler_), ScheduleForegroundApplication()).Times(1); + serviceInner_->UpdateAbilityState(GetMockToken(), AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->ApplicationForegrounded(testAppPreRecord.appRecord_->GetRecordId()); + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, testAppPreRecord.firstAbilityRecord_->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testAppPreRecord.appRecord_->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Update ability state to foreground + * CaseDescription: Update ability state to foreground when ability is ready and app is foreground. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_014, TestSize.Level0) +{ + auto testAppPreRecord = + CreateTestApplicationRecord(AbilityState::ABILITY_STATE_READY, ApplicationState::APP_STATE_FOREGROUND); + + serviceInner_->UpdateAbilityState(GetMockToken(), AbilityState::ABILITY_STATE_FOREGROUND); + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, testAppPreRecord.firstAbilityRecord_->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testAppPreRecord.appRecord_->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Update ability state to foreground + * CaseDescription: Update ability state to foreground when ability is ready and app is background. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_015, TestSize.Level0) +{ + auto testAppPreRecord = + CreateTestApplicationRecord(AbilityState::ABILITY_STATE_READY, ApplicationState::APP_STATE_BACKGROUND); + + EXPECT_CALL(*(testAppPreRecord.mockAppScheduler_), ScheduleForegroundApplication()).Times(1); + serviceInner_->UpdateAbilityState(GetMockToken(), AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->ApplicationForegrounded(testAppPreRecord.appRecord_->GetRecordId()); + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, testAppPreRecord.firstAbilityRecord_->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testAppPreRecord.appRecord_->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Update ability state to foreground + * CaseDescription: Update ability state to foreground when ability and app is foreground. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_016, TestSize.Level0) +{ + auto testAppPreRecord = + CreateTestApplicationRecord(AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + + serviceInner_->UpdateAbilityState(GetMockToken(), AbilityState::ABILITY_STATE_FOREGROUND); + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, testAppPreRecord.firstAbilityRecord_->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testAppPreRecord.appRecord_->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Update ability state to foreground + * CaseDescription: Update ability state to foreground when ability is background and app is foreground. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_017, TestSize.Level0) +{ + auto testAppPreRecord = + CreateTestApplicationRecord(AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_FOREGROUND); + + serviceInner_->UpdateAbilityState(GetMockToken(), AbilityState::ABILITY_STATE_FOREGROUND); + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, testAppPreRecord.firstAbilityRecord_->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testAppPreRecord.appRecord_->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Update ability state to foreground + * CaseDescription: Update ability state to foreground when ability and app is background. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_018, TestSize.Level0) +{ + auto testAppPreRecord = + CreateTestApplicationRecord(AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + + EXPECT_CALL(*(testAppPreRecord.mockAppScheduler_), ScheduleForegroundApplication()).Times(1); + serviceInner_->UpdateAbilityState(GetMockToken(), AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->ApplicationForegrounded(testAppPreRecord.appRecord_->GetRecordId()); + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, testAppPreRecord.firstAbilityRecord_->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testAppPreRecord.appRecord_->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Update ability state to foreground + * CaseDescription: Update ability state to foreground when ability is background and app is foreground. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_019, TestSize.Level0) +{ + auto testAppPreRecord = + CreateTestApplicationRecord(AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_SUSPENDED); + + EXPECT_CALL(*(testAppPreRecord.mockAppScheduler_), ScheduleForegroundApplication()).Times(1); + serviceInner_->UpdateAbilityState(GetMockToken(), AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->ApplicationForegrounded(testAppPreRecord.appRecord_->GetRecordId()); + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, testAppPreRecord.firstAbilityRecord_->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testAppPreRecord.appRecord_->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Update ability state to background + * CaseDescription: Update ability state to background when ability is not loaded. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_020, TestSize.Level0) +{ + TestUpdateAbilityStateWhenAbilityIsUnLoaded(AbilityState::ABILITY_STATE_BACKGROUND); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Update ability state to background + * CaseDescription: Update ability state to background when ability and app is create. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_021, TestSize.Level0) +{ + TestUpdateAbilityStateWhenAbilityIsCreate( + AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_CREATE); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Update ability state to background + * CaseDescription: Update ability state to background when ability is create but app is ready. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_022, TestSize.Level0) +{ + TestUpdateAbilityStateWhenAbilityIsCreate( + AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_READY); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Update ability state to background + * CaseDescription: Update ability state to background when ability is create but app is foreground. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_023, TestSize.Level0) +{ + TestUpdateAbilityStateWhenAbilityIsCreate( + AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_FOREGROUND); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Update ability state to background + * CaseDescription: Update ability state to background when ability is create but app is background. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_024, TestSize.Level0) +{ + TestUpdateAbilityStateWhenAbilityIsCreate( + AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Update ability state to background + * CaseDescription: Update ability state to background when ability and app is ready. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_025, TestSize.Level0) +{ + TestUpdateAbilityStateToBackgroundWhenAbilityIsReady(ApplicationState::APP_STATE_READY); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Update ability state to background + * CaseDescription: Update ability state to background when ability is ready and app is foreground. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_026, TestSize.Level0) +{ + TestUpdateAbilityStateToBackgroundWhenAbilityIsReady(ApplicationState::APP_STATE_FOREGROUND); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Update ability state to background + * CaseDescription: Update ability state to background when ability is ready and app is background. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_027, TestSize.Level0) +{ + TestUpdateAbilityStateToBackgroundWhenAbilityIsReady(ApplicationState::APP_STATE_BACKGROUND); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Update ability state to background + * CaseDescription: Update ability state to background when ability and app is foreground. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_028, TestSize.Level0) +{ + auto testAppPreRecord = + CreateTestApplicationRecord(AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + + EXPECT_CALL(*(testAppPreRecord.mockAppScheduler_), ScheduleBackgroundApplication()).Times(1); + serviceInner_->UpdateAbilityState(GetMockToken(), AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(testAppPreRecord.appRecord_->GetRecordId()); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, testAppPreRecord.firstAbilityRecord_->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_BACKGROUND, testAppPreRecord.appRecord_->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Update ability state to background + * CaseDescription: Update ability state to background when multiple ability. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_029, TestSize.Level0) +{ + auto testAppPreRecord = + CreateTestApplicationRecord(AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + auto newAbilityInfo = GetAbilityInfoByIndex("1"); + sptr newToken = new MockAbilityToken(); + auto newAbilityRecord = testAppPreRecord.appRecord_->AddAbility(newToken, newAbilityInfo); + newAbilityRecord->SetState(AbilityState::ABILITY_STATE_FOREGROUND); + EXPECT_NE(newAbilityRecord, nullptr); + + serviceInner_->UpdateAbilityState(GetMockToken(), AbilityState::ABILITY_STATE_BACKGROUND); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, testAppPreRecord.firstAbilityRecord_->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testAppPreRecord.appRecord_->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Update ability state to background + * CaseDescription: Update ability state to background when ability is background and app is foreground. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_030, TestSize.Level0) +{ + TestUpdateAbilityStateToBackgroundWhenAbilityIsBackground(ApplicationState::APP_STATE_FOREGROUND); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Update ability state to background + * CaseDescription: Update ability state to background when ability is background and app is background. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_031, TestSize.Level0) +{ + TestUpdateAbilityStateToBackgroundWhenAbilityIsBackground(ApplicationState::APP_STATE_BACKGROUND); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Update ability state to background + * CaseDescription: Update ability state to background when ability is background and app is suspended. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_032, TestSize.Level0) +{ + TestUpdateAbilityStateToBackgroundWhenAbilityIsBackground(ApplicationState::APP_STATE_SUSPENDED); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Terminate ability + * CaseDescription: Terminate ability when ability is unload. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_033, TestSize.Level0) +{ + serviceInner_->TerminateAbility(GetMockToken()); + auto appRecord = serviceInner_->GetAppRunningRecordByAbilityToken(GetMockToken()); + EXPECT_EQ(appRecord, nullptr); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Terminate ability + * CaseDescription: Terminate ability when ability and app is create. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_034, TestSize.Level0) +{ + TestTerminateAbilityWhenAbilityIsNotBackground( + AbilityState::ABILITY_STATE_CREATE, ApplicationState::APP_STATE_CREATE); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Terminate ability + * CaseDescription: Terminate ability when ability is create and app is ready. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_035, TestSize.Level0) +{ + TestTerminateAbilityWhenAbilityIsNotBackground( + AbilityState::ABILITY_STATE_CREATE, ApplicationState::APP_STATE_READY); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Terminate ability + * CaseDescription: Terminate ability when ability is create and app is foreground. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_036, TestSize.Level0) +{ + TestTerminateAbilityWhenAbilityIsNotBackground( + AbilityState::ABILITY_STATE_CREATE, ApplicationState::APP_STATE_FOREGROUND); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Terminate ability + * CaseDescription: Terminate ability when ability is create and app is background. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_037, TestSize.Level0) +{ + TestTerminateAbilityWhenAbilityIsNotBackground( + AbilityState::ABILITY_STATE_CREATE, ApplicationState::APP_STATE_BACKGROUND); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Terminate ability + * CaseDescription: Terminate ability when ability and app is ready. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_038, TestSize.Level0) +{ + TestTerminateAbilityWhenAbilityIsNotBackground( + AbilityState::ABILITY_STATE_READY, ApplicationState::APP_STATE_READY); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Terminate ability + * CaseDescription: Terminate ability when ability is ready and app is foreground. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_039, TestSize.Level0) +{ + TestTerminateAbilityWhenAbilityIsNotBackground( + AbilityState::ABILITY_STATE_READY, ApplicationState::APP_STATE_FOREGROUND); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Terminate ability + * CaseDescription: Terminate ability when ability is ready and app is background. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_040, TestSize.Level0) +{ + TestTerminateAbilityWhenAbilityIsNotBackground( + AbilityState::ABILITY_STATE_READY, ApplicationState::APP_STATE_BACKGROUND); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Terminate ability + * CaseDescription: Terminate ability when ability and app is foreground. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_041, TestSize.Level0) +{ + TestTerminateAbilityWhenAbilityIsNotBackground( + AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Terminate ability + * CaseDescription: Terminate ability when ability is background and app is foreground. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_042, TestSize.Level0) +{ + auto testAppRecord = + CreateTestApplicationRecord(AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + EXPECT_CALL(*(testAppRecord.mockAppScheduler_), ScheduleLaunchAbility(_, _)).Times(1); + auto newAbilityRecord = AddNewAbility(testAppRecord.appRecord_, "1"); + newAbilityRecord->SetState(AbilityState::ABILITY_STATE_BACKGROUND); + + EXPECT_CALL(*(testAppRecord.mockAppScheduler_), ScheduleCleanAbility(_)).Times(1); + serviceInner_->TerminateAbility(newAbilityRecord->GetToken()); + serviceInner_->AbilityTerminated(newAbilityRecord->GetToken()); + auto abilityRecord = testAppRecord.appRecord_->GetAbilityRunningRecordByToken(newAbilityRecord->GetToken()); + EXPECT_EQ(nullptr, abilityRecord); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testAppRecord.appRecord_->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Terminate ability + * CaseDescription: Terminate ability when ability and app is background. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_043, TestSize.Level0) +{ + auto testAppRecord = + CreateTestApplicationRecord(AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + + EXPECT_CALL(*(testAppRecord.mockAppScheduler_), ScheduleCleanAbility(_)).Times(1); + serviceInner_->TerminateAbility(GetMockToken()); + EXPECT_CALL(*(testAppRecord.mockAppScheduler_), ScheduleTerminateApplication()).Times(1); + serviceInner_->AbilityTerminated(GetMockToken()); + auto abilityRecord = testAppRecord.appRecord_->GetAbilityRunningRecordByToken(GetMockToken()); + EXPECT_EQ(nullptr, abilityRecord); + + serviceInner_->ApplicationTerminated(testAppRecord.appRecord_->GetRecordId()); + auto appRecord = serviceInner_->GetAppRunningRecordByAppName(testAppRecord.appRecord_->GetName()); + EXPECT_EQ(nullptr, appRecord); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Terminate ability + * CaseDescription: Terminate ability when multiple abilities and app is background. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_044, TestSize.Level0) +{ + auto testAppRecord = + CreateTestApplicationRecord(AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + + EXPECT_CALL(*(testAppRecord.mockAppScheduler_), ScheduleLaunchAbility(_, _)).Times(1); + auto newAbilityRecord = AddNewAbility(testAppRecord.appRecord_, "1"); + newAbilityRecord->SetState(AbilityState::ABILITY_STATE_BACKGROUND); + + EXPECT_CALL(*(testAppRecord.mockAppScheduler_), ScheduleCleanAbility(_)).Times(1); + serviceInner_->TerminateAbility(GetMockToken()); + serviceInner_->AbilityTerminated(GetMockToken()); + auto abilityRecord = testAppRecord.appRecord_->GetAbilityRunningRecordByToken(GetMockToken()); + EXPECT_EQ(nullptr, abilityRecord); + EXPECT_EQ(ApplicationState::APP_STATE_BACKGROUND, testAppRecord.appRecord_->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Terminate ability + * CaseDescription: Terminate ability when ability is background and app is suspended. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_045, TestSize.Level0) +{ + auto testAppRecord = + CreateTestApplicationRecord(AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_SUSPENDED); + + EXPECT_CALL(*(testAppRecord.mockAppScheduler_), ScheduleCleanAbility(_)).Times(1); + serviceInner_->TerminateAbility(GetMockToken()); + EXPECT_CALL(*(testAppRecord.mockAppScheduler_), ScheduleTerminateApplication()).Times(1); + serviceInner_->AbilityTerminated(GetMockToken()); + auto abilityRecord = testAppRecord.appRecord_->GetAbilityRunningRecordByToken(GetMockToken()); + EXPECT_EQ(nullptr, abilityRecord); + + serviceInner_->ApplicationTerminated(testAppRecord.appRecord_->GetRecordId()); + auto appRecord = serviceInner_->GetAppRunningRecordByAppName(testAppRecord.appRecord_->GetName()); + EXPECT_EQ(nullptr, appRecord); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Terminate ability + * CaseDescription: Terminate ability when multiple abilities is backgroung and app is suspended. + */ +HWTEST_F(AmsAppLifeCycleTest, Schedule_046, TestSize.Level0) +{ + auto testAppRecord = + CreateTestApplicationRecord(AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_SUSPENDED); + + EXPECT_CALL(*(testAppRecord.mockAppScheduler_), ScheduleLaunchAbility(_, _)).Times(1); + auto newAbilityRecord = AddNewAbility(testAppRecord.appRecord_, "1"); + newAbilityRecord->SetState(AbilityState::ABILITY_STATE_BACKGROUND); + testAppRecord.appRecord_->SetState(ApplicationState::APP_STATE_SUSPENDED); + + EXPECT_CALL(*(testAppRecord.mockAppScheduler_), ScheduleCleanAbility(_)).Times(1); + serviceInner_->TerminateAbility(GetMockToken()); + serviceInner_->AbilityTerminated(GetMockToken()); + auto abilityRecord = testAppRecord.appRecord_->GetAbilityRunningRecordByToken(GetMockToken()); + EXPECT_EQ(nullptr, abilityRecord); + EXPECT_EQ(ApplicationState::APP_STATE_BACKGROUND, testAppRecord.appRecord_->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: ApplicationForegrounded + * CaseDescription: Verify application can not change to foreground if application is create. + */ +HWTEST_F(AmsAppLifeCycleTest, Process_001, TestSize.Level0) +{ + auto appRecord = CreateTestApplicationAndSetState(ApplicationState::APP_STATE_CREATE); + int32_t appRecordId = appRecord->GetRecordId(); + EXPECT_TRUE(appRecordId > 0); + + serviceInner_->ApplicationForegrounded(appRecordId); + auto testAppRecord = serviceInner_->GetAppRunningRecordByAppRecordId(appRecordId); + EXPECT_NE(nullptr, testAppRecord); + EXPECT_EQ(ApplicationState::APP_STATE_CREATE, testAppRecord->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: ApplicationForegrounded + * CaseDescription: Verify application can change to foreground if application is ready. + */ +HWTEST_F(AmsAppLifeCycleTest, Process_002, TestSize.Level0) +{ + auto appRecord = CreateTestApplicationAndSetState(ApplicationState::APP_STATE_READY); + int32_t appRecordId = appRecord->GetRecordId(); + EXPECT_TRUE(appRecordId > 0); + + serviceInner_->ApplicationForegrounded(appRecordId); + auto testAppRecord = serviceInner_->GetAppRunningRecordByAppRecordId(appRecordId); + EXPECT_NE(nullptr, testAppRecord); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testAppRecord->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: ApplicationForegrounded + * CaseDescription: Verify application can not change to foreground if application is foreground. + */ +HWTEST_F(AmsAppLifeCycleTest, Process_003, TestSize.Level0) +{ + auto appRecord = CreateTestApplicationAndSetState(ApplicationState::APP_STATE_FOREGROUND); + int32_t appRecordId = appRecord->GetRecordId(); + EXPECT_TRUE(appRecordId > 0); + + serviceInner_->ApplicationForegrounded(appRecordId); + auto testAppRecord = serviceInner_->GetAppRunningRecordByAppRecordId(appRecordId); + EXPECT_NE(nullptr, testAppRecord); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testAppRecord->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: ApplicationForegrounded + * CaseDescription: Verify application can change to foreground if application is background. + */ +HWTEST_F(AmsAppLifeCycleTest, Process_004, TestSize.Level0) +{ + auto appRecord = CreateTestApplicationAndSetState(ApplicationState::APP_STATE_BACKGROUND); + int32_t appRecordId = appRecord->GetRecordId(); + EXPECT_TRUE(appRecordId > 0); + + serviceInner_->ApplicationForegrounded(appRecordId); + auto testAppRecord = serviceInner_->GetAppRunningRecordByAppRecordId(appRecordId); + EXPECT_NE(nullptr, testAppRecord); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testAppRecord->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: ApplicationForegrounded + * CaseDescription: Verify application can change to foregrounded if application is not exist. + */ +HWTEST_F(AmsAppLifeCycleTest, Process_005, TestSize.Level0) +{ + int32_t appRecordId = AppRecordId::Create(); + + serviceInner_->ApplicationForegrounded(appRecordId); + auto testAppRecord = serviceInner_->GetAppRunningRecordByAppRecordId(appRecordId); + EXPECT_EQ(nullptr, testAppRecord); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: ApplicationBackgrounded + * CaseDescription: Verify application can not change to background if application is create. + */ +HWTEST_F(AmsAppLifeCycleTest, Process_006, TestSize.Level0) +{ + auto appRecord = CreateTestApplicationAndSetState(ApplicationState::APP_STATE_CREATE); + int32_t appRecordId = appRecord->GetRecordId(); + EXPECT_TRUE(appRecordId > 0); + + serviceInner_->ApplicationBackgrounded(appRecordId); + auto testAppRecord = serviceInner_->GetAppRunningRecordByAppRecordId(appRecordId); + EXPECT_NE(nullptr, testAppRecord); + EXPECT_EQ(ApplicationState::APP_STATE_CREATE, testAppRecord->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: ApplicationBackgrounded + * CaseDescription: Verify application can change to background if application is foreground. + */ +HWTEST_F(AmsAppLifeCycleTest, Process_007, TestSize.Level0) +{ + auto appRecord = CreateTestApplicationAndSetState(ApplicationState::APP_STATE_FOREGROUND); + int32_t appRecordId = appRecord->GetRecordId(); + EXPECT_TRUE(appRecordId > 0); + + serviceInner_->ApplicationBackgrounded(appRecordId); + auto testAppRecord = serviceInner_->GetAppRunningRecordByAppRecordId(appRecordId); + EXPECT_NE(nullptr, testAppRecord); + EXPECT_EQ(ApplicationState::APP_STATE_BACKGROUND, testAppRecord->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: ApplicationBackgrounded + * CaseDescription: Verify application can not change to background if application is ready. + */ +HWTEST_F(AmsAppLifeCycleTest, Process_008, TestSize.Level0) +{ + auto appRecord = CreateTestApplicationAndSetState(ApplicationState::APP_STATE_READY); + int32_t appRecordId = appRecord->GetRecordId(); + EXPECT_TRUE(appRecordId > 0); + + serviceInner_->ApplicationBackgrounded(appRecord->GetRecordId()); + auto testAppRecord = serviceInner_->GetAppRunningRecordByAppRecordId(appRecord->GetRecordId()); + EXPECT_NE(nullptr, testAppRecord); + EXPECT_EQ(ApplicationState::APP_STATE_READY, testAppRecord->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: ApplicationBackgrounded + * CaseDescription: Verify application can not change to background if application is not exist. + */ +HWTEST_F(AmsAppLifeCycleTest, Process_009, TestSize.Level0) +{ + int32_t appRecordId = AppRecordId::Create(); + + serviceInner_->ApplicationBackgrounded(appRecordId); + auto testAppRecord = serviceInner_->GetAppRunningRecordByAppRecordId(appRecordId); + EXPECT_EQ(nullptr, testAppRecord); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: ApplicationTerminated + * CaseDescription: Verify application can change to terminate if application is background. + */ +HWTEST_F(AmsAppLifeCycleTest, Process_010, TestSize.Level0) +{ + auto testAppRecord = PrepareLoadTestAbilityAndApp(ApplicationState::APP_STATE_BACKGROUND); + EXPECT_CALL(*(testAppRecord.mockAppScheduler_), ScheduleTerminateApplication()).Times(1); + serviceInner_->AbilityTerminated(GetMockToken()); + auto abilityRecord = testAppRecord.appRecord_->GetAbilityRunningRecordByToken(GetMockToken()); + EXPECT_EQ(nullptr, abilityRecord); + + serviceInner_->ApplicationTerminated(testAppRecord.appRecord_->GetRecordId()); + auto appRecord = serviceInner_->GetAppRunningRecordByAppRecordId(testAppRecord.appRecord_->GetRecordId()); + EXPECT_EQ(nullptr, appRecord); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: ApplicationTerminated + * CaseDescription: Verify application can not change to terminate if application is foreground. + */ +HWTEST_F(AmsAppLifeCycleTest, Process_011, TestSize.Level0) +{ + auto appRecord = CreateTestApplicationAndSetState(ApplicationState::APP_STATE_FOREGROUND); + int32_t appRecordId = appRecord->GetRecordId(); + EXPECT_TRUE(appRecordId > 0); + + serviceInner_->ApplicationTerminated(appRecordId); + auto testAppRecord = serviceInner_->GetAppRunningRecordByAppRecordId(appRecordId); + EXPECT_NE(nullptr, testAppRecord); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testAppRecord->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: ApplicationTerminated + * CaseDescription: Verify application can not change to foregrounded if application is not exist. + */ +HWTEST_F(AmsAppLifeCycleTest, Process_012, TestSize.Level0) +{ + int32_t appRecordId = AppRecordId::Create(); + serviceInner_->ApplicationTerminated(appRecordId); + auto testAppRecord = serviceInner_->GetAppRunningRecordByAppRecordId(appRecordId); + EXPECT_EQ(nullptr, testAppRecord); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: AppMgrService stop + * CaseDescription: Verify if AppMgrService stop successfully. + */ +HWTEST_F(AmsAppLifeCycleTest, Stop_001, TestSize.Level0) +{ + const pid_t NEW_PID = 123; + auto abilityInfo = GetAbilityInfoByIndex("0"); + auto appInfo = GetApplication(); + sptr token = GetMockToken(); + auto appRecord = StartProcessAndLoadAbility(token, nullptr, abilityInfo, appInfo, NEW_PID); + EXPECT_NE(appRecord, nullptr); + auto abilityRecord = appRecord->GetAbilityRunningRecordByToken(token); + EXPECT_NE(abilityRecord, nullptr); + AbilityState abilityState = abilityRecord->GetState(); + ApplicationState appState = appRecord->GetState(); + serviceInner_->LoadAbility(token, nullptr, abilityInfo, appInfo); + EXPECT_EQ(abilityState, abilityRecord->GetState()); + EXPECT_EQ(appState, appRecord->GetState()); + + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, serviceInner_->QueryAppSpawnConnectionState()); + int32_t size = serviceInner_->GetRecordMap().size(); + EXPECT_EQ(1, size); + serviceInner_->OnStop(); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, serviceInner_->QueryAppSpawnConnectionState()); + size = serviceInner_->GetRecordMap().size(); + EXPECT_EQ(0, size); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: AppMgrService stop + * CaseDescription: Verify if AppMgrService stop successfully. + */ +HWTEST_F(AmsAppLifeCycleTest, Stop_002, TestSize.Level0) +{ + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr socketMock = std::make_shared(); + appSpawnClient->SetSocket(socketMock); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appSpawnClient->QueryConnectionState()); + EXPECT_CALL(*socketMock, OpenAppSpawnConnection()).WillOnce(Return(ERR_OK)); + serviceInner_->SetAppSpawnClient(appSpawnClient); + serviceInner_->OpenAppSpawnConnection(); + EXPECT_EQ(SpawnConnectionState::STATE_CONNECTED, serviceInner_->QueryAppSpawnConnectionState()); + int32_t size = serviceInner_->GetRecordMap().size(); + EXPECT_EQ(0, size); + + EXPECT_CALL(*socketMock, CloseAppSpawnConnection()).Times(1); + serviceInner_->OnStop(); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, serviceInner_->QueryAppSpawnConnectionState()); + size = serviceInner_->GetRecordMap().size(); + EXPECT_EQ(0, size); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: AppMgrService stop + * CaseDescription: Verify if AppMgrService stop successfully. + */ +HWTEST_F(AmsAppLifeCycleTest, Stop_003, TestSize.Level0) +{ + const pid_t NEW_PID = 123; + auto abilityInfo = GetAbilityInfoByIndex("0"); + auto appInfo = GetApplication(); + sptr token = GetMockToken(); + auto appRecord = StartProcessAndLoadAbility(token, nullptr, abilityInfo, appInfo, NEW_PID); + EXPECT_NE(appRecord, nullptr); + auto abilityRecord = appRecord->GetAbilityRunningRecordByToken(token); + EXPECT_NE(abilityRecord, nullptr); + AbilityState abilityState = abilityRecord->GetState(); + ApplicationState appState = appRecord->GetState(); + serviceInner_->LoadAbility(token, nullptr, abilityInfo, appInfo); + EXPECT_EQ(abilityState, abilityRecord->GetState()); + EXPECT_EQ(appState, appRecord->GetState()); + + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr socketMock = std::make_shared(); + appSpawnClient->SetSocket(socketMock); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appSpawnClient->QueryConnectionState()); + EXPECT_CALL(*socketMock, OpenAppSpawnConnection()).WillOnce(Return(ERR_OK)); + serviceInner_->SetAppSpawnClient(appSpawnClient); + serviceInner_->OpenAppSpawnConnection(); + EXPECT_EQ(SpawnConnectionState::STATE_CONNECTED, serviceInner_->QueryAppSpawnConnectionState()); + int32_t size = serviceInner_->GetRecordMap().size(); + EXPECT_EQ(1, size); + + EXPECT_CALL(*socketMock, CloseAppSpawnConnection()).Times(1); + serviceInner_->OnStop(); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, serviceInner_->QueryAppSpawnConnectionState()); + size = serviceInner_->GetRecordMap().size(); + EXPECT_EQ(0, size); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Kill application + * CaseDescription: Verify if AppMgrService Kill by appname fail. + */ +HWTEST_F(AmsAppLifeCycleTest, KillApplication_001, TestSize.Level0) +{ + int result = serviceInner_->KillApplication("hwei.ss.bb"); + EXPECT_EQ(ERR_OK, result); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Kill application + * CaseDescription: Verify if AppMgrService Kill by appname successfully. + */ +HWTEST_F(AmsAppLifeCycleTest, KillApplication_002, TestSize.Level0) +{ + const pid_t NEW_PID = 123; + auto abilityInfo = GetAbilityInfoByIndex("0"); + auto appInfo = GetApplication(); + sptr token = GetMockToken(); + + std::shared_ptr mockClientPtr = std::make_shared(); + EXPECT_CALL(*mockClientPtr, StartProcess(_, _)).Times(1).WillOnce(DoAll(SetArgReferee<1>(NEW_PID), Return(ERR_OK))); + + serviceInner_->SetAppSpawnClient(mockClientPtr); + + serviceInner_->LoadAbility(token, nullptr, abilityInfo, appInfo); + std::shared_ptr appRecord = serviceInner_->GetAppRunningRecordByAppName(appInfo->name); + EXPECT_EQ(appRecord->GetPriorityObject()->GetPid(), NEW_PID); + + pid_t pid = fork(); + if (pid > 0) { + appRecord->GetPriorityObject()->SetPid(pid); + } + + sptr mockAppScheduler = new MockAppScheduler(); + sptr client = iface_cast(mockAppScheduler.GetRefPtr()); + appRecord->SetApplicationClient(client); + EXPECT_CALL(*mockAppScheduler, ScheduleProcessSecurityExit()).Times(1); + + int ret = serviceInner_->KillApplication(abilityInfo->applicationName); + EXPECT_EQ(ERR_OK, ret); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Kill application + * CaseDescription: Verify if AppMgrService Kill by pid successfully. + */ +HWTEST_F(AmsAppLifeCycleTest, KillProcessByPid001, TestSize.Level0) +{ + pid_t pid = fork(); + + if (pid > 0) { + int32_t ret = serviceInner_->KillProcessByPid(pid); + EXPECT_EQ(ERR_OK, ret); + } + + if (pid == 0) { + int32_t ret = serviceInner_->KillProcessByPid(pid); + EXPECT_EQ(-1, ret); + } +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Kill application + * CaseDescription: Verify if AppMgrService Kill by pid fail. + */ +HWTEST_F(AmsAppLifeCycleTest, KillProcessByPid002, TestSize.Level0) +{ + int32_t ret = serviceInner_->KillProcessByPid(-1); + EXPECT_EQ(-1, ret); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Register App State Callback + * CaseDescription: Verify if AppMgrService Register Callback. + */ +HWTEST_F(AmsAppLifeCycleTest, Callback001, TestSize.Level0) +{ + sptr mockCallback(new MockAppStateCallback()); + sptr callback = iface_cast(mockCallback); + serviceInner_->RegisterAppStateCallback(callback); + + EXPECT_CALL(*mockCallback, OnAppStateChanged(_)).Times(2); + + const pid_t NEW_PID = 123; + auto abilityInfo = GetAbilityInfoByIndex("0"); + auto appInfo = GetApplication(); + sptr token = GetMockToken(); + auto appRecord = StartProcessAndLoadAbility(token, nullptr, abilityInfo, appInfo, NEW_PID); + EXPECT_NE(appRecord, nullptr); + serviceInner_->OnAppStateChanged(appRecord, ApplicationState::APP_STATE_READY); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Register App State Callback + * CaseDescription: Verify if AppMgrService Register Callback. + */ +HWTEST_F(AmsAppLifeCycleTest, Callback002, TestSize.Level0) +{ + sptr mockCallback(new MockAppStateCallback()); + sptr callback = iface_cast(mockCallback); + serviceInner_->RegisterAppStateCallback(callback); + + EXPECT_CALL(*mockCallback, OnAppStateChanged(_)).Times(0); + + serviceInner_->OnAppStateChanged(nullptr, ApplicationState::APP_STATE_READY); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Register Ability State Callback + * CaseDescription: Verify if AppMgrService Register Callback. + */ +HWTEST_F(AmsAppLifeCycleTest, Callback003, TestSize.Level0) +{ + sptr mockCallback(new MockAppStateCallback()); + sptr callback = iface_cast(mockCallback); + + const pid_t NEW_PID = 123; + auto abilityInfo = GetAbilityInfoByIndex("0"); + auto appInfo = GetApplication(); + sptr token = GetMockToken(); + auto appRecord = StartProcessAndLoadAbility(token, nullptr, abilityInfo, appInfo, NEW_PID); + EXPECT_NE(appRecord, nullptr); + auto ability = appRecord->GetAbilityRunningRecordByToken(token); + EXPECT_NE(ability, nullptr); + + serviceInner_->RegisterAppStateCallback(callback); + EXPECT_CALL(*mockCallback, OnAbilityRequestDone(_, _)).Times(1); + serviceInner_->OnAbilityStateChanged(ability, AbilityState::ABILITY_STATE_READY); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Register Ability State Callback + * CaseDescription: Verify if AppMgrService Register Callback. + */ +HWTEST_F(AmsAppLifeCycleTest, Callback004, TestSize.Level0) +{ + sptr mockCallback(new MockAppStateCallback()); + sptr callback = iface_cast(mockCallback); + serviceInner_->RegisterAppStateCallback(callback); + EXPECT_CALL(*mockCallback, OnAbilityRequestDone(_, _)).Times(0); + serviceInner_->OnAbilityStateChanged(nullptr, AbilityState::ABILITY_STATE_READY); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Register Ability State Changed + * CaseDescription: Verify if AppMgrService Ability State Changed Callback. + */ +HWTEST_F(AmsAppLifeCycleTest, AbilityStateChanged001, TestSize.Level0) +{ + sptr mockCallback(new MockAppStateCallback()); + sptr callback = iface_cast(mockCallback); + const pid_t NEW_PID = 123; + auto abilityInfo = GetAbilityInfoByIndex("0"); + auto appInfo = GetApplication(); + sptr token = GetMockToken(); + auto appRecord = StartProcessAndLoadAbility(token, nullptr, abilityInfo, appInfo, NEW_PID); + EXPECT_NE(appRecord, nullptr); + auto ability = appRecord->GetAbilityRunningRecordByToken(token); + EXPECT_NE(ability, nullptr); + serviceInner_->RegisterAppStateCallback(callback); + EXPECT_CALL(*mockCallback, OnAbilityRequestDone(_, _)).Times(1); + serviceInner_->OnAbilityStateChanged(ability, AbilityState::ABILITY_STATE_BEGIN); + EXPECT_CALL(*mockCallback, OnAbilityRequestDone(_, _)).Times(1); + serviceInner_->OnAbilityStateChanged(ability, AbilityState::ABILITY_STATE_CREATE); + EXPECT_CALL(*mockCallback, OnAbilityRequestDone(_, _)).Times(1); + serviceInner_->OnAbilityStateChanged(ability, AbilityState::ABILITY_STATE_READY); + EXPECT_CALL(*mockCallback, OnAbilityRequestDone(_, _)).Times(1); + serviceInner_->OnAbilityStateChanged(ability, AbilityState::ABILITY_STATE_FOREGROUND); + EXPECT_CALL(*mockCallback, OnAbilityRequestDone(_, _)).Times(1); + serviceInner_->OnAbilityStateChanged(ability, AbilityState::ABILITY_STATE_BACKGROUND); + EXPECT_CALL(*mockCallback, OnAbilityRequestDone(_, _)).Times(1); + serviceInner_->OnAbilityStateChanged(ability, AbilityState::ABILITY_STATE_TERMINATED); + EXPECT_CALL(*mockCallback, OnAbilityRequestDone(_, _)).Times(1); + serviceInner_->OnAbilityStateChanged(ability, AbilityState::ABILITY_STATE_END); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: Schedule + * FunctionPoints: Register App State Changed + * CaseDescription: Verify if AppMgrService App State Changed Callback. + */ +HWTEST_F(AmsAppLifeCycleTest, AppStateChanged001, TestSize.Level0) +{ + sptr mockCallback(new MockAppStateCallback()); + sptr callback = iface_cast(mockCallback); + const pid_t NEW_PID = 123; + auto abilityInfo = GetAbilityInfoByIndex("0"); + auto appInfo = GetApplication(); + sptr token = GetMockToken(); + auto appRecord = StartProcessAndLoadAbility(token, nullptr, abilityInfo, appInfo, NEW_PID); + EXPECT_NE(appRecord, nullptr); + serviceInner_->RegisterAppStateCallback(callback); + EXPECT_CALL(*mockCallback, OnAppStateChanged(_)).Times(1); + serviceInner_->OnAppStateChanged(appRecord, ApplicationState::APP_STATE_BEGIN); + EXPECT_CALL(*mockCallback, OnAppStateChanged(_)).Times(1); + serviceInner_->OnAppStateChanged(appRecord, ApplicationState::APP_STATE_CREATE); + EXPECT_CALL(*mockCallback, OnAppStateChanged(_)).Times(1); + serviceInner_->OnAppStateChanged(appRecord, ApplicationState::APP_STATE_READY); + EXPECT_CALL(*mockCallback, OnAppStateChanged(_)).Times(1); + serviceInner_->OnAppStateChanged(appRecord, ApplicationState::APP_STATE_FOREGROUND); + EXPECT_CALL(*mockCallback, OnAppStateChanged(_)).Times(1); + serviceInner_->OnAppStateChanged(appRecord, ApplicationState::APP_STATE_BACKGROUND); + EXPECT_CALL(*mockCallback, OnAppStateChanged(_)).Times(1); + serviceInner_->OnAppStateChanged(appRecord, ApplicationState::APP_STATE_SUSPENDED); + EXPECT_CALL(*mockCallback, OnAppStateChanged(_)).Times(1); + serviceInner_->OnAppStateChanged(appRecord, ApplicationState::APP_STATE_TERMINATED); + EXPECT_CALL(*mockCallback, OnAppStateChanged(_)).Times(1); + serviceInner_->OnAppStateChanged(appRecord, ApplicationState::APP_STATE_END); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: UnsuspendApplication + * FunctionPoints: UnsuspendApplication + * CaseDescription: test application state is APP_STATE_BACKGROUND + */ +HWTEST_F(AmsAppLifeCycleTest, Unsuspend_001, TestSize.Level0) +{ + TestApplicationPreRecord testAppRecord = PrepareLoadTestAbilityAndApp(ApplicationState::APP_STATE_FOREGROUND); + + EXPECT_CALL(*(testAppRecord.mockAppScheduler_), ScheduleLaunchAbility(_, _)).Times(1); + auto newAbilityRecord = AddNewAbility(testAppRecord.appRecord_, "1"); + EXPECT_EQ(AbilityState::ABILITY_STATE_READY, newAbilityRecord->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testAppRecord.appRecord_->GetState()); + testAppRecord.appRecord_->SetState(ApplicationState::APP_STATE_BACKGROUND); + EXPECT_EQ(ApplicationState::APP_STATE_BACKGROUND, testAppRecord.appRecord_->GetState()); + testAppRecord.appRecord_->SetState(ApplicationState::APP_STATE_SUSPENDED); + EXPECT_EQ(ApplicationState::APP_STATE_SUSPENDED, testAppRecord.appRecord_->GetState()); + serviceInner_->UnsuspendApplication(testAppRecord.appRecord_); + EXPECT_EQ(ApplicationState::APP_STATE_BACKGROUND, testAppRecord.appRecord_->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: UnsuspendApplication + * FunctionPoints: UnsuspendApplication + * CaseDescription: test application state is APP_STATE_SUSPENDED(apprecord is nullptr) + */ +HWTEST_F(AmsAppLifeCycleTest, Unsuspend_002, TestSize.Level0) +{ + TestApplicationPreRecord testAppRecord = PrepareLoadTestAbilityAndApp(ApplicationState::APP_STATE_FOREGROUND); + + EXPECT_CALL(*(testAppRecord.mockAppScheduler_), ScheduleLaunchAbility(_, _)).Times(1); + auto newAbilityRecord = AddNewAbility(testAppRecord.appRecord_, "1"); + EXPECT_EQ(AbilityState::ABILITY_STATE_READY, newAbilityRecord->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testAppRecord.appRecord_->GetState()); + testAppRecord.appRecord_->SetState(ApplicationState::APP_STATE_BACKGROUND); + EXPECT_EQ(ApplicationState::APP_STATE_BACKGROUND, testAppRecord.appRecord_->GetState()); + testAppRecord.appRecord_->SetState(ApplicationState::APP_STATE_SUSPENDED); + EXPECT_EQ(ApplicationState::APP_STATE_SUSPENDED, testAppRecord.appRecord_->GetState()); + serviceInner_->UnsuspendApplication(nullptr); + EXPECT_EQ(ApplicationState::APP_STATE_SUSPENDED, testAppRecord.appRecord_->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: suspendApplication + * FunctionPoints: suspendApplication + * CaseDescription: test application state is APP_STATE_SUSPENDED + */ +HWTEST_F(AmsAppLifeCycleTest, Suspend_001, TestSize.Level0) +{ + TestApplicationPreRecord testAppRecord = PrepareLoadTestAbilityAndApp(ApplicationState::APP_STATE_FOREGROUND); + + EXPECT_CALL(*(testAppRecord.mockAppScheduler_), ScheduleLaunchAbility(_, _)).Times(1); + auto newAbilityRecord = AddNewAbility(testAppRecord.appRecord_, "1"); + EXPECT_EQ(AbilityState::ABILITY_STATE_READY, newAbilityRecord->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testAppRecord.appRecord_->GetState()); + testAppRecord.appRecord_->SetState(ApplicationState::APP_STATE_BACKGROUND); + EXPECT_EQ(ApplicationState::APP_STATE_BACKGROUND, testAppRecord.appRecord_->GetState()); + testAppRecord.appRecord_->SetState(ApplicationState::APP_STATE_SUSPENDED); + EXPECT_EQ(ApplicationState::APP_STATE_SUSPENDED, testAppRecord.appRecord_->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: UnsuspendApplication + * FunctionPoints: UnsuspendApplication + * CaseDescription: test application state is APP_STATE_BACKGROUND(apprecord is nullptr) + */ +HWTEST_F(AmsAppLifeCycleTest, Suspend_002, TestSize.Level0) +{ + TestApplicationPreRecord testAppRecord = PrepareLoadTestAbilityAndApp(ApplicationState::APP_STATE_FOREGROUND); + + EXPECT_CALL(*(testAppRecord.mockAppScheduler_), ScheduleLaunchAbility(_, _)).Times(1); + auto newAbilityRecord = AddNewAbility(testAppRecord.appRecord_, "1"); + EXPECT_EQ(AbilityState::ABILITY_STATE_READY, newAbilityRecord->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testAppRecord.appRecord_->GetState()); + testAppRecord.appRecord_->SetState(ApplicationState::APP_STATE_BACKGROUND); + EXPECT_EQ(ApplicationState::APP_STATE_BACKGROUND, testAppRecord.appRecord_->GetState()); + serviceInner_->UnsuspendApplication(nullptr); + EXPECT_EQ(ApplicationState::APP_STATE_BACKGROUND, testAppRecord.appRecord_->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: UnsuspendApplication + * FunctionPoints: UnsuspendApplication + * CaseDescription: test application state is APP_STATE_BACKGROUND(apprecord is nullptr) + */ +HWTEST_F(AmsAppLifeCycleTest, AbilityBehaviorAnalysis_001, TestSize.Level0) +{ + const pid_t NEW_PID = 1234; + auto abilityInfo = GetAbilityInfoByIndex("110"); + auto appInfo = GetApplication(); + sptr token = GetMockToken(); + auto appRecord = StartProcessAndLoadAbility(token, nullptr, abilityInfo, appInfo, NEW_PID); + EXPECT_TRUE(appRecord != nullptr); + + auto abilityRecord = appRecord->GetAbilityRunningRecordByToken(token); + EXPECT_TRUE(abilityRecord != nullptr); + EXPECT_EQ(0, abilityRecord->GetVisibility()); + EXPECT_EQ(0, abilityRecord->GetPerceptibility()); + EXPECT_EQ(0, abilityRecord->GetConnectionState()); + + EXPECT_TRUE(serviceInner_); + serviceInner_->AbilityBehaviorAnalysis(token, nullptr, 1, 1, 1); + + auto abilityRecordAfter = appRecord->GetAbilityRunningRecordByToken(token); + EXPECT_TRUE(abilityRecordAfter != nullptr); + EXPECT_EQ(1, abilityRecordAfter->GetVisibility()); + EXPECT_EQ(1, abilityRecordAfter->GetPerceptibility()); + EXPECT_EQ(1, abilityRecordAfter->GetConnectionState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: UnsuspendApplication + * FunctionPoints: UnsuspendApplication + * CaseDescription: test application state is APP_STATE_BACKGROUND(apprecord is nullptr) + */ +HWTEST_F(AmsAppLifeCycleTest, AbilityBehaviorAnalysis_002, TestSize.Level0) +{ + const pid_t NEW_PID = 1234; + auto abilityInfo = GetAbilityInfoByIndex("110"); + auto appInfo = GetApplication(); + sptr token = GetMockToken(); + + auto appRecord = StartProcessAndLoadAbility(token, nullptr, abilityInfo, appInfo, NEW_PID); + EXPECT_TRUE(appRecord != nullptr); + + auto abilityRecord = appRecord->GetAbilityRunningRecordByToken(token); + EXPECT_TRUE(abilityRecord != nullptr); + EXPECT_EQ(0, abilityRecord->GetVisibility()); + EXPECT_EQ(0, abilityRecord->GetPerceptibility()); + EXPECT_EQ(0, abilityRecord->GetConnectionState()); + + EXPECT_TRUE(serviceInner_); + serviceInner_->AbilityBehaviorAnalysis(nullptr, nullptr, 1, 1, 1); + + auto abilityRecordAfter = appRecord->GetAbilityRunningRecordByToken(token); + EXPECT_TRUE(abilityRecordAfter != nullptr); + EXPECT_NE(1, abilityRecordAfter->GetVisibility()); + EXPECT_NE(1, abilityRecordAfter->GetPerceptibility()); + EXPECT_NE(1, abilityRecordAfter->GetConnectionState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: UnsuspendApplication + * FunctionPoints: UnsuspendApplication + * CaseDescription: test application state is APP_STATE_BACKGROUND(apprecord is nullptr) + */ +HWTEST_F(AmsAppLifeCycleTest, ClearUpApplicationData_001, TestSize.Level0) +{ + const pid_t NEW_PID = 1234; + auto abilityInfo = GetAbilityInfoByIndex("110"); + auto appInfo = GetApplication(); + sptr token = GetMockToken(); + + auto appRecord = StartProcessAndLoadAbility(token, nullptr, abilityInfo, appInfo, NEW_PID); + + // pid < 0 + appRecord->SetUid(101); + EXPECT_CALL(*mockBundleMgr, GetUidByBundleName(_, _)).Times(0); + serviceInner_->ClearUpApplicationData(appRecord->GetBundleName(), appRecord->GetUid(), 0); + + // uid < 0 + EXPECT_CALL(*mockBundleMgr, GetUidByBundleName(_, _)).Times(0); + serviceInner_->ClearUpApplicationData(appRecord->GetBundleName(), -1, NEW_PID); + + EXPECT_CALL(*mockBundleMgr, GetUidByBundleName(_, _)).Times(1).WillOnce(Return(101)); + EXPECT_CALL(*mockBundleMgr, CheckPermission(_, _)).Times(1); + EXPECT_CALL(*mockBundleMgr, CleanBundleDataFiles(_)).Times(1).WillOnce(Return(1)); + + sptr mockAppScheduler = new MockAppScheduler(); + sptr client = iface_cast(mockAppScheduler.GetRefPtr()); + appRecord->SetApplicationClient(client); + EXPECT_CALL(*mockAppScheduler, ScheduleProcessSecurityExit()).Times(1); + + serviceInner_->ClearUpApplicationData(appRecord->GetBundleName(), appRecord->GetUid(), NEW_PID); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: ClearUpApplicationData + * FunctionPoints: UnsuspendApplication + * CaseDescription: test application state is APP_STATE_BACKGROUND(apprecord is nullptr) + */ +HWTEST_F(AmsAppLifeCycleTest, ClearUpApplicationData_002, TestSize.Level0) +{ + auto abilityInfo = GetAbilityInfoByIndex("110"); + auto appInfo = GetApplication(); + sptr token = GetMockToken(); + + int32_t pid = fork(); + + if (pid > 0) { + auto appRecord = StartProcessAndLoadAbility(token, nullptr, abilityInfo, appInfo, pid); + + EXPECT_CALL(*mockBundleMgr, GetUidByBundleName(_, _)).Times(1).WillOnce(Return(101)); + EXPECT_CALL(*mockBundleMgr, CheckPermission(_, _)).Times(1); + EXPECT_CALL(*mockBundleMgr, CleanBundleDataFiles(_)).Times(1).WillOnce(Return(true)); + + sptr mockAppScheduler = new MockAppScheduler(); + sptr client = iface_cast(mockAppScheduler.GetRefPtr()); + appRecord->SetApplicationClient(client); + EXPECT_CALL(*mockAppScheduler, ScheduleProcessSecurityExit()).Times(1); + serviceInner_->ClearUpApplicationData(appRecord->GetBundleName(), appRecord->GetUid(), pid); + } +} + +/* + * Feature: AMS + * Function: AppLifeCycle::IsBackgroundRunningRestricted + * SubFunction: bundleMgr CheckPermission + * FunctionPoints: UnsuspendApplication + * CaseDescription: Check if there is background operation permission + */ +HWTEST_F(AmsAppLifeCycleTest, IsBackgroundRunningRestricted_001, TestSize.Level0) +{ + sptr bundleMgr = new BundleMgrService(); + serviceInner_->SetBundleManager(bundleMgr); + EXPECT_CALL(*bundleMgr, CheckPermission(_, _)).Times(1).WillOnce(Return(ERR_OK)); + EXPECT_EQ(ERR_OK, serviceInner_->IsBackgroundRunningRestricted("bundle")); +} + +/* + * Feature: AMS + * Function: AppLifeCycle::GetOrCreateAppRunningRecord + * SubFunction: bundleMgr CheckPermission + * FunctionPoints: UnsuspendApplication + * CaseDescription: Check if there is background operation permission + */ +HWTEST_F(AmsAppLifeCycleTest, GetOrCreateAppRunningRecord_001, TestSize.Level0) +{ + RecordQueryResult result; + auto abilityInfo = GetAbilityInfoByIndex("0"); + auto appInfo = GetApplication(); + sptr token = GetMockToken(); + + auto appRecord = serviceInner_->GetOrCreateAppRunningRecord(nullptr, appInfo, abilityInfo, "test_app", 100, result); + EXPECT_FALSE(appRecord); + appRecord = serviceInner_->GetOrCreateAppRunningRecord(token, nullptr, abilityInfo, "test_app", 100, result); + EXPECT_FALSE(appRecord); + appRecord = serviceInner_->GetOrCreateAppRunningRecord(token, appInfo, nullptr, "test_app", 100, result); + EXPECT_FALSE(appRecord); + appRecord = serviceInner_->GetOrCreateAppRunningRecord(token, appInfo, abilityInfo, "test_app", -1, result); + EXPECT_FALSE(appRecord); + appRecord = serviceInner_->GetOrCreateAppRunningRecord( + token, appInfo, abilityInfo, "test_app", std::numeric_limits::max(), result); + EXPECT_FALSE(appRecord); + appRecord = serviceInner_->GetOrCreateAppRunningRecord(token, appInfo, abilityInfo, "", 100, result); + EXPECT_FALSE(appRecord); +} + +/* + * Feature: AMS + * Function: AppLifeCycle::GetOrCreateAppRunningRecord + * SubFunction: bundleMgr CheckPermission + * FunctionPoints: UnsuspendApplication + * CaseDescription: Check if there is background operation permission + */ +HWTEST_F(AmsAppLifeCycleTest, GetOrCreateAppRunningRecord_002, TestSize.Level0) +{ + RecordQueryResult result; + auto abilityInfo = GetAbilityInfoByIndex("0"); + auto appInfo = GetApplication(); + sptr token = GetMockToken(); + + // add one app + auto appRecord = + serviceInner_->GetOrCreateAppRunningRecord(token, appInfo, abilityInfo, appInfo->name, 100, result); + EXPECT_TRUE(appRecord); + + // add again + RecordQueryResult result1; + auto appRecord2 = + serviceInner_->GetOrCreateAppRunningRecord(token, appInfo, abilityInfo, appInfo->name, 100, result1); + EXPECT_TRUE(appRecord2); + EXPECT_TRUE(result1.appExists); + EXPECT_TRUE(result1.abilityExists); + EXPECT_EQ(appRecord->GetRecordId(), appRecord2->GetRecordId()); + + // same token, new ability, + RecordQueryResult result2; + auto abilityInfo2 = GetAbilityInfoByIndex("1"); + auto appRecord3 = + serviceInner_->GetOrCreateAppRunningRecord(token, appInfo, abilityInfo2, appInfo->name, 100, result2); + EXPECT_TRUE(appRecord3); + EXPECT_TRUE(result2.appExists); + EXPECT_TRUE(result2.abilityExists); + EXPECT_FALSE(appRecord3->GetAbilityRunningRecord(abilityInfo2->name)); + + // new token, new ability + RecordQueryResult result3; + sptr token2 = new MockAbilityToken(); + auto abilityInfo3 = GetAbilityInfoByIndex("2"); + auto appRecord4 = + serviceInner_->GetOrCreateAppRunningRecord(token2, appInfo, abilityInfo3, appInfo->name, 100, result3); + auto abilityRecord = appRecord4->GetAbilityRunningRecord(abilityInfo3->name); + + EXPECT_TRUE(appRecord4); + EXPECT_TRUE(result3.appExists); + EXPECT_FALSE(result3.abilityExists); + EXPECT_TRUE(abilityRecord); +} + +/* + * Feature: AMS + * Function: AppLifeCycle::GetOrCreateAppRunningRecord + * SubFunction: bundleMgr CheckPermission + * FunctionPoints: UnsuspendApplication + * CaseDescription: Check if there is background operation permission + */ +HWTEST_F(AmsAppLifeCycleTest, GetAppRunningRecordByProcessName_001, TestSize.Level0) +{ + RecordQueryResult result; + auto abilityInfo = GetAbilityInfoByIndex("0"); + auto appInfo = GetApplication(); + sptr token = GetMockToken(); + + auto appRecord = + serviceInner_->GetOrCreateAppRunningRecord(token, appInfo, abilityInfo, appInfo->name, 100, result); + EXPECT_TRUE(appRecord); + + auto appRecordProc = serviceInner_->GetAppRunningRecordByProcessName(appInfo->name, appInfo->name); + EXPECT_TRUE(appRecordProc); + + EXPECT_EQ(appRecord->GetRecordId(), appRecordProc->GetRecordId()); + EXPECT_TRUE(appRecord->GetName() == appRecordProc->GetName()); + EXPECT_TRUE(appRecord->GetUid() == appRecordProc->GetUid()); + EXPECT_TRUE(appRecord->GetProcessName() == appRecordProc->GetProcessName()); + + appRecord->SetState(ApplicationState::APP_STATE_FOREGROUND); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, appRecordProc->GetState()); +} + +/* + * Feature: AMS + * Function: AppLifeCycle::GetOrCreateAppRunningRecord + * SubFunction: bundleMgr CheckPermission + * FunctionPoints: UnsuspendApplication + * CaseDescription: Check if there is background operation permission + */ +HWTEST_F(AmsAppLifeCycleTest, RemoveAppFromRecentList_001, TestSize.Level0) +{ + RecordQueryResult result; + sptr mockAppScheduler = new MockAppScheduler(); + sptr client = iface_cast(mockAppScheduler.GetRefPtr()); + + auto abilityInfo = GetAbilityInfoByIndex("0"); + auto appInfo = GetApplication(); + sptr token = GetMockToken(); + auto appRecord = StartProcessAndLoadAbility(token, nullptr, abilityInfo, appInfo, 100); + appRecord->SetApplicationClient(client); + + EXPECT_TRUE(appRecord); + int size = serviceInner_->GetRecentAppList().size(); + EXPECT_EQ(size, 1); + EXPECT_FALSE(result.appExists); + + auto abilityInfo2 = std::make_shared(); + abilityInfo2->name = "test_ability_1"; + abilityInfo2->applicationName = "test_app_1"; + abilityInfo2->process = "test_app_1"; + + auto appInfo2 = std::make_shared(); + appInfo2->name = "test_app_1"; + appInfo2->bundleName = "test_app_1"; + sptr token2 = GetMockToken(); + + auto appRecord2 = StartProcessAndLoadAbility(token, nullptr, abilityInfo2, appInfo2, 101); + appRecord2->SetApplicationClient(client); + EXPECT_TRUE(appRecord2); + size = serviceInner_->GetRecentAppList().size(); + EXPECT_EQ(size, 2); + EXPECT_FALSE(result.appExists); + + // remove the first + EXPECT_CALL(*mockAppScheduler, ScheduleProcessSecurityExit()).Times(1); + serviceInner_->RemoveAppFromRecentList(appRecord->GetName(), appRecord->GetName()); + + size = serviceInner_->GetRecentAppList().size(); + EXPECT_EQ(size, 1); + + EXPECT_CALL(*mockAppScheduler, ScheduleProcessSecurityExit()).Times(1); + serviceInner_->RemoveAppFromRecentList(appRecord2->GetName(), appRecord2->GetName()); + size = serviceInner_->GetRecentAppList().size(); + EXPECT_EQ(size, 0); +} + +/* + * Feature: AMS + * Function: AppLifeCycle::GetOrCreateAppRunningRecord + * SubFunction: bundleMgr CheckPermission + * FunctionPoints: UnsuspendApplication + * CaseDescription: Check if there is background operation permission + */ +HWTEST_F(AmsAppLifeCycleTest, GetAbilityRunningRecordByAbilityToken_001, TestSize.Level0) +{ + // RecordQueryResult result; + auto abilityInfo = GetAbilityInfoByIndex("0"); + auto appInfo = GetApplication(); + sptr token = GetMockToken(); + + auto abilityRecord = serviceInner_->GetAbilityRunningRecordByAbilityToken(nullptr); + EXPECT_FALSE(abilityRecord); + + abilityRecord = serviceInner_->GetAbilityRunningRecordByAbilityToken(token); + EXPECT_FALSE(abilityRecord); + auto appRecord = StartProcessAndLoadAbility(token, nullptr, abilityInfo, appInfo, 1234); + EXPECT_TRUE(appRecord); + + abilityRecord = serviceInner_->GetAbilityRunningRecordByAbilityToken(token); + sptr token2 = new MockAbilityToken(); + auto abilityRecord2 = serviceInner_->GetAbilityRunningRecordByAbilityToken(token2); + EXPECT_FALSE(abilityRecord2); +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/appmgr/test/unittest/ams_app_mgr_client_test/BUILD.gn b/services/appmgr/test/unittest/ams_app_mgr_client_test/BUILD.gn new file mode 100644 index 000000000..bb4bd02fa --- /dev/null +++ b/services/appmgr/test/unittest/ams_app_mgr_client_test/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/test.gni") +import("//foundation/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/appmgrservice" + +ohos_unittest("AmsAppMgrClientTest") { + module_out_path = module_output_path + + sources = [ + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/src/appmgr/app_mgr_client.cpp", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/src/appmgr/app_service_manager.cpp", + ] + + sources += [ "ams_app_mgr_client_test.cpp" ] + + include_dirs = [ + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler/include/", + "//foundation/aafwk/standard/interfaces/innerkits/want/include/", + "//foundation/distributedschedule/dmsfwk/services/dtbschedmgr/include/", + "//foundation/aafwk/standard/interfaces/innerkits/base/include/", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include/", + "//foundation/distributedschedule/samgr/adapter/interfaces/innerkits/include/", + ] + + configs = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appmgr_sdk_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${libs_path}/libeventhandler:libeventhandler_target", + "${services_path}/appmgr/test:appmgr_test_source", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":AmsAppMgrClientTest" ] +} diff --git a/services/appmgr/test/unittest/ams_app_mgr_client_test/ams_app_mgr_client_test.cpp b/services/appmgr/test/unittest/ams_app_mgr_client_test/ams_app_mgr_client_test.cpp new file mode 100644 index 000000000..99db3843a --- /dev/null +++ b/services/appmgr/test/unittest/ams_app_mgr_client_test/ams_app_mgr_client_test.cpp @@ -0,0 +1,364 @@ +/* + * 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. + */ + +#define private public +#include "app_mgr_client.h" +#undef private +#include +#include "ability_info.h" +#include "application_info.h" +#include "app_log_wrapper.h" +#include "iapp_state_callback.h" +#include "running_process_info.h" +#include "mock_ability_token.h" +#include "mock_app_mgr_service.h" +#include "mock_app_service_mgr.h" +#include "mock_iapp_state_callback.h" +#include "mock_ams_mgr_scheduler.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; +using testing::_; +using testing::Invoke; +using testing::InvokeWithoutArgs; +using testing::Return; +using testing::SetArgReferee; + +class AmsAppMgrClientTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + +protected: + sptr token_; + sptr preToken_; + std::unique_ptr client_; +}; + +void AmsAppMgrClientTest::SetUpTestCase() +{} + +void AmsAppMgrClientTest::TearDownTestCase() +{} + +void AmsAppMgrClientTest::SetUp() +{ + client_.reset(new (std::nothrow) AppMgrClient()); + client_->SetServiceManager(std::make_unique()); + token_ = new (std::nothrow) MockAbilityToken(); +} + +void AmsAppMgrClientTest::TearDown() +{} + +/* + * Feature: AppMgrService + * Function: AppMgrClient + * SubFunction: LoadAbility Function + * FunctionPoints: AppMgrClient LoadAbility interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if AppMgrClient invoke LoadAbility works. + */ +HWTEST_F(AmsAppMgrClientTest, AppMgrClient_001, TestSize.Level0) +{ + APP_LOGI("ams_app_mgr_client_test_001 start"); + EXPECT_EQ(AppMgrResultCode::RESULT_OK, client_->ConnectAppMgrService()); + + AbilityInfo abilityInfo; + ApplicationInfo appInfo; + + sptr amsMgrScheduler(new MockAmsMgrScheduler()); + + EXPECT_CALL(*(static_cast(amsMgrScheduler.GetRefPtr())), LoadAbility(_, _, _, _)).Times(1); + + EXPECT_CALL(*(static_cast(client_->remote_.GetRefPtr())), GetAmsMgr()) + .Times(1) + .WillOnce(Return(amsMgrScheduler)); + + EXPECT_EQ(AppMgrResultCode::RESULT_OK, client_->LoadAbility(token_, preToken_, abilityInfo, appInfo)); + APP_LOGI("ams_app_mgr_client_test_001 end"); +} + +/* + * Feature: AppMgrService + * Function: AppMgrClient + * SubFunction: LoadAbility Function + * FunctionPoints: AppMgrClient LoadAbility interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if AppMgrClient invoke LoadAbility act normal without connect to service. + */ +HWTEST_F(AmsAppMgrClientTest, AppMgrClient_002, TestSize.Level0) +{ + APP_LOGI("ams_app_mgr_client_test_002 start"); + AbilityInfo abilityInfo; + ApplicationInfo appInfo; + EXPECT_EQ( + AppMgrResultCode::ERROR_SERVICE_NOT_CONNECTED, client_->LoadAbility(token_, preToken_, abilityInfo, appInfo)); + APP_LOGI("ams_app_mgr_client_test_002 end"); +} + +/* + * Feature: AppMgrService + * Function: AppMgrClient + * SubFunction: TerminateAbility Function + * FunctionPoints: AppMgrClient TerminateAbility interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if AppMgrClient invoke TerminateAbility works. + */ +HWTEST_F(AmsAppMgrClientTest, AppMgrClient_003, TestSize.Level0) +{ + APP_LOGI("ams_app_mgr_client_test_003 start"); + EXPECT_EQ(AppMgrResultCode::RESULT_OK, client_->ConnectAppMgrService()); + + sptr amsMgrScheduler(new MockAmsMgrScheduler()); + EXPECT_CALL(*(static_cast(client_->remote_.GetRefPtr())), GetAmsMgr()) + .Times(1) + .WillOnce(Return(amsMgrScheduler)); + EXPECT_CALL(*(static_cast(amsMgrScheduler.GetRefPtr())), TerminateAbility(_)).Times(1); + + EXPECT_EQ(AppMgrResultCode::RESULT_OK, client_->TerminateAbility(token_)); + APP_LOGI("ams_app_mgr_client_test_003 end"); +} + +/* + * Feature: AppMgrService + * Function: AppMgrClient + * SubFunction: TerminateAbility Function + * FunctionPoints: AppMgrClient TerminateAbility interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if AppMgrClient invoke TerminateAbility act normal without connect to service. + */ +HWTEST_F(AmsAppMgrClientTest, AppMgrClient_004, TestSize.Level0) +{ + APP_LOGI("ams_app_mgr_client_test_004 start"); + EXPECT_EQ(AppMgrResultCode::ERROR_SERVICE_NOT_CONNECTED, client_->TerminateAbility(token_)); + APP_LOGI("ams_app_mgr_client_test_004 end"); +} + +/* + * Feature: AppMgrService + * Function: AppMgrClient + * SubFunction: UpdateAbilityState Function + * FunctionPoints: AppMgrClient UpdateAbilityState interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if AppMgrClient invoke UpdateAbilityState works. + */ +HWTEST_F(AmsAppMgrClientTest, AppMgrClient_005, TestSize.Level0) +{ + APP_LOGI("ams_app_mgr_client_test_005 start"); + EXPECT_EQ(AppMgrResultCode::RESULT_OK, client_->ConnectAppMgrService()); + + sptr amsMgrScheduler(new MockAmsMgrScheduler()); + EXPECT_CALL(*(static_cast(amsMgrScheduler.GetRefPtr())), UpdateAbilityState(_, _)).Times(1); + EXPECT_CALL(*(static_cast(client_->remote_.GetRefPtr())), GetAmsMgr()) + .Times(1) + .WillOnce(Return(amsMgrScheduler)); + + AbilityState state = AbilityState::ABILITY_STATE_BEGIN; + EXPECT_EQ(AppMgrResultCode::RESULT_OK, client_->UpdateAbilityState(token_, state)); + APP_LOGI("ams_app_mgr_client_test_005 end"); +} + +/* + * Feature: AppMgrService + * Function: AppMgrClient + * SubFunction: UpdateAbilityState Function + * FunctionPoints: AppMgrClient UpdateAbilityState interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if AppMgrClient invoke UpdateAbilityState act normal without connect to service. + */ +HWTEST_F(AmsAppMgrClientTest, AppMgrClient_006, TestSize.Level0) +{ + APP_LOGI("ams_app_mgr_client_test_006 start"); + AbilityState state = AbilityState::ABILITY_STATE_BEGIN; + EXPECT_EQ(AppMgrResultCode::ERROR_SERVICE_NOT_CONNECTED, client_->UpdateAbilityState(token_, state)); + APP_LOGI("ams_app_mgr_client_test_006 end"); +} + +/* + * Feature: AppMgrService + * Function: AppMgrClient + * SubFunction: RegisterAppStateCallback Function + * FunctionPoints: AppMgrClient RegisterAppStateCallback interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if AppMgrClient invoke RegisterAppStateCallback works. + */ +HWTEST_F(AmsAppMgrClientTest, AppMgrClient_007, TestSize.Level0) +{ + APP_LOGI("ams_app_mgr_client_test_007 start"); + EXPECT_EQ(AppMgrResultCode::RESULT_OK, client_->ConnectAppMgrService()); + sptr mockCallback(new MockAppStateCallback()); + sptr callback = iface_cast(mockCallback); + + sptr amsMgrScheduler(new MockAmsMgrScheduler()); + EXPECT_CALL(*(static_cast(client_->remote_.GetRefPtr())), GetAmsMgr()) + .Times(1) + .WillOnce(Return(amsMgrScheduler)); + + EXPECT_CALL(*mockCallback, OnAbilityRequestDone(_, _)).Times(1); + EXPECT_CALL(*mockCallback, OnAppStateChanged(_)).Times(1); + + EXPECT_EQ(AppMgrResultCode::RESULT_OK, client_->RegisterAppStateCallback(callback)); + APP_LOGI("ams_app_mgr_client_test_007 end"); +} + +/* + * Feature: AppMgrService + * Function: AppMgrClient + * SubFunction: RegisterAppStateCallback Function + * FunctionPoints: AppMgrClient RegisterAppStateCallback interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if AppMgrClient invoke RegisterAppStateCallback act normal without connect to service. + */ +HWTEST_F(AmsAppMgrClientTest, AppMgrClient_008, TestSize.Level0) +{ + APP_LOGI("ams_app_mgr_client_test_008 start"); + sptr callback; + EXPECT_EQ(AppMgrResultCode::ERROR_SERVICE_NOT_CONNECTED, client_->RegisterAppStateCallback(callback)); + APP_LOGI("ams_app_mgr_client_test_008 end"); +} + +/* + * Feature: AppMgrService + * Function: AppMgrClient::AbilityBehaviorAnalysis + * SubFunction: RegisterAppStateCallback Function + * FunctionPoints: AppMgrClient AbilityBehaviorAnalysis interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: ability behavior notification + */ +HWTEST_F(AmsAppMgrClientTest, AppMgrClient_009, TestSize.Level0) +{ + APP_LOGI("ams_app_mgr_client_test_008 start"); + EXPECT_EQ(AppMgrResultCode::RESULT_OK, client_->ConnectAppMgrService()); + sptr token; + sptr preToken; + + sptr amsMgrScheduler(new MockAmsMgrScheduler()); + EXPECT_CALL( + *(static_cast(amsMgrScheduler.GetRefPtr())), AbilityBehaviorAnalysis(_, _, _, _, _)) + .Times(1); + EXPECT_CALL(*(static_cast(client_->remote_.GetRefPtr())), GetAmsMgr()) + .Times(1) + .WillOnce(Return(amsMgrScheduler)); + + EXPECT_EQ(AppMgrResultCode::RESULT_OK, client_->AbilityBehaviorAnalysis(token, preToken, 1, 1, 1)); + APP_LOGI("ams_app_mgr_client_test_008 end"); +} + +/* + * Feature: AppMgrService + * Function: AppMgrClient::KillApplication + * SubFunction: RegisterAppStateCallback Function + * FunctionPoints: AppMgrClient KillApplication interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Notify app of death + */ +HWTEST_F(AmsAppMgrClientTest, AppMgrClient_010, TestSize.Level0) +{ + APP_LOGI("ams_app_mgr_client_test_008 start"); + EXPECT_EQ(AppMgrResultCode::RESULT_OK, client_->ConnectAppMgrService()); + sptr token; + sptr preToken; + + sptr amsMgrScheduler(new MockAmsMgrScheduler()); + EXPECT_CALL(*(static_cast(amsMgrScheduler.GetRefPtr())), KillApplication(_)) + .Times(1) + .WillOnce(Return(ERR_OK)); + EXPECT_CALL(*(static_cast(client_->remote_.GetRefPtr())), GetAmsMgr()) + .Times(1) + .WillOnce(Return(amsMgrScheduler)); + + EXPECT_EQ(AppMgrResultCode::RESULT_OK, client_->KillApplication("")); + APP_LOGI("ams_app_mgr_client_test_008 end"); +} + +/* + * Feature: AppMgrService + * Function: AppMgrClient::KillApplication + * SubFunction: RegisterAppStateCallback Function + * FunctionPoints: AppMgrClient KillApplication interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Notify app of death + */ +HWTEST_F(AmsAppMgrClientTest, AppMgrClient_011, TestSize.Level0) +{ + APP_LOGI("ams_app_mgr_client_test_011 start"); + sptr token; + sptr preToken; + EXPECT_EQ(AppMgrResultCode::RESULT_OK, client_->ConnectAppMgrService()); + sptr amsMgrScheduler(new MockAmsMgrScheduler()); + EXPECT_CALL(*(static_cast(amsMgrScheduler.GetRefPtr())), KillApplication(_)) + .Times(1) + .WillOnce(Return(ERR_NO_MEMORY)); + EXPECT_CALL(*(static_cast(client_->remote_.GetRefPtr())), GetAmsMgr()) + .Times(1) + .WillOnce(Return(amsMgrScheduler)); + + EXPECT_EQ(AppMgrResultCode::ERROR_SERVICE_NOT_READY, client_->KillApplication("")); + APP_LOGI("ams_app_mgr_client_test_011 end"); +} + +/* + * Feature: AppMgrService + * Function: AppMgrClient::KillProcessByAbilityToken + * SubFunction: RegisterAppStateCallback Function + * FunctionPoints: AppMgrClient KillApplication interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Notify app of death + */ +HWTEST_F(AmsAppMgrClientTest, AppMgrClient_012, TestSize.Level0) +{ + APP_LOGI("ams_app_mgr_client_test_012 start"); + sptr token; + EXPECT_EQ(AppMgrResultCode::RESULT_OK, client_->ConnectAppMgrService()); + sptr amsMgrScheduler(new MockAmsMgrScheduler()); + EXPECT_CALL(*(static_cast(amsMgrScheduler.GetRefPtr())), KillProcessByAbilityToken(_)) + .Times(1); + + EXPECT_CALL(*(static_cast(client_->remote_.GetRefPtr())), GetAmsMgr()) + .Times(1) + .WillOnce(Return(amsMgrScheduler)); + + EXPECT_EQ(AppMgrResultCode::RESULT_OK, client_->KillProcessByAbilityToken(token)); + APP_LOGI("ams_app_mgr_client_test_012 end"); +} + +/* + * Feature: AppMgrService + * Function: AppMgrClient::KillProcessByAbilityToken + * SubFunction: RegisterAppStateCallback Function + * FunctionPoints: AppMgrClient KillApplication interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Notify app of death + */ +HWTEST_F(AmsAppMgrClientTest, AppMgrClient_013, TestSize.Level0) +{ + APP_LOGI("ams_app_mgr_client_test_013 start"); + sptr token; + EXPECT_EQ(AppMgrResultCode::RESULT_OK, client_->ConnectAppMgrService()); + sptr amsMgrScheduler(new MockAmsMgrScheduler()); + EXPECT_CALL(*(static_cast(amsMgrScheduler.GetRefPtr())), KillProcessByAbilityToken(_)) + .Times(0); + + EXPECT_CALL(*(static_cast(client_->remote_.GetRefPtr())), GetAmsMgr()) + .Times(1) + .WillOnce(Return(nullptr)); + + EXPECT_EQ(AppMgrResultCode::ERROR_SERVICE_NOT_CONNECTED, client_->KillProcessByAbilityToken(token)); + APP_LOGI("ams_app_mgr_client_test_013 end"); +} \ No newline at end of file diff --git a/services/appmgr/test/unittest/ams_app_running_record_test/BUILD.gn b/services/appmgr/test/unittest/ams_app_running_record_test/BUILD.gn new file mode 100644 index 000000000..1d13c25e0 --- /dev/null +++ b/services/appmgr/test/unittest/ams_app_running_record_test/BUILD.gn @@ -0,0 +1,66 @@ +# 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/appmgrservice" + +ohos_unittest("AmsAppRunningRecordTest") { + module_out_path = module_output_path + + include_dirs = [ + "//foundation/aafwk/standard/interfaces/innerkits/base/include", + "//foundation/aafwk/standard/interfaces/innerkits/want/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include", + "//foundation/distributedschedule/dmsfwk/services/dtbschedmgr/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "//foundation/distributedschedule/samgr/adapter/interfaces/innerkits/include/", + ] + + sources = [ + "${services_path}/appmgr/src/ability_running_record.cpp", + "${services_path}/appmgr/src/app_mgr_service_inner.cpp", + "${services_path}/appmgr/src/app_running_record.cpp", + "${services_path}/appmgr/src/app_spawn_client.cpp", + "${services_path}/appmgr/src/app_spawn_msg_wrapper.cpp", + "${services_path}/appmgr/src/app_spawn_socket.cpp", + "${services_path}/appmgr/test/mock/src/mock_bundle_manager.cpp", + ] + + sources += [ "ams_app_running_record_test.cpp" ] + + configs = [ "${libs_path}/libeventhandler:libeventhandler_config" ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${libs_path}/libeventhandler:libeventhandler_target", + "${services_path}/appmgr/test:appmgr_test_source", + "//base/startup/appspawn_standard:appspawn_socket_client", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "//foundation/appexecfwk/standard/services/appmgr:libams", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":AmsAppRunningRecordTest" ] +} diff --git a/services/appmgr/test/unittest/ams_app_running_record_test/ams_app_running_record_test.cpp b/services/appmgr/test/unittest/ams_app_running_record_test/ams_app_running_record_test.cpp new file mode 100644 index 000000000..1df3e63d8 --- /dev/null +++ b/services/appmgr/test/unittest/ams_app_running_record_test/ams_app_running_record_test.cpp @@ -0,0 +1,1231 @@ +/* + * 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. + */ + +#define private public +#include "app_mgr_service_inner.h" +#undef private + +#include +#include +#include "iremote_object.h" +#include "refbase.h" +#include "application_info.h" +#include "app_log_wrapper.h" +#include "app_record_id.h" +#include "app_scheduler_host.h" +#include "ability_info.h" +#include "ability_running_record.h" +#include "mock_app_scheduler.h" +#include "mock_ability_token.h" +#include "mock_app_spawn_client.h" +#include "mock_app_mgr_service_inner.h" +#include "mock_iapp_state_callback.h" +#include "mock_bundle_manager.h" + +using namespace testing::ext; +using testing::_; +using testing::Return; +using testing::SetArgReferee; +namespace OHOS { +namespace AppExecFwk { +class AmsAppRunningRecordTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + +protected: + static const std::string GetTestProcessName() + { + return "test_app_name"; + } + static const std::string GetTestAppName() + { + return "test_app_name"; + } + static const std::string GetTestAbilityName() + { + return "test_ability_name"; + } + static int GetTestUid() + { + // a valid inner uid value which is not border value. + const static int VALID_UID_VALUE = 1010; + return VALID_UID_VALUE; + } + + std::shared_ptr GetTestAppRunningRecord(); + sptr GetMockedAppSchedulerClient() const; + std::shared_ptr StartLoadAbility(const sptr &token, + const std::shared_ptr &abilityInfo, const std::shared_ptr &appInfo, + const pid_t newPid) const; + sptr GetMockToken() const + { + return mock_token_; + } + +protected: + std::shared_ptr testAbilityRecord_; + sptr client_; + sptr mockAppSchedulerClient_; + std::shared_ptr testAppRecord_; + std::unique_ptr service_; + sptr mock_token_; + sptr mockBundleMgr; +}; + +void AmsAppRunningRecordTest::SetUpTestCase() +{} + +void AmsAppRunningRecordTest::TearDownTestCase() +{} + +void AmsAppRunningRecordTest::SetUp() +{ + mockAppSchedulerClient_ = new (std::nothrow) MockAppScheduler(); + service_.reset(new (std::nothrow) AppMgrServiceInner()); + mock_token_ = new (std::nothrow) MockAbilityToken(); + client_ = iface_cast(mockAppSchedulerClient_.GetRefPtr()); + mockBundleMgr = new (std::nothrow) BundleMgrService(); + service_->SetBundleManager(mockBundleMgr); +} + +void AmsAppRunningRecordTest::TearDown() +{ + testAbilityRecord_.reset(); + testAppRecord_.reset(); +} + +sptr AmsAppRunningRecordTest::GetMockedAppSchedulerClient() const +{ + if (client_) { + return client_; + } + return nullptr; +} + +std::shared_ptr AmsAppRunningRecordTest::GetTestAppRunningRecord() +{ + if (!testAppRecord_) { + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + testAppRecord_ = std::make_shared(appInfo, AppRecordId::Create(), GetTestProcessName()); + testAppRecord_->SetApplicationClient(GetMockedAppSchedulerClient()); + } + return testAppRecord_; +} + +std::shared_ptr AmsAppRunningRecordTest::StartLoadAbility(const sptr &token, + const std::shared_ptr &abilityInfo, const std::shared_ptr &appInfo, + const pid_t newPid) const +{ + RecordQueryResult result; + std::shared_ptr mockClientPtr = std::make_shared(); + service_->SetAppSpawnClient(mockClientPtr); + EXPECT_CALL(*mockClientPtr, StartProcess(_, _)).Times(1).WillOnce(DoAll(SetArgReferee<1>(newPid), Return(ERR_OK))); + + service_->LoadAbility(token, nullptr, abilityInfo, appInfo); + + std::shared_ptr record = + service_->GetOrCreateAppRunningRecord(GetMockToken(), appInfo, abilityInfo, GetTestProcessName(), 0, result); + + EXPECT_TRUE(record); + auto clent = GetMockedAppSchedulerClient(); + record->SetApplicationClient(clent); + EXPECT_EQ(record->GetPriorityObject()->GetPid(), newPid); + EXPECT_NE(record->GetApplicationClient(), nullptr); + return record; +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: Create using correct args with app/ability not exists. + * EnvConditions: NA + * CaseDescription: Call GetOrCreateAppRunningRecord to get result. + */ +HWTEST_F(AmsAppRunningRecordTest, CreateAppRunningRecord_001, TestSize.Level0) +{ + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + RecordQueryResult result; + EXPECT_TRUE(service_ != nullptr); + auto record = service_->GetOrCreateAppRunningRecord( + GetMockToken(), appInfo, abilityInfo, GetTestProcessName(), GetTestUid(), result); + + EXPECT_TRUE(record != nullptr); + EXPECT_EQ(result.error, ERR_OK); + EXPECT_EQ(record->GetName(), GetTestAppName()); + EXPECT_FALSE(result.appExists); + EXPECT_FALSE(result.abilityExists); + EXPECT_TRUE(result.appRecordId > 0); + + EXPECT_EQ(record->GetProcessName(), GetTestProcessName()); + + auto abilityRecord = record->GetAbilityRunningRecordByToken(GetMockToken()); + EXPECT_TRUE(abilityRecord != nullptr); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints Create using correct args with app/ability exists. + * EnvConditions: NA + * CaseDescription: Call GetOrCreateAppRunningRecord twice to create/get a AppRunningRecord. + */ +HWTEST_F(AmsAppRunningRecordTest, CreateAppRunningRecord_002, TestSize.Level0) +{ + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + RecordQueryResult result; + EXPECT_TRUE(service_ != nullptr); + // Create + sptr token = GetMockToken(); + auto record = + service_->GetOrCreateAppRunningRecord(token, appInfo, abilityInfo, GetTestProcessName(), GetTestUid(), result); + EXPECT_EQ(result.error, ERR_OK); + // Get + record = + service_->GetOrCreateAppRunningRecord(token, appInfo, abilityInfo, GetTestProcessName(), GetTestUid(), result); + EXPECT_TRUE(record != nullptr); + EXPECT_EQ(result.error, ERR_OK); + EXPECT_EQ(record->GetName(), GetTestAppName()); + EXPECT_EQ(record->GetProcessName(), GetTestProcessName()); + // Already exists + EXPECT_TRUE(result.appExists); + EXPECT_TRUE(result.abilityExists); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: Create using correct args with app exists but ability not. + * EnvConditions: NA + * CaseDescription: Call GetOrCreateAppRunningRecord twice which second call uses a different ability info. + */ +HWTEST_F(AmsAppRunningRecordTest, CreateAppRunningRecord_003, TestSize.Level0) +{ + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + RecordQueryResult result; + EXPECT_TRUE(service_ != nullptr); + auto record = service_->GetOrCreateAppRunningRecord( + GetMockToken(), appInfo, abilityInfo, GetTestProcessName(), GetTestUid(), result); + EXPECT_EQ(result.error, ERR_OK); + + auto anotherAbilityInfo = std::make_shared(); + anotherAbilityInfo->name = "Another_ability"; + sptr anotherToken = new (std::nothrow) MockAbilityToken(); + record = service_->GetOrCreateAppRunningRecord( + anotherToken, appInfo, anotherAbilityInfo, GetTestProcessName(), GetTestUid(), result); + EXPECT_EQ(result.error, ERR_OK); + EXPECT_EQ(record->GetName(), GetTestAppName()); + EXPECT_EQ(record->GetProcessName(), GetTestProcessName()); + EXPECT_TRUE(result.appExists); + EXPECT_FALSE(result.abilityExists); + EXPECT_TRUE(result.appRecordId > 0); + + auto abilityRecord = record->GetAbilityRunningRecordByToken(GetMockToken()); + EXPECT_TRUE(abilityRecord != nullptr); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: Create using invalid uid (-1). + * EnvConditions: NA + * CaseDescription: Call GetOrCreateAppRunningRecord using uid -1. + */ +HWTEST_F(AmsAppRunningRecordTest, CreateAppRunningRecord_004, TestSize.Level0) +{ + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + RecordQueryResult result; + EXPECT_TRUE(service_ != nullptr); + // Create + auto record = + service_->GetOrCreateAppRunningRecord(GetMockToken(), appInfo, abilityInfo, GetTestProcessName(), -1, result); + EXPECT_TRUE(record == nullptr); + EXPECT_EQ(result.error, ERR_APPEXECFWK_INVALID_UID); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: Create using invalid uid (int32_max). + * EnvConditions: NA + * CaseDescription: Call GetOrCreateAppRunningRecord using uid int32_max. + */ +HWTEST_F(AmsAppRunningRecordTest, CreateAppRunningRecord_005, TestSize.Level0) +{ + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + RecordQueryResult result; + EXPECT_TRUE(service_ != nullptr); + // Create + auto record = service_->GetOrCreateAppRunningRecord( + GetMockToken(), appInfo, abilityInfo, GetTestProcessName(), std::numeric_limits::max(), result); + EXPECT_TRUE(record == nullptr); + EXPECT_EQ(result.error, ERR_APPEXECFWK_INVALID_UID); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: Create using empty appInfo. + * EnvConditions: NA + * CaseDescription: Call GetOrCreateAppRunningRecord using empty appInfo. + */ +HWTEST_F(AmsAppRunningRecordTest, CreateAppRunningRecord_006, TestSize.Level0) +{ + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + RecordQueryResult result; + EXPECT_TRUE(service_ != nullptr); + // Create + auto record = service_->GetOrCreateAppRunningRecord( + GetMockToken(), nullptr, abilityInfo, GetTestProcessName(), GetTestUid(), result); + EXPECT_TRUE(record == nullptr); + EXPECT_EQ(result.error, ERR_INVALID_VALUE); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: Create using empty abilityInfo. + * EnvConditions: NA + * CaseDescription: Call GetOrCreateAppRunningRecord using empty abilityInfo. + */ +HWTEST_F(AmsAppRunningRecordTest, CreateAppRunningRecord_007, TestSize.Level0) +{ + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + RecordQueryResult result; + EXPECT_TRUE(service_ != nullptr); + // Create + auto record = service_->GetOrCreateAppRunningRecord( + GetMockToken(), appInfo, nullptr, GetTestProcessName(), GetTestUid(), result); + EXPECT_TRUE(record == nullptr); + EXPECT_EQ(result.error, ERR_INVALID_VALUE); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: Create using valid border uid (0). + * EnvConditions: NA + * CaseDescription: Call GetOrCreateAppRunningRecord using uid 0. + */ +HWTEST_F(AmsAppRunningRecordTest, CreateAppRunningRecord_008, TestSize.Level0) +{ + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + RecordQueryResult result; + EXPECT_TRUE(service_ != nullptr); + // Create + auto record = + service_->GetOrCreateAppRunningRecord(GetMockToken(), appInfo, abilityInfo, GetTestProcessName(), 0, result); + EXPECT_TRUE(record != nullptr); + EXPECT_EQ(result.error, ERR_OK); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: Create using valid border uid (int32_max - 1). + * EnvConditions: NA + * CaseDescription: Call GetOrCreateAppRunningRecord using uid (int32_max - 1). + */ +HWTEST_F(AmsAppRunningRecordTest, CreateAppRunningRecord_009, TestSize.Level0) +{ + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + RecordQueryResult result; + EXPECT_TRUE(service_ != nullptr); + // Create + auto record = service_->GetOrCreateAppRunningRecord( + GetMockToken(), appInfo, abilityInfo, GetTestProcessName(), std::numeric_limits::max() - 1, result); + EXPECT_TRUE(record != nullptr); + EXPECT_EQ(result.error, ERR_OK); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: Test launch application. + * EnvConditions: NA + * CaseDescription: Create an AppRunningRecord and call LaunchApplication. + */ +HWTEST_F(AmsAppRunningRecordTest, LaunchApplication_001, TestSize.Level0) +{ + auto record = GetTestAppRunningRecord(); + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleLaunchApplication(_)).Times(1); + record->LaunchApplication(); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: Test launch ability via AppRunningRecord using valid name. + * EnvConditions: NA + * CaseDescription: Create an AppRunningRecord and call LaunchAbility which is exists. + */ +HWTEST_F(AmsAppRunningRecordTest, LaunchAbility_001, TestSize.Level0) +{ + auto record = GetTestAppRunningRecord(); + EXPECT_TRUE(record); + auto abilityRecord = record->AddAbility(GetMockToken(), nullptr); + + EXPECT_EQ(nullptr, abilityRecord); + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleLaunchAbility(_, _)).Times(0); + record->LaunchAbility(abilityRecord); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: Test launch ability via AppRunningRecord using empty name. + * EnvConditions: NA + * CaseDescription: Create an AppRunningRecord and call LaunchAbility which is not exists. + */ +HWTEST_F(AmsAppRunningRecordTest, LaunchAbility_002, TestSize.Level0) +{ + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + auto record = GetTestAppRunningRecord(); + auto abilityRecord = record->AddAbility(GetMockToken(), abilityInfo); + + EXPECT_TRUE(abilityRecord); + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleLaunchAbility(_, _)).Times(1); + + record->LaunchAbility(abilityRecord); + + EXPECT_EQ(AbilityState::ABILITY_STATE_READY, abilityRecord->GetState()); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: Schedule application terminate by AppRunningRecord. + * EnvConditions: NA + * CaseDescription: Create an AppRunningRecord and call ScheduleTerminate. + */ +HWTEST_F(AmsAppRunningRecordTest, ScheduleTerminate_001, TestSize.Level0) +{ + auto record = GetTestAppRunningRecord(); + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleTerminateApplication()).Times(1); + record->ScheduleTerminate(); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: Schedule application foreground by AppRunningRecord. + * EnvConditions: NA + * CaseDescription: Create an AppRunningRecord and call ScheduleForegroundRunning. + */ +HWTEST_F(AmsAppRunningRecordTest, ScheduleForegroundRunning_001, TestSize.Level0) +{ + auto record = GetTestAppRunningRecord(); + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleForegroundApplication()).Times(1); + record->ScheduleForegroundRunning(); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: Schedule application background by AppRunningRecord. + * EnvConditions: NA + * CaseDescription: Create an AppRunningRecord and call ScheduleBackgroundRunning. + */ +HWTEST_F(AmsAppRunningRecordTest, ScheduleBackgroundRunning_001, TestSize.Level0) +{ + auto record = GetTestAppRunningRecord(); + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleBackgroundApplication()).Times(1); + record->ScheduleBackgroundRunning(); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: Schedule application trim memory by AppRunningRecord. + * EnvConditions: NA + * CaseDescription: Create an AppRunningRecord and call ScheduleTrimMemory. + */ +HWTEST_F(AmsAppRunningRecordTest, ScheduleTrimMemory_001, TestSize.Level0) +{ + auto record = GetTestAppRunningRecord(); + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleShrinkMemory(_)).Times(1); + EXPECT_NE(nullptr, record->GetPriorityObject()); + record->ScheduleTrimMemory(); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: Test low memory warning notification handling. + * EnvConditions: NA + * CaseDescription: Create an AppRunningRecord and call LowMemoryWarning. + */ +HWTEST_F(AmsAppRunningRecordTest, LowMemoryWarning_001, TestSize.Level0) +{ + auto record = GetTestAppRunningRecord(); + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleLowMemory()).Times(1); + record->LowMemoryWarning(); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: Update application state using correct args. + * EnvConditions: NA + * CaseDescription: Create an AppRunningRecord and call SetState in a for-each cycle. + */ +HWTEST_F(AmsAppRunningRecordTest, UpdateAppRunningRecord_001, TestSize.Level0) +{ + auto record = GetTestAppRunningRecord(); + for (ApplicationState state = ApplicationState::APP_STATE_BEGIN; state < ApplicationState::APP_STATE_END; + state = (ApplicationState)(static_cast::type>(state) + 1)) { + record->SetState(state); + EXPECT_EQ(record->GetState(), state); + } +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: Update application state using wrong args. + * EnvConditions: NA + * CaseDescription: Create an AppRunningRecord and call SetState using arg |APP_STATE_END|. + */ +HWTEST_F(AmsAppRunningRecordTest, UpdateAppRunningRecord_002, TestSize.Level0) +{ + auto record = GetTestAppRunningRecord(); + record->SetState(ApplicationState::APP_STATE_END); + EXPECT_NE(record->GetState(), ApplicationState::APP_STATE_END); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: Delete application record info when application terminated. + * EnvConditions: NA + * CaseDescription: Create an AppRunningRecord and call AppMgrService::ApplicationTerminated passing exists |RecordId|. + */ +HWTEST_F(AmsAppRunningRecordTest, DeleteAppRunningRecord_001, TestSize.Level0) +{ + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + RecordQueryResult result; + EXPECT_TRUE(service_ != nullptr); + auto record = + service_->GetOrCreateAppRunningRecord(GetMockToken(), appInfo, abilityInfo, GetTestProcessName(), 0, result); + EXPECT_TRUE(record != nullptr); + record->SetState(ApplicationState::APP_STATE_BACKGROUND); + record->SetApplicationClient(GetMockedAppSchedulerClient()); + service_->ApplicationTerminated(record->GetRecordId()); + record = service_->GetAppRunningRecordByAppRecordId(record->GetRecordId()); + EXPECT_TRUE(record == nullptr); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: When server received attachApplication request. + * EnvConditions: NA + * CaseDescription: Test server received normal pid attachApplication request. + */ +HWTEST_F(AmsAppRunningRecordTest, AttachApplication_001, TestSize.Level0) +{ + APP_LOGI("AmsAppRunningRecordTest AttachApplication_001 start"); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + abilityInfo->process = GetTestAppName(); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + sptr token = GetMockToken(); + + const pid_t newPid = 1234; + EXPECT_TRUE(service_); + auto record = StartLoadAbility(token, abilityInfo, appInfo, newPid); + + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleLaunchApplication(_)).Times(1); + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleLaunchAbility(_, _)).Times(1); + service_->AttachApplication(newPid, mockAppSchedulerClient_); + EXPECT_EQ(record->GetState(), ApplicationState::APP_STATE_READY); + APP_LOGI("AmsAppRunningRecordTest AttachApplication_001 end"); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: When server received attachApplication request. + * EnvConditions: NA + * CaseDescription: Test server received invalid pid attachApplication request. + */ +HWTEST_F(AmsAppRunningRecordTest, AttachApplication_002, TestSize.Level0) +{ + APP_LOGI("AmsAppRunningRecordTest AttachApplication_002 start"); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + abilityInfo->process = GetTestAppName(); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + sptr token = GetMockToken(); + EXPECT_TRUE(service_ != nullptr); + const pid_t newPid = 1234; + const pid_t invalidPid = -1; + auto record = StartLoadAbility(token, abilityInfo, appInfo, newPid); + + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleLaunchApplication(_)).Times(0); + service_->AttachApplication(invalidPid, GetMockedAppSchedulerClient()); + EXPECT_EQ(record->GetState(), ApplicationState::APP_STATE_CREATE); + APP_LOGI("AmsAppRunningRecordTest AttachApplication_002 end"); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: When server received attachApplication request. + * EnvConditions: NA + * CaseDescription: Test server received non-exist pid attachApplication request. + */ +HWTEST_F(AmsAppRunningRecordTest, AttachApplication_003, TestSize.Level0) +{ + APP_LOGI("AmsAppRunningRecordTest AttachApplication_003 start"); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + abilityInfo->process = GetTestAppName(); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + sptr token = GetMockToken(); + EXPECT_TRUE(service_ != nullptr); + const pid_t newPid = 1234; + const pid_t anotherPid = 1000; + auto record = StartLoadAbility(token, abilityInfo, appInfo, newPid); + + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleLaunchApplication(_)).Times(0); + service_->AttachApplication(anotherPid, GetMockedAppSchedulerClient()); + EXPECT_EQ(record->GetState(), ApplicationState::APP_STATE_CREATE); + APP_LOGI("AmsAppRunningRecordTest AttachApplication_003 end"); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: When server received attachApplication request. + * EnvConditions: NA + * CaseDescription: Test server received null appClient attachApplication request. + */ +HWTEST_F(AmsAppRunningRecordTest, AttachApplication_004, TestSize.Level0) +{ + APP_LOGI("AmsAppRunningRecordTest AttachApplication_004 start"); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + abilityInfo->process = GetTestAppName(); + + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + sptr token = GetMockToken(); + EXPECT_TRUE(service_ != nullptr); + const pid_t newPid = 1234; + auto record = StartLoadAbility(token, abilityInfo, appInfo, newPid); + service_->AttachApplication(newPid, nullptr); + EXPECT_EQ(record->GetState(), ApplicationState::APP_STATE_CREATE); + APP_LOGI("AmsAppRunningRecordTest AttachApplication_004 end"); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: When server received attachApplication request. + * EnvConditions: NA + * CaseDescription: Test server received multiple same attachApplication request. + */ +HWTEST_F(AmsAppRunningRecordTest, AttachApplication_005, TestSize.Level0) +{ + APP_LOGI("AmsAppRunningRecordTest AttachApplication_005 start"); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + abilityInfo->process = GetTestAppName(); + + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + + sptr token = GetMockToken(); + const pid_t newPid = 1234; + EXPECT_TRUE(service_ != nullptr); + auto record = StartLoadAbility(token, abilityInfo, appInfo, newPid); + + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleLaunchApplication(_)).Times(1); + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleLaunchAbility(_, _)).Times(1); + service_->AttachApplication(newPid, GetMockedAppSchedulerClient()); + EXPECT_NE(record->GetApplicationClient(), nullptr); + EXPECT_EQ(record->GetState(), ApplicationState::APP_STATE_READY); + + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleLaunchApplication(_)).Times(0); + service_->AttachApplication(newPid, GetMockedAppSchedulerClient()); + EXPECT_EQ(record->GetState(), ApplicationState::APP_STATE_READY); + APP_LOGI("AmsAppRunningRecordTest AttachApplication_005 end"); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: When server received attachApplication request. + * EnvConditions: NA + * CaseDescription: Test server received attachApplication request after multiple loadAbility. + */ +HWTEST_F(AmsAppRunningRecordTest, AttachApplication_006, TestSize.Level0) +{ + APP_LOGI("AmsAppRunningRecordTest AttachApplication_006 start"); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + abilityInfo->process = GetTestAppName(); + + auto abilityInfo2 = std::make_shared(); + abilityInfo2->name = GetTestAbilityName() + "_1"; + abilityInfo2->applicationName = GetTestAppName(); + abilityInfo2->process = GetTestAppName(); + + auto abilityInfo3 = std::make_shared(); + abilityInfo3->name = GetTestAbilityName() + "_2"; + abilityInfo3->applicationName = GetTestAppName(); + abilityInfo3->process = GetTestAppName(); + + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + + sptr token = GetMockToken(); + const uint32_t EXPECT_RECORD_SIZE = 3; + const int EXPECT_ABILITY_LAUNCH_TIME = 3; + const pid_t PID = 1234; + EXPECT_TRUE(service_ != nullptr); + auto record = StartLoadAbility(token, abilityInfo, appInfo, PID); + + sptr token2 = new (std::nothrow) MockAbilityToken(); + service_->LoadAbility(token2, nullptr, abilityInfo2, appInfo); + sptr token3 = new (std::nothrow) MockAbilityToken(); + service_->LoadAbility(token3, nullptr, abilityInfo3, appInfo); + EXPECT_EQ(record->GetAbilities().size(), EXPECT_RECORD_SIZE); + + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleLaunchApplication(_)).Times(1); + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleLaunchAbility(_, _)).Times(EXPECT_ABILITY_LAUNCH_TIME); + service_->AttachApplication(PID, mockAppSchedulerClient_); + EXPECT_NE(record->GetApplicationClient(), nullptr); + EXPECT_EQ(record->GetState(), ApplicationState::APP_STATE_READY); + APP_LOGI("AmsAppRunningRecordTest AttachApplication_006 end"); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: When server LaunchApplication and LaunchAbility. + * EnvConditions: NA + * CaseDescription: Test normal case of LaunchAbility after LaunchApplication. + */ +HWTEST_F(AmsAppRunningRecordTest, LaunchAbilityForApp_001, TestSize.Level0) +{ + APP_LOGI("AmsAppRunningRecordTest LaunchAbilityForApp_001 start"); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + abilityInfo->process = GetTestAppName(); + + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + RecordQueryResult result; + Profile profile; + EXPECT_TRUE(service_ != nullptr); + + std::shared_ptr record = + service_->GetOrCreateAppRunningRecord(GetMockToken(), appInfo, abilityInfo, GetTestProcessName(), 0, result); + auto abilityRecord = record->GetAbilityRunningRecord(GetTestAbilityName()); + EXPECT_TRUE(abilityRecord != nullptr); + + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleLaunchApplication(_)).Times(1); + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleLaunchAbility(_, _)).Times(1); + record->SetApplicationClient(GetMockedAppSchedulerClient()); + service_->LaunchApplication(record); + EXPECT_EQ(record->GetState(), ApplicationState::APP_STATE_READY); + APP_LOGI("AmsAppRunningRecordTest LaunchAbilityForApp_001 end"); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: When server LaunchApplication and LaunchAbility. + * EnvConditions: NA + * CaseDescription: Test normal case of multiple LaunchAbility after LaunchApplication. + */ +HWTEST_F(AmsAppRunningRecordTest, LaunchAbilityForApp_002, TestSize.Level0) +{ + APP_LOGI("AmsAppRunningRecordTest LaunchAbilityForApp_002 start"); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + auto abilityInfo2 = std::make_shared(); + abilityInfo2->name = GetTestAbilityName() + "_1"; + abilityInfo2->applicationName = GetTestAppName(); + auto abilityInfo3 = std::make_shared(); + abilityInfo3->name = GetTestAbilityName() + "_2"; + abilityInfo3->applicationName = GetTestAppName(); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + RecordQueryResult result; + Profile profile; + const int EXPECT_ABILITY_LAUNCH_TIME = 3; + EXPECT_TRUE(service_ != nullptr); + + std::shared_ptr record = + service_->GetOrCreateAppRunningRecord(GetMockToken(), appInfo, abilityInfo, GetTestProcessName(), 0, result); + auto abilityRecord = record->GetAbilityRunningRecord(GetTestAbilityName()); + EXPECT_TRUE(abilityRecord != nullptr); + sptr token2 = new (std::nothrow) MockAbilityToken(); + auto abilityRecord2 = record->AddAbility(token2, abilityInfo2); + EXPECT_TRUE(abilityRecord2 != nullptr); + sptr token3 = new (std::nothrow) MockAbilityToken(); + auto abilityRecord3 = record->AddAbility(token3, abilityInfo3); + EXPECT_TRUE(abilityRecord3 != nullptr); + + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleLaunchApplication(_)).Times(1); + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleLaunchAbility(_, _)).Times(EXPECT_ABILITY_LAUNCH_TIME); + record->SetApplicationClient(GetMockedAppSchedulerClient()); + service_->LaunchApplication(record); + EXPECT_EQ(record->GetState(), ApplicationState::APP_STATE_READY); + APP_LOGI("AmsAppRunningRecordTest LaunchAbilityForApp_002 end"); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: When server LaunchApplication and LaunchAbility. + * EnvConditions: NA + * CaseDescription: Test abnormal case of LaunchApplication with wrong state. + */ +HWTEST_F(AmsAppRunningRecordTest, LaunchAbilityForApp_003, TestSize.Level0) +{ + APP_LOGI("AmsAppRunningRecordTest LaunchAbilityForApp_003 start"); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + RecordQueryResult result; + Profile profile; + EXPECT_TRUE(service_ != nullptr); + + std::shared_ptr record = + service_->GetOrCreateAppRunningRecord(GetMockToken(), appInfo, abilityInfo, GetTestProcessName(), 0, result); + record->SetState(ApplicationState::APP_STATE_READY); + record->SetApplicationClient(GetMockedAppSchedulerClient()); + auto abilityRecord = record->GetAbilityRunningRecord(GetTestAbilityName()); + EXPECT_TRUE(abilityRecord != nullptr); + + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleLaunchApplication(_)).Times(0); + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleLaunchAbility(_, _)).Times(0); + service_->LaunchApplication(record); + EXPECT_EQ(record->GetState(), ApplicationState::APP_STATE_READY); + APP_LOGI("AmsAppRunningRecordTest LaunchAbilityForApp_003 end"); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: When server LaunchApplication and LaunchAbility. + * EnvConditions: NA + * CaseDescription: Test normal case of LoadAbility after LaunchAbility and LaunchApplication. + */ +HWTEST_F(AmsAppRunningRecordTest, LaunchAbilityForApp_004, TestSize.Level0) +{ + APP_LOGI("AmsAppRunningRecordTest LaunchAbilityForApp_004 start"); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + abilityInfo->process = GetTestAppName(); + + auto abilityInfo2 = std::make_shared(); + abilityInfo2->name = GetTestAbilityName() + "_1"; + abilityInfo2->applicationName = GetTestAppName(); + abilityInfo2->process = GetTestAppName(); + + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + appInfo->bundleName = GetTestAppName(); + + RecordQueryResult result; + Profile profile; + EXPECT_TRUE(service_ != nullptr); + + std::shared_ptr record = + service_->GetOrCreateAppRunningRecord(GetMockToken(), appInfo, abilityInfo, GetTestAppName(), 0, result); + auto abilityRecord = record->GetAbilityRunningRecord(GetTestAbilityName()); + EXPECT_TRUE(abilityRecord != nullptr); + + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleLaunchApplication(_)).Times(1); + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleLaunchAbility(_, _)).Times(1); + record->SetApplicationClient(GetMockedAppSchedulerClient()); + service_->LaunchApplication(record); + EXPECT_EQ(record->GetState(), ApplicationState::APP_STATE_READY); + + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleLaunchApplication(_)).Times(0); + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleLaunchAbility(_, _)).Times(1); + sptr token2 = new (std::nothrow) MockAbilityToken(); + service_->LoadAbility(token2, nullptr, abilityInfo2, appInfo); + APP_LOGI("AmsAppRunningRecordTest LaunchAbilityForApp_004 end"); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: NA + * FunctionPoints: When server LaunchApplication and LaunchAbility. + * EnvConditions: NA + * CaseDescription: Test normal case of multiple LaunchAbility with wrong state after LaunchApplication. + */ +HWTEST_F(AmsAppRunningRecordTest, LaunchAbilityForApp_005, TestSize.Level0) +{ + APP_LOGI("AmsAppRunningRecordTest LaunchAbilityForApp_005 start"); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + auto abilityInfo2 = std::make_shared(); + abilityInfo2->name = GetTestAbilityName() + "_1"; + abilityInfo2->applicationName = GetTestAppName(); + auto abilityInfo3 = std::make_shared(); + abilityInfo3->name = GetTestAbilityName() + "_2"; + abilityInfo3->applicationName = GetTestAppName(); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + RecordQueryResult result; + Profile profile; + const int EXPECT_ABILITY_LAUNCH_TIME = 2; + EXPECT_TRUE(service_ != nullptr); + + std::shared_ptr record = + service_->GetOrCreateAppRunningRecord(GetMockToken(), appInfo, abilityInfo, GetTestProcessName(), 0, result); + auto abilityRecord = record->GetAbilityRunningRecord(GetTestAbilityName()); + EXPECT_TRUE(abilityRecord != nullptr); + sptr token2 = new (std::nothrow) MockAbilityToken(); + auto abilityRecord2 = record->AddAbility(token2, abilityInfo2); + abilityRecord2->SetState(AbilityState::ABILITY_STATE_READY); + sptr token3 = new (std::nothrow) MockAbilityToken(); + auto abilityRecord3 = record->AddAbility(token3, abilityInfo3); + + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleLaunchApplication(_)).Times(1); + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleLaunchAbility(_, _)).Times(EXPECT_ABILITY_LAUNCH_TIME); + record->SetApplicationClient(GetMockedAppSchedulerClient()); + service_->LaunchApplication(record); + EXPECT_EQ(record->GetState(), ApplicationState::APP_STATE_READY); + APP_LOGI("AmsAppRunningRecordTest LaunchAbilityForApp_005 end"); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: AddAbility + * FunctionPoints: check params + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify the function AddAbility can check the invalid token param. + */ +HWTEST_F(AmsAppRunningRecordTest, AddAbility_001, TestSize.Level0) +{ + auto appRecord = GetTestAppRunningRecord(); + EXPECT_TRUE(appRecord); + + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->type = AbilityType::PAGE; + + EXPECT_EQ(nullptr, appRecord->AddAbility(nullptr, abilityInfo)); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: AddAbility + * FunctionPoints: check params + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify the function AddAbility can check the invalid abilityInfo param. + */ +HWTEST_F(AmsAppRunningRecordTest, AddAbility_002, TestSize.Level0) +{ + auto appRecord = GetTestAppRunningRecord(); + EXPECT_TRUE(appRecord); + + EXPECT_EQ(nullptr, appRecord->AddAbility(GetMockToken(), nullptr)); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: AddAbility + * FunctionPoints: check params + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify the function AddAbility can check the AbilityRecord which already existed. + */ +HWTEST_F(AmsAppRunningRecordTest, AddAbility_003, TestSize.Level0) +{ + auto appRecord = GetTestAppRunningRecord(); + EXPECT_TRUE(appRecord); + + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->type = AbilityType::PAGE; + + EXPECT_NE(nullptr, appRecord->AddAbility(GetMockToken(), abilityInfo)); + EXPECT_EQ(nullptr, appRecord->AddAbility(GetMockToken(), abilityInfo)); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: TerminateAbility + * FunctionPoints: check params + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify the function TerminateAbility can check the token which not added. + */ +HWTEST_F(AmsAppRunningRecordTest, TerminateAbility_001, TestSize.Level0) +{ + APP_LOGI("AmsAppRunningRecordTest TerminateAbility_001 start"); + + auto record = GetTestAppRunningRecord(); + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleCleanAbility(_)).Times(0); + record->TerminateAbility(GetMockToken()); + + APP_LOGI("AmsAppRunningRecordTest TerminateAbility_001 end"); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: TerminateAbility + * FunctionPoints: check params + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify the function TerminateAbility can check the state not in background. + */ +HWTEST_F(AmsAppRunningRecordTest, TerminateAbility_002, TestSize.Level0) +{ + APP_LOGI("AmsAppRunningRecordTest TerminateAbility_002 start"); + + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + auto record = GetTestAppRunningRecord(); + EXPECT_NE(nullptr, record->AddAbility(GetMockToken(), abilityInfo)); + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleCleanAbility(_)).Times(0); + record->TerminateAbility(GetMockToken()); + + APP_LOGI("AmsAppRunningRecordTest TerminateAbility_002 end"); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: AbilityTerminated + * FunctionPoints: check params + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify the function AbilityTerminated can check the token is nullptr. + */ +HWTEST_F(AmsAppRunningRecordTest, AbilityTerminated_001, TestSize.Level0) +{ + APP_LOGI("AmsAppRunningRecordTest AbilityTerminated_001 start"); + + auto record = GetTestAppRunningRecord(); + EXPECT_CALL(*mockAppSchedulerClient_, ScheduleTerminateApplication()).Times(0); + record->AbilityTerminated(nullptr); + + APP_LOGI("AmsAppRunningRecordTest AbilityTerminated_001 end"); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: GetAbilityRunningRecord + * FunctionPoints: check params + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify the function GetAbilityRunningRecord return nullptr when the ability doesn't added. + */ +HWTEST_F(AmsAppRunningRecordTest, GetAbilityRunningRecord_001, TestSize.Level0) +{ + APP_LOGI("AmsAppRunningRecordTest GetAbilityRunningRecord_001 start"); + + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + auto record = GetTestAppRunningRecord(); + EXPECT_NE(nullptr, record->AddAbility(GetMockToken(), abilityInfo)); + std::string abilityName = "not_exist_ability_name"; + EXPECT_EQ(nullptr, record->GetAbilityRunningRecord(abilityName)); + + APP_LOGI("AmsAppRunningRecordTest GetAbilityRunningRecord_001 end"); +} + +/* + * Feature: AMS + * Function: AppRunningRecord + * SubFunction: GetAbilityRunningRecordByToken + * FunctionPoints: check params + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify the function GetAbilityRunningRecordByToken can check token is nullptr. + */ +HWTEST_F(AmsAppRunningRecordTest, GetAbilityRunningRecordByToken_001, TestSize.Level0) +{ + APP_LOGI("AmsAppRunningRecordTest GetAbilityRunningRecordByToken_001 start"); + + auto record = GetTestAppRunningRecord(); + EXPECT_EQ(nullptr, record->GetAbilityRunningRecordByToken(nullptr)); + + APP_LOGI("AmsAppRunningRecordTest GetAbilityRunningRecordByToken_001 end"); +} +/* + * Feature: AMS + * Function: AppRunningRecord::SetUid, AppRunningRecord::GetUid() + * SubFunction: GetAbilityRunningRecordByToken + * FunctionPoints: check params + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify the function GetAbilityRunningRecordByToken can check token is nullptr. + */ + +HWTEST_F(AmsAppRunningRecordTest, SetUid_GetUid_001, TestSize.Level0) +{ + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + + RecordQueryResult result; + EXPECT_TRUE(service_ != nullptr); + auto record = + service_->GetOrCreateAppRunningRecord(GetMockToken(), appInfo, abilityInfo, GetTestProcessName(), 101, result); + + EXPECT_TRUE(record != nullptr); + record->SetUid(102); + + auto otherRecord = service_->GetAppRunningRecordByAppRecordId(record->GetRecordId()); + EXPECT_TRUE(record != nullptr); + + EXPECT_EQ(otherRecord->GetUid(), 102); +} + +/* + * Feature: AMS + * Function: OptimizerAbilityStateChanged + * SubFunction: OnAbilityStateChanged + * FunctionPoints: check params + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Record and optimize the current app status + */ + +HWTEST_F(AmsAppRunningRecordTest, OptimizerAbilityStateChanged_001, TestSize.Level0) +{} + +/* + * Feature: AMS + * Function: OnAbilityStateChanged + * SubFunction: App state switch + * FunctionPoints: check params + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Notify ability when the status of the app changes + */ + +HWTEST_F(AmsAppRunningRecordTest, OnAbilityStateChanged_001, TestSize.Level0) +{ + auto appRecord = GetTestAppRunningRecord(); + EXPECT_TRUE(appRecord); + + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + + auto abilityRecord = appRecord->AddAbility(GetMockToken(), abilityInfo); + EXPECT_NE(nullptr, abilityRecord); + + sptr callback = new (std::nothrow) MockAppStateCallback(); + EXPECT_CALL(*callback, OnAbilityRequestDone(_, _)).Times(0); + + appRecord->OnAbilityStateChanged(nullptr, AbilityState::ABILITY_STATE_FOREGROUND); + + EXPECT_NE(AbilityState::ABILITY_STATE_FOREGROUND, abilityRecord->GetState()); + + std::shared_ptr serviceInner; + serviceInner.reset(new (std::nothrow) AppMgrServiceInner()); + EXPECT_TRUE(serviceInner); + + EXPECT_CALL(*callback, OnAbilityRequestDone(_, _)).Times(2); + serviceInner->RegisterAppStateCallback(callback); + appRecord->SetAppMgrServiceInner(serviceInner); + + appRecord->OnAbilityStateChanged(abilityRecord, AbilityState::ABILITY_STATE_FOREGROUND); + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, abilityRecord->GetState()); + + appRecord->OnAbilityStateChanged(abilityRecord, AbilityState::ABILITY_STATE_BACKGROUND); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, abilityRecord->GetState()); +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/appmgr/test/unittest/ams_app_state_callback_test/BUILD.gn b/services/appmgr/test/unittest/ams_app_state_callback_test/BUILD.gn new file mode 100644 index 000000000..08f9f0886 --- /dev/null +++ b/services/appmgr/test/unittest/ams_app_state_callback_test/BUILD.gn @@ -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. + +import("//build/test.gni") +import("//foundation/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/appmgrservice" + +ohos_unittest("AmsAppStateCallbackTest") { + module_out_path = module_output_path + + sources = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core/src/appmgr/app_process_data.cpp", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core/src/appmgr/app_state_callback_host.cpp", + ] + + sources += [ "ams_app_state_callback_test.cpp" ] + + configs = [ + "//utils/native/base:utils_config", + "${services_path}/appmgr/test:appmgr_test_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${common_path}:libappexecfwk_common", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "//third_party/googletest:gmock_main", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":AmsAppStateCallbackTest" ] +} diff --git a/services/appmgr/test/unittest/ams_app_state_callback_test/ams_app_state_callback_test.cpp b/services/appmgr/test/unittest/ams_app_state_callback_test/ams_app_state_callback_test.cpp new file mode 100644 index 000000000..ea7ec8e57 --- /dev/null +++ b/services/appmgr/test/unittest/ams_app_state_callback_test/ams_app_state_callback_test.cpp @@ -0,0 +1,117 @@ +/* + * 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_state_callback_host.h" +#include +#include "app_mgr_constants.h" +#include "iapp_state_callback.h" +#include "app_process_data.h" +#include "mock_ability_token.h" + +using namespace testing::ext; +namespace OHOS { +namespace AppExecFwk { +class AmsAppStateCallBackTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); +}; + +void AmsAppStateCallBackTest::SetUpTestCase() +{} +void AmsAppStateCallBackTest::TearDownTestCase() +{} +void AmsAppStateCallBackTest::SetUp() +{} +void AmsAppStateCallBackTest::TearDown() +{} + +/* + * Feature: AppStateCallBackHost + * Function: AppStateCallBackHost + * SubFunction: OnRemoteRequest Function + * FunctionPoints: AppStateCallBackHost Onreceived interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if Onreceived works when app state changed. + */ +HWTEST_F(AmsAppStateCallBackTest, OnRemoteRequest_001, TestSize.Level0) +{ + sptr host(new AppStateCallbackHost()); + MessageParcel data; + MessageParcel reply; + MessageOption option{MessageOption::TF_ASYNC}; + AppProcessData processData; + processData.appName = "test_name"; + processData.pid = 1; + processData.appState = ApplicationState::APP_STATE_FOREGROUND; + data.WriteParcelable(&processData); + int32_t ret = 0; + EXPECT_EQ(0, ret); +} + +/* + * Feature: AppStateCallBackHost + * Function: AppStateCallBackHost + * SubFunction: OnRemoteRequest Function + * FunctionPoints: AppStateCallBackHost Onreceived interface + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if Onreceived works when ability request done. + */ +HWTEST_F(AmsAppStateCallBackTest, OnRemoteRequest_002, TestSize.Level0) +{ + sptr host(new AppStateCallbackHost()); + MessageParcel data; + MessageParcel reply; + MessageOption option{MessageOption::TF_ASYNC}; + sptr token = new MockAbilityToken(); + + data.WriteParcelable(token.GetRefPtr()); + int32_t abilityState = static_cast(AbilityState::ABILITY_STATE_FOREGROUND); + data.WriteInt32(abilityState); + int32_t ret = 0; + EXPECT_EQ(0, ret); +} + +/* +* Feature: AppProcessData +* Function: AppProcessData +* SubFunction: Marshalling and Unmarshalling +* FunctionPoints: Marshalling and Unmarshalling can work normal +* EnvConditions: Mobile that can run normal +* CaseDescription: 1. Verify process data can write to parcel. + 2. verify process data can read from parcel. +*/ +HWTEST_F(AmsAppStateCallBackTest, AppProcessData_001, TestSize.Level0) +{ + Parcel data; + AppProcessData processData; + processData.appName = "test_name"; + processData.pid = 1; + processData.appState = ApplicationState::APP_STATE_FOREGROUND; + + bool ret = processData.Marshalling(data); + EXPECT_EQ(true, ret); + + sptr newProcessData = AppProcessData::Unmarshalling(data); + EXPECT_NE(nullptr, newProcessData); + + EXPECT_EQ(processData.appName, newProcessData->appName); + EXPECT_EQ(processData.pid, newProcessData->pid); + EXPECT_EQ(processData.appState, newProcessData->appState); +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/appmgr/test/unittest/ams_app_workflow_test/BUILD.gn b/services/appmgr/test/unittest/ams_app_workflow_test/BUILD.gn new file mode 100644 index 000000000..91ffa8f34 --- /dev/null +++ b/services/appmgr/test/unittest/ams_app_workflow_test/BUILD.gn @@ -0,0 +1,72 @@ +# 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/appmgrservice" + +ohos_unittest("AmsWorkFlowTest") { + module_out_path = module_output_path + + include_dirs = [ + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include/", + "//foundation/distributedschedule/samgr/adapter/interfaces/innerkits/include/", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include/", + ] + + sources = [ + "${services_path}/appmgr/src/ability_running_record.cpp", + "${services_path}/appmgr/src/app_lifecycle_deal.cpp", + "${services_path}/appmgr/src/app_mgr_service_inner.cpp", + "${services_path}/appmgr/src/app_process_manager.cpp", + "${services_path}/appmgr/src/app_running_manager.cpp", + "${services_path}/appmgr/src/app_running_record.cpp", + "${services_path}/appmgr/src/app_spawn_client.cpp", + "${services_path}/appmgr/src/app_spawn_msg_wrapper.cpp", + "${services_path}/appmgr/src/app_spawn_socket.cpp", + "${services_path}/appmgr/src/cgroup_manager.cpp", + "${services_path}/appmgr/src/lmk_util.cpp", + "${services_path}/appmgr/src/lmkd_client.cpp", + "${services_path}/appmgr/src/process_optimizer.cpp", + "${services_path}/appmgr/src/process_optimizer_uba.cpp", + "${services_path}/appmgr/src/remote_client_manager.cpp", + ] + + sources += [ "ams_workflow_test.cpp" ] + + configs = [ "${libs_path}/libeventhandler:libeventhandler_config" ] + + deps = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${libs_path}/libeventhandler:libeventhandler_target", + "${services_path}/appmgr/test:appmgr_test_source", + "//base/startup/appspawn_standard:appspawn_socket_client", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler:libeventhandler", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":AmsWorkFlowTest" ] +} 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 new file mode 100644 index 000000000..f990c22d1 --- /dev/null +++ b/services/appmgr/test/unittest/ams_app_workflow_test/ams_workflow_test.cpp @@ -0,0 +1,877 @@ +/* + * 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_mgr_service_inner.h" +#include +#include +#include "iremote_object.h" +#include "refbase.h" +#include "app_launch_data.h" +#include "app_log_wrapper.h" +#include "mock_ability_token.h" +#include "mock_app_scheduler.h" +#include "mock_app_spawn_client.h" + +using namespace testing::ext; +using testing::_; +using testing::Return; +using testing::SetArgReferee; +namespace OHOS { +namespace AppExecFwk { +struct TestApplicationPreRecord { + TestApplicationPreRecord( + const std::shared_ptr &appRecord, const sptr &mockAppScheduler) + : appRecord_(appRecord), mockAppScheduler_(mockAppScheduler) + {} + + std::shared_ptr GetAbility(const sptr &token) const + { + return appRecord_->GetAbilityRunningRecordByToken(token); + } + + virtual ~TestApplicationPreRecord() + {} + + std::shared_ptr appRecord_; + sptr mockAppScheduler_; +}; + +pid_t g_mockPid = 0; +class AmsWorkFlowTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + +protected: + AbilityInfo CreateAbilityInfo(const std::string &ability, const std::string &app) const; + ApplicationInfo CreateApplication(const std::string &app) const; + sptr AddApplicationClient(const std::shared_ptr &appRecord) const; + TestApplicationPreRecord CreateTestApplicationRecord(const std::string &ability, const sptr &token, + const std::string &app, const AbilityState abilityState, const ApplicationState appState) const; + +protected: + std::unique_ptr serviceInner_; +}; + +void AmsWorkFlowTest::SetUpTestCase() +{} + +void AmsWorkFlowTest::TearDownTestCase() +{} + +void AmsWorkFlowTest::SetUp() +{ + serviceInner_ = std::make_unique(); +} + +void AmsWorkFlowTest::TearDown() +{ + g_mockPid = 0; +} + +AbilityInfo AmsWorkFlowTest::CreateAbilityInfo(const std::string &ability, const std::string &app) const +{ + AbilityInfo abilityInfo; + abilityInfo.name = "test_ability" + ability; + abilityInfo.applicationName = "test_app" + app; + return abilityInfo; +} + +ApplicationInfo AmsWorkFlowTest::CreateApplication(const std::string &app) const +{ + ApplicationInfo appInfo; + appInfo.name = "test_app" + app; + return appInfo; +} + +sptr AmsWorkFlowTest::AddApplicationClient(const std::shared_ptr &appRecord) const +{ + if (appRecord->GetApplicationClient()) { + return nullptr; + } + sptr mockAppScheduler = new (std::nothrow) MockAppScheduler(); + sptr client = iface_cast(mockAppScheduler.GetRefPtr()); + appRecord->SetApplicationClient(client); + return mockAppScheduler; +} + +// create one application that include one ability, and set state +TestApplicationPreRecord AmsWorkFlowTest::CreateTestApplicationRecord(const std::string &ability, + const sptr &token, const std::string &app, const AbilityState abilityState, + const ApplicationState appState) const +{ + RecordQueryResult result; + AbilityInfo abilityInfo = CreateAbilityInfo(ability, app); + ApplicationInfo appInfo = CreateApplication(app); + + auto appRecord = serviceInner_->GetOrCreateAppRunningRecord(token, + std::make_shared(appInfo), + std::make_shared(abilityInfo), + appInfo.name, + 0, + result); + if (!result.appExists) { + appRecord->GetPriorityObject()->SetPid(g_mockPid++); + } + EXPECT_NE(appRecord, nullptr); + auto abilityRecord = appRecord->GetAbilityRunningRecordByToken(token); + EXPECT_NE(abilityRecord, nullptr); + abilityRecord->SetState(abilityState); + appRecord->SetState(appState); + sptr mockAppScheduler = AddApplicationClient(appRecord); + + TestApplicationPreRecord testAppPreRecord(appRecord, mockAppScheduler); + return testAppPreRecord; +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: WorkFlow + * FunctionPoints: BackKey + * CaseDescription: when only one ability on foreground, previous is another app, simulate press back key + */ +HWTEST_F(AmsWorkFlowTest, BackKey_001, TestSize.Level0) +{ + APP_LOGI("AmsWorkFlowTest BackKey_001 start"); + sptr tokenA = new MockAbilityToken(); + TestApplicationPreRecord appA = CreateTestApplicationRecord( + "A", tokenA, "A", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + sptr tokenB = new MockAbilityToken(); + TestApplicationPreRecord appB = CreateTestApplicationRecord( + "B", tokenB, "B", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + EXPECT_CALL(*(appB.mockAppScheduler_), ScheduleForegroundApplication()).Times(1); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleBackgroundApplication()).Times(1); + + serviceInner_->UpdateAbilityState(tokenB, AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->ApplicationForegrounded(appB.appRecord_->GetRecordId()); + serviceInner_->UpdateAbilityState(tokenA, AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(appA.appRecord_->GetRecordId()); + + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, appB.GetAbility(tokenB)->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, appB.appRecord_->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, appA.GetAbility(tokenA)->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_BACKGROUND, appA.appRecord_->GetState()); + APP_LOGI("AmsWorkFlowTest BackKey_001 end"); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: WorkFlow + * FunctionPoints: BackKey + * CaseDescription: when only one ability on foreground, previous ability in same app, simulate press back key + */ +HWTEST_F(AmsWorkFlowTest, BackKey_002, TestSize.Level0) +{ + APP_LOGI("AmsWorkFlowTest BackKey_002 start"); + sptr tokenA = new MockAbilityToken(); + TestApplicationPreRecord appA = CreateTestApplicationRecord( + "A", tokenA, "A", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + sptr tokenB = new MockAbilityToken(); + CreateTestApplicationRecord( + "B", tokenB, "A", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_FOREGROUND); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleBackgroundApplication()).Times(0); + + serviceInner_->UpdateAbilityState(tokenB, AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->UpdateAbilityState(tokenA, AbilityState::ABILITY_STATE_BACKGROUND); + + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, appA.GetAbility(tokenA)->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, appA.GetAbility(tokenB)->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, appA.appRecord_->GetState()); + APP_LOGI("AmsWorkFlowTest BackKey_002 end"); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: WorkFlow + * FunctionPoints: BackKey + * CaseDescription: when two ability on foreground, previous ability in another app, simulate press back key + */ +HWTEST_F(AmsWorkFlowTest, BackKey_003, TestSize.Level0) +{ + APP_LOGI("AmsWorkFlowTest BackKey_003 start"); + sptr tokenA = new MockAbilityToken(); + TestApplicationPreRecord appA = CreateTestApplicationRecord( + "A", tokenA, "A", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + sptr tokenB = new MockAbilityToken(); + CreateTestApplicationRecord( + "B", tokenB, "A", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + sptr tokenC = new MockAbilityToken(); + TestApplicationPreRecord appC = CreateTestApplicationRecord( + "C", tokenC, "C", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + EXPECT_CALL(*(appC.mockAppScheduler_), ScheduleForegroundApplication()).Times(1); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleBackgroundApplication()).Times(1); + + serviceInner_->UpdateAbilityState(tokenC, AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->ApplicationForegrounded(appC.appRecord_->GetRecordId()); + serviceInner_->UpdateAbilityState(tokenA, AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->UpdateAbilityState(tokenB, AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(appA.appRecord_->GetRecordId()); + + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, appC.GetAbility(tokenC)->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, appC.appRecord_->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, appA.GetAbility(tokenA)->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, appA.GetAbility(tokenB)->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_BACKGROUND, appA.appRecord_->GetState()); + APP_LOGI("AmsWorkFlowTest BackKey_003 end"); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: WorkFlow + * FunctionPoints: BackKey + * CaseDescription: when two ability on foreground, previous is 2 ability in another app, simulate press back key + */ +HWTEST_F(AmsWorkFlowTest, BackKey_004, TestSize.Level0) +{ + APP_LOGI("AmsWorkFlowTest BackKey_004 start"); + sptr tokenA = new MockAbilityToken(); + TestApplicationPreRecord appA = CreateTestApplicationRecord( + "A", tokenA, "A", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + sptr tokenB = new MockAbilityToken(); + CreateTestApplicationRecord( + "B", tokenB, "A", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + sptr tokenC = new MockAbilityToken(); + TestApplicationPreRecord appC = CreateTestApplicationRecord( + "C", tokenC, "C", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + sptr tokenD = new MockAbilityToken(); + CreateTestApplicationRecord( + "D", tokenD, "C", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + EXPECT_CALL(*(appC.mockAppScheduler_), ScheduleForegroundApplication()).Times(1); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleBackgroundApplication()).Times(1); + + serviceInner_->UpdateAbilityState(tokenC, AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->ApplicationForegrounded(appC.appRecord_->GetRecordId()); + serviceInner_->UpdateAbilityState(tokenD, AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->UpdateAbilityState(tokenA, AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->UpdateAbilityState(tokenB, AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(appA.appRecord_->GetRecordId()); + + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, appC.GetAbility(tokenC)->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, appC.GetAbility(tokenD)->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, appC.appRecord_->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, appA.GetAbility(tokenA)->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, appA.GetAbility(tokenB)->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_BACKGROUND, appA.appRecord_->GetState()); + APP_LOGI("AmsWorkFlowTest BackKey_004 end"); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: WorkFlow + * FunctionPoints: BackKey + * CaseDescription: when only one ability on foreground, previous is another app, simulate press back key and exit app + */ +HWTEST_F(AmsWorkFlowTest, BackKey_005, TestSize.Level0) +{ + APP_LOGI("AmsWorkFlowTest BackKey_005 start"); + sptr tokenA = new MockAbilityToken(); + TestApplicationPreRecord appA = CreateTestApplicationRecord( + "A", tokenA, "A", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + sptr tokenB = new MockAbilityToken(); + TestApplicationPreRecord appB = CreateTestApplicationRecord( + "B", tokenB, "B", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + EXPECT_CALL(*(appB.mockAppScheduler_), ScheduleForegroundApplication()).Times(1); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleBackgroundApplication()).Times(1); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleCleanAbility(_)).Times(1); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleTerminateApplication()).Times(1); + + serviceInner_->UpdateAbilityState(tokenB, AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->ApplicationForegrounded(appB.appRecord_->GetRecordId()); + serviceInner_->UpdateAbilityState(tokenA, AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(appA.appRecord_->GetRecordId()); + serviceInner_->TerminateAbility(tokenA); + serviceInner_->AbilityTerminated(tokenA); + serviceInner_->ApplicationTerminated(appA.appRecord_->GetRecordId()); + + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, appB.GetAbility(tokenB)->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, appB.appRecord_->GetState()); + EXPECT_EQ(appA.GetAbility(tokenA), nullptr); + EXPECT_EQ(ApplicationState::APP_STATE_TERMINATED, appA.appRecord_->GetState()); + APP_LOGI("AmsWorkFlowTest BackKey_005 end"); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: WorkFlow + * FunctionPoints: BackKey + * CaseDescription: when two ability on foreground, previous is another app, simulate press back key and exit + */ +HWTEST_F(AmsWorkFlowTest, BackKey_006, TestSize.Level0) +{ + APP_LOGI("AmsWorkFlowTest BackKey_006 start"); + sptr tokenA = new MockAbilityToken(); + TestApplicationPreRecord appA = CreateTestApplicationRecord( + "A", tokenA, "A", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + sptr tokenB = new MockAbilityToken(); + CreateTestApplicationRecord( + "B", tokenB, "A", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + sptr tokenC = new MockAbilityToken(); + TestApplicationPreRecord appC = CreateTestApplicationRecord( + "C", tokenC, "C", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + EXPECT_CALL(*(appC.mockAppScheduler_), ScheduleForegroundApplication()).Times(1); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleBackgroundApplication()).Times(1); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleCleanAbility(_)).Times(2); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleTerminateApplication()).Times(1); + + serviceInner_->UpdateAbilityState(tokenC, AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->ApplicationForegrounded(appC.appRecord_->GetRecordId()); + serviceInner_->UpdateAbilityState(tokenA, AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->UpdateAbilityState(tokenB, AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(appA.appRecord_->GetRecordId()); + serviceInner_->TerminateAbility(tokenA); + serviceInner_->AbilityTerminated(tokenA); + serviceInner_->TerminateAbility(tokenB); + serviceInner_->AbilityTerminated(tokenB); + serviceInner_->ApplicationTerminated(appA.appRecord_->GetRecordId()); + + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, appC.GetAbility(tokenC)->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, appC.appRecord_->GetState()); + EXPECT_EQ(appA.GetAbility(tokenA), nullptr); + EXPECT_EQ(appA.GetAbility(tokenB), nullptr); + EXPECT_EQ(ApplicationState::APP_STATE_TERMINATED, appA.appRecord_->GetState()); + APP_LOGI("AmsWorkFlowTest BackKey_006 end"); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: WorkFlow + * FunctionPoints: BackKey + * CaseDescription: when two ability on foreground, previous is 2 abiltiy in another app, + * simulate press back key and exit + */ +HWTEST_F(AmsWorkFlowTest, BackKey_007, TestSize.Level0) +{ + APP_LOGI("AmsWorkFlowTest BackKey_007 start"); + sptr tokenA = new MockAbilityToken(); + TestApplicationPreRecord appA = CreateTestApplicationRecord( + "A", tokenA, "A", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + sptr tokenB = new MockAbilityToken(); + CreateTestApplicationRecord( + "B", tokenB, "A", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + sptr tokenC = new MockAbilityToken(); + TestApplicationPreRecord appC = CreateTestApplicationRecord( + "C", tokenC, "C", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + sptr tokenD = new MockAbilityToken(); + CreateTestApplicationRecord( + "D", tokenD, "C", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + EXPECT_CALL(*(appC.mockAppScheduler_), ScheduleForegroundApplication()).Times(1); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleBackgroundApplication()).Times(1); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleCleanAbility(_)).Times(2); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleTerminateApplication()).Times(1); + + serviceInner_->UpdateAbilityState(tokenC, AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->ApplicationForegrounded(appC.appRecord_->GetRecordId()); + serviceInner_->UpdateAbilityState(tokenD, AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->UpdateAbilityState(tokenA, AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->UpdateAbilityState(tokenB, AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(appA.appRecord_->GetRecordId()); + serviceInner_->TerminateAbility(tokenA); + serviceInner_->AbilityTerminated(tokenA); + serviceInner_->TerminateAbility(tokenB); + serviceInner_->AbilityTerminated(tokenB); + serviceInner_->ApplicationTerminated(appA.appRecord_->GetRecordId()); + + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, appC.GetAbility(tokenC)->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, appC.GetAbility(tokenD)->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, appC.appRecord_->GetState()); + EXPECT_EQ(appA.GetAbility(tokenA), nullptr); + EXPECT_EQ(appA.GetAbility(tokenB), nullptr); + EXPECT_EQ(ApplicationState::APP_STATE_TERMINATED, appA.appRecord_->GetState()); + APP_LOGI("AmsWorkFlowTest BackKey_007 end"); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: WorkFlow + * FunctionPoints: ScreenOff + * CaseDescription: when only one ability on foreground, simulate screenoff + */ +HWTEST_F(AmsWorkFlowTest, ScreenOff_001, TestSize.Level0) +{ + APP_LOGI("AmsWorkFlowTest ScreenOff_001 start"); + sptr tokenA = new MockAbilityToken(); + TestApplicationPreRecord appA = CreateTestApplicationRecord( + "A", tokenA, "A", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleBackgroundApplication()).Times(1); + + serviceInner_->UpdateAbilityState(tokenA, AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(appA.appRecord_->GetRecordId()); + + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, appA.GetAbility(tokenA)->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_BACKGROUND, appA.appRecord_->GetState()); + APP_LOGI("AmsWorkFlowTest ScreenOff_001 end"); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: WorkFlow + * FunctionPoints: ScreenOff + * CaseDescription: when multiple ability on foreground, simulate screenoff + */ +HWTEST_F(AmsWorkFlowTest, ScreenOff_002, TestSize.Level0) +{ + APP_LOGI("AmsWorkFlowTest ScreenOff_002 start"); + sptr tokenA = new MockAbilityToken(); + TestApplicationPreRecord appA = CreateTestApplicationRecord( + "A", tokenA, "A", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + sptr tokenB = new MockAbilityToken(); + CreateTestApplicationRecord( + "B", tokenB, "A", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleBackgroundApplication()).Times(1); + + serviceInner_->UpdateAbilityState(tokenA, AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->UpdateAbilityState(tokenB, AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(appA.appRecord_->GetRecordId()); + + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, appA.GetAbility(tokenA)->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, appA.GetAbility(tokenB)->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_BACKGROUND, appA.appRecord_->GetState()); + APP_LOGI("AmsWorkFlowTest ScreenOff_002 end"); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: WorkFlow + * FunctionPoints: ScreenOff + * CaseDescription: when one ability on foreground, another ability in same app is background, simulate screenoff + */ +HWTEST_F(AmsWorkFlowTest, ScreenOff_003, TestSize.Level0) +{ + APP_LOGI("AmsWorkFlowTest ScreenOff_003 start"); + sptr tokenA = new MockAbilityToken(); + TestApplicationPreRecord appA = CreateTestApplicationRecord( + "A", tokenA, "A", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + sptr tokenB = new MockAbilityToken(); + CreateTestApplicationRecord( + "B", tokenB, "A", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_FOREGROUND); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleBackgroundApplication()).Times(1); + + serviceInner_->UpdateAbilityState(tokenA, AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(appA.appRecord_->GetRecordId()); + + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, appA.GetAbility(tokenA)->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, appA.GetAbility(tokenB)->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_BACKGROUND, appA.appRecord_->GetState()); + APP_LOGI("AmsWorkFlowTest ScreenOff_003 end"); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: WorkFlow + * FunctionPoints: ScreenOff + * CaseDescription: when only one ability on foreground, simulate screenoff and exit + */ +HWTEST_F(AmsWorkFlowTest, ScreenOff_004, TestSize.Level0) +{ + APP_LOGI("AmsWorkFlowTest ScreenOff_004 start"); + sptr tokenA = new MockAbilityToken(); + TestApplicationPreRecord appA = CreateTestApplicationRecord( + "A", tokenA, "A", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleBackgroundApplication()).Times(1); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleCleanAbility(_)).Times(1); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleTerminateApplication()).Times(1); + + serviceInner_->UpdateAbilityState(tokenA, AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(appA.appRecord_->GetRecordId()); + serviceInner_->TerminateAbility(tokenA); + serviceInner_->AbilityTerminated(tokenA); + serviceInner_->ApplicationTerminated(appA.appRecord_->GetRecordId()); + + EXPECT_EQ(appA.GetAbility(tokenA), nullptr); + EXPECT_EQ(ApplicationState::APP_STATE_TERMINATED, appA.appRecord_->GetState()); + APP_LOGI("AmsWorkFlowTest ScreenOff_004 end"); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: WorkFlow + * FunctionPoints: ScreenOff + * CaseDescription: when multiple ability on foreground, simulate screenoff and exit + */ +HWTEST_F(AmsWorkFlowTest, ScreenOff_005, TestSize.Level0) +{ + APP_LOGI("AmsWorkFlowTest ScreenOff_005 start"); + sptr tokenA = new MockAbilityToken(); + TestApplicationPreRecord appA = CreateTestApplicationRecord( + "A", tokenA, "A", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + sptr tokenB = new MockAbilityToken(); + CreateTestApplicationRecord( + "B", tokenB, "A", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleBackgroundApplication()).Times(1); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleCleanAbility(_)).Times(2); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleTerminateApplication()).Times(1); + + serviceInner_->UpdateAbilityState(tokenA, AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->UpdateAbilityState(tokenB, AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(appA.appRecord_->GetRecordId()); + serviceInner_->TerminateAbility(tokenA); + serviceInner_->AbilityTerminated(tokenA); + serviceInner_->TerminateAbility(tokenB); + serviceInner_->AbilityTerminated(tokenB); + serviceInner_->ApplicationTerminated(appA.appRecord_->GetRecordId()); + + EXPECT_EQ(appA.GetAbility(tokenA), nullptr); + EXPECT_EQ(appA.GetAbility(tokenB), nullptr); + EXPECT_EQ(ApplicationState::APP_STATE_TERMINATED, appA.appRecord_->GetState()); + APP_LOGI("AmsWorkFlowTest ScreenOff_005 end"); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: WorkFlow + * FunctionPoints: ScreenOff + * CaseDescription: when one ability on foreground, another ability in same app is background, + * simulate screenoff and exit + */ +HWTEST_F(AmsWorkFlowTest, ScreenOff_006, TestSize.Level0) +{ + APP_LOGI("AmsWorkFlowTest ScreenOff_006 start"); + sptr tokenA = new MockAbilityToken(); + TestApplicationPreRecord appA = CreateTestApplicationRecord( + "A", tokenA, "A", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + sptr tokenB = new MockAbilityToken(); + CreateTestApplicationRecord( + "B", tokenB, "A", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_FOREGROUND); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleBackgroundApplication()).Times(1); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleCleanAbility(_)).Times(2); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleTerminateApplication()).Times(1); + + serviceInner_->UpdateAbilityState(tokenA, AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(appA.appRecord_->GetRecordId()); + serviceInner_->TerminateAbility(tokenA); + serviceInner_->AbilityTerminated(tokenA); + serviceInner_->TerminateAbility(tokenB); + serviceInner_->AbilityTerminated(tokenB); + serviceInner_->ApplicationTerminated(appA.appRecord_->GetRecordId()); + + EXPECT_EQ(appA.GetAbility(tokenA), nullptr); + EXPECT_EQ(appA.GetAbility(tokenB), nullptr); + EXPECT_EQ(ApplicationState::APP_STATE_TERMINATED, appA.appRecord_->GetState()); + APP_LOGI("AmsWorkFlowTest ScreenOff_006 end"); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: WorkFlow + * FunctionPoints: ScreenOn + * CaseDescription: when only one ability on background, simulate screen on + */ +HWTEST_F(AmsWorkFlowTest, ScreenOn_001, TestSize.Level0) +{ + APP_LOGI("AmsWorkFlowTest ScreenOn_001 start"); + sptr tokenA = new MockAbilityToken(); + TestApplicationPreRecord appA = CreateTestApplicationRecord( + "A", tokenA, "A", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleForegroundApplication()).Times(1); + + serviceInner_->UpdateAbilityState(tokenA, AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->ApplicationForegrounded(appA.appRecord_->GetRecordId()); + + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, appA.GetAbility(tokenA)->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, appA.appRecord_->GetState()); + APP_LOGI("AmsWorkFlowTest ScreenOn_001 end"); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: WorkFlow + * FunctionPoints: ScreenOn + * CaseDescription: when multiple abilities on backgroud, previous is one ability, simulate screen on + */ +HWTEST_F(AmsWorkFlowTest, ScreenOn_002, TestSize.Level0) +{ + APP_LOGI("AmsWorkFlowTest ScreenOn_002 start"); + sptr tokenA = new MockAbilityToken(); + TestApplicationPreRecord appA = CreateTestApplicationRecord( + "A", tokenA, "A", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + sptr tokenB = new MockAbilityToken(); + CreateTestApplicationRecord( + "B", tokenB, "A", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleForegroundApplication()).Times(1); + + serviceInner_->UpdateAbilityState(tokenA, AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->ApplicationForegrounded(appA.appRecord_->GetRecordId()); + + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, appA.GetAbility(tokenA)->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, appA.GetAbility(tokenB)->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, appA.appRecord_->GetState()); + APP_LOGI("AmsWorkFlowTest ScreenOn_002 end"); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: WorkFlow + * FunctionPoints: ScreenOn + * CaseDescription: when multiple abilities on backgroud, all abilities are previous, simulate screen on + */ +HWTEST_F(AmsWorkFlowTest, ScreenOn_003, TestSize.Level0) +{ + APP_LOGI("AmsWorkFlowTest ScreenOn_003 start"); + sptr tokenA = new MockAbilityToken(); + TestApplicationPreRecord appA = CreateTestApplicationRecord( + "A", tokenA, "A", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + sptr tokenB = new MockAbilityToken(); + CreateTestApplicationRecord( + "B", tokenB, "A", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleForegroundApplication()).Times(1); + + serviceInner_->UpdateAbilityState(tokenA, AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->ApplicationForegrounded(appA.appRecord_->GetRecordId()); + serviceInner_->UpdateAbilityState(tokenB, AbilityState::ABILITY_STATE_FOREGROUND); + + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, appA.GetAbility(tokenA)->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, appA.GetAbility(tokenB)->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, appA.appRecord_->GetState()); + APP_LOGI("AmsWorkFlowTest ScreenOn_003 end"); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: WorkFlow + * FunctionPoints: ChangeAbility + * CaseDescription: when one ability on foreground, request to load another ability of the same Application + */ +HWTEST_F(AmsWorkFlowTest, ChangeAbility_001, TestSize.Level0) +{ + APP_LOGD("AmsWorkFlowTest ChangeAbility_001 start"); + sptr tokenA = new MockAbilityToken(); + TestApplicationPreRecord appA = CreateTestApplicationRecord( + "A", tokenA, "A", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + sptr tokenB = new MockAbilityToken(); + CreateTestApplicationRecord( + "B", tokenB, "A", AbilityState::ABILITY_STATE_READY, ApplicationState::APP_STATE_FOREGROUND); + + serviceInner_->UpdateAbilityState(tokenB, AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->UpdateAbilityState(tokenA, AbilityState::ABILITY_STATE_BACKGROUND); + + std::shared_ptr abilityA = appA.GetAbility(tokenA); + std::shared_ptr abilityB = appA.GetAbility(tokenB); + EXPECT_EQ(abilityA->GetAbilityInfo()->applicationName, abilityB->GetAbilityInfo()->applicationName); + + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, appA.GetAbility(tokenB)->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, appA.GetAbility(tokenA)->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, appA.appRecord_->GetState()); + + auto abilities = appA.appRecord_->GetAbilities(); + EXPECT_NE(nullptr, abilities[tokenA]); + EXPECT_NE(nullptr, abilities[tokenB]); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: WorkFlow + * FunctionPoints: ChangeAbility + * CaseDescription: when two ability on foreground, request to load another ability of the same Application + */ +HWTEST_F(AmsWorkFlowTest, ChangeAbility_002, TestSize.Level0) +{ + APP_LOGD("AmsWorkFlowTest ChangeAbility_001 start"); + sptr tokenA = new MockAbilityToken(); + TestApplicationPreRecord appA = CreateTestApplicationRecord( + "A", tokenA, "A", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + sptr tokenB = new MockAbilityToken(); + CreateTestApplicationRecord( + "B", tokenB, "A", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + sptr tokenC = new MockAbilityToken(); + CreateTestApplicationRecord( + "C", tokenC, "A", AbilityState::ABILITY_STATE_READY, ApplicationState::APP_STATE_FOREGROUND); + + serviceInner_->UpdateAbilityState(tokenC, AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->UpdateAbilityState(tokenB, AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->UpdateAbilityState(tokenA, AbilityState::ABILITY_STATE_BACKGROUND); + + std::shared_ptr abilityA = appA.GetAbility(tokenA); + std::shared_ptr abilityB = appA.GetAbility(tokenB); + std::shared_ptr abilityC = appA.GetAbility(tokenC); + EXPECT_EQ(abilityA->GetAbilityInfo()->applicationName, abilityB->GetAbilityInfo()->applicationName); + EXPECT_EQ(abilityC->GetAbilityInfo()->applicationName, abilityB->GetAbilityInfo()->applicationName); + + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, appA.GetAbility(tokenC)->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, appA.GetAbility(tokenB)->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, appA.GetAbility(tokenA)->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, appA.appRecord_->GetState()); + + auto abilities = appA.appRecord_->GetAbilities(); + EXPECT_NE(nullptr, abilities[tokenA]); + EXPECT_NE(nullptr, abilities[tokenB]); + EXPECT_NE(nullptr, abilities[tokenC]); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: WorkFlow + * FunctionPoints: ChangeAbility + * CaseDescription: when one ability on foreground, request to load another ability of the another Application + */ +HWTEST_F(AmsWorkFlowTest, ChangeAbility_003, TestSize.Level0) +{ + APP_LOGD("AmsWorkFlowTest ChangeAbility_001 start"); + sptr tokenA = new MockAbilityToken(); + TestApplicationPreRecord appA = CreateTestApplicationRecord( + "A", tokenA, "A", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + sptr tokenB = new MockAbilityToken(); + TestApplicationPreRecord appB = CreateTestApplicationRecord( + "B", tokenB, "B", AbilityState::ABILITY_STATE_READY, ApplicationState::APP_STATE_READY); + + EXPECT_CALL(*(appB.mockAppScheduler_), ScheduleForegroundApplication()).Times(1); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleBackgroundApplication()).Times(1); + + serviceInner_->UpdateAbilityState(tokenB, AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->ApplicationForegrounded(appB.appRecord_->GetRecordId()); + serviceInner_->UpdateAbilityState(tokenA, AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(appA.appRecord_->GetRecordId()); + + std::shared_ptr abilityA = appA.GetAbility(tokenA); + std::shared_ptr abilityB = appB.GetAbility(tokenB); + EXPECT_NE(abilityA->GetAbilityInfo()->applicationName, abilityB->GetAbilityInfo()->applicationName); + + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, appB.GetAbility(tokenB)->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, appB.appRecord_->GetState()); + + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, appA.GetAbility(tokenA)->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_BACKGROUND, appA.appRecord_->GetState()); + + auto abilitiesA = appA.appRecord_->GetAbilities(); + auto abilitiesB = appB.appRecord_->GetAbilities(); + EXPECT_NE(nullptr, abilitiesA[tokenA]); + EXPECT_NE(nullptr, abilitiesB[tokenB]); + pid_t pidA = appA.appRecord_->GetPriorityObject()->GetPid(); + pid_t pidB = appB.appRecord_->GetPriorityObject()->GetPid(); + EXPECT_NE(pidA, pidB); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: WorkFlow + * FunctionPoints: ChangeAbility + * CaseDescription: when two ability on foreground, request to load another ability of the another Application + */ +HWTEST_F(AmsWorkFlowTest, ChangeAbility_004, TestSize.Level0) +{ + APP_LOGD("AmsWorkFlowTest ChangeAbility_004 start"); + sptr tokenA = new MockAbilityToken(); + TestApplicationPreRecord appA = CreateTestApplicationRecord( + "A", tokenA, "A", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + sptr tokenB = new MockAbilityToken(); + CreateTestApplicationRecord( + "B", tokenB, "A", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + sptr tokenC = new MockAbilityToken(); + TestApplicationPreRecord appC = CreateTestApplicationRecord( + "C", tokenC, "C", AbilityState::ABILITY_STATE_READY, ApplicationState::APP_STATE_READY); + + EXPECT_CALL(*(appC.mockAppScheduler_), ScheduleForegroundApplication()).Times(1); + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleBackgroundApplication()).Times(1); + + serviceInner_->UpdateAbilityState(tokenC, AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->ApplicationForegrounded(appC.appRecord_->GetRecordId()); + + serviceInner_->UpdateAbilityState(tokenB, AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->UpdateAbilityState(tokenA, AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(appA.appRecord_->GetRecordId()); + + std::shared_ptr abilityA = appA.GetAbility(tokenA); + std::shared_ptr abilityB = appA.GetAbility(tokenB); + std::shared_ptr abilityC = appC.GetAbility(tokenC); + EXPECT_EQ(abilityA->GetAbilityInfo()->applicationName, abilityB->GetAbilityInfo()->applicationName); + EXPECT_NE(abilityC->GetAbilityInfo()->applicationName, abilityB->GetAbilityInfo()->applicationName); + + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, appC.GetAbility(tokenC)->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, appC.appRecord_->GetState()); + + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, appA.GetAbility(tokenA)->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, appA.GetAbility(tokenB)->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_BACKGROUND, appA.appRecord_->GetState()); + + auto abilitiesA = appA.appRecord_->GetAbilities(); + auto abilitiesC = appC.appRecord_->GetAbilities(); + EXPECT_NE(nullptr, abilitiesA[tokenA]); + EXPECT_NE(nullptr, abilitiesA[tokenB]); + EXPECT_NE(nullptr, abilitiesC[tokenC]); + + pid_t pidA = appA.appRecord_->GetPriorityObject()->GetPid(); + pid_t pidC = appC.appRecord_->GetPriorityObject()->GetPid(); + EXPECT_NE(pidA, pidC); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: WorkFlow + * FunctionPoints: ChangeAbility + * CaseDescription: when a application on background, request to load another ability of the same Application + */ +HWTEST_F(AmsWorkFlowTest, ChangeAbility_005, TestSize.Level0) +{ + APP_LOGD("AmsWorkFlowTest ChangeAbility_004 start"); + sptr tokenA = new MockAbilityToken(); + TestApplicationPreRecord appA = CreateTestApplicationRecord( + "A", tokenA, "A", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + sptr tokenB = new MockAbilityToken(); + TestApplicationPreRecord appB = CreateTestApplicationRecord( + "B", tokenB, "B", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + sptr tokenC = new MockAbilityToken(); + CreateTestApplicationRecord("C", tokenC, "B", AbilityState::ABILITY_STATE_READY, ApplicationState::APP_STATE_READY); + + EXPECT_CALL(*(appA.mockAppScheduler_), ScheduleBackgroundApplication()).Times(1); + EXPECT_CALL(*(appB.mockAppScheduler_), ScheduleForegroundApplication()).Times(1); + + serviceInner_->UpdateAbilityState(tokenC, AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->UpdateAbilityState(tokenB, AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationForegrounded(appB.appRecord_->GetRecordId()); + + serviceInner_->UpdateAbilityState(tokenA, AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(appA.appRecord_->GetRecordId()); + + std::shared_ptr abilityB = appB.GetAbility(tokenB); + std::shared_ptr abilityC = appB.GetAbility(tokenC); + EXPECT_EQ(abilityC->GetAbilityInfo()->applicationName, abilityB->GetAbilityInfo()->applicationName); + + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, appB.GetAbility(tokenC)->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, appB.GetAbility(tokenB)->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, appB.appRecord_->GetState()); + + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, appA.GetAbility(tokenA)->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_BACKGROUND, appA.appRecord_->GetState()); + + auto abilitiesA = appA.appRecord_->GetAbilities(); + auto abilitiesB = appB.appRecord_->GetAbilities(); + EXPECT_NE(nullptr, abilitiesA[tokenA]); + EXPECT_NE(nullptr, abilitiesB[tokenB]); + EXPECT_NE(nullptr, abilitiesB[tokenC]); +} +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/appmgr/test/unittest/ams_ipc_interface_test/BUILD.gn b/services/appmgr/test/unittest/ams_ipc_interface_test/BUILD.gn new file mode 100644 index 000000000..8754af89b --- /dev/null +++ b/services/appmgr/test/unittest/ams_ipc_interface_test/BUILD.gn @@ -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. + +import("//build/test.gni") +import("//foundation/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/appmgrservice" + +ohos_unittest("AmsIpcAppSchedulerInterfaceTest") { + module_out_path = module_output_path + + sources = [ "ams_ipc_appscheduler_interface_test.cpp" ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ "${services_path}/appmgr/test:appmgr_test_source" ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +ohos_unittest("AmsIpcAppMgrInterfaceTest") { + module_out_path = module_output_path + + sources = [ "ams_ipc_appmgr_interface_test.cpp" ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${services_path}/appmgr/test:appmgr_test_source", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ + ":AmsIpcAppMgrInterfaceTest", + ":AmsIpcAppSchedulerInterfaceTest", + ] +} diff --git a/services/appmgr/test/unittest/ams_ipc_interface_test/ams_ipc_appmgr_interface_test.cpp b/services/appmgr/test/unittest/ams_ipc_interface_test/ams_ipc_appmgr_interface_test.cpp new file mode 100644 index 000000000..fc5d9e028 --- /dev/null +++ b/services/appmgr/test/unittest/ams_ipc_interface_test/ams_ipc_appmgr_interface_test.cpp @@ -0,0 +1,265 @@ +/* + * 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_scheduler_proxy.h" +#include +#include +#include "errors.h" +#include "ipc_types.h" +#include "app_log_wrapper.h" +#include "app_mgr_proxy.h" +#include "app_record_id.h" +#include "mock_application.h" +#include "mock_app_mgr_service.h" + +using namespace testing::ext; +using namespace OHOS::AppExecFwk; +using OHOS::iface_cast; +using OHOS::sptr; +using testing::_; +using testing::Invoke; +using testing::InvokeWithoutArgs; +using testing::Return; + +class AmsIpcAppMgrInterfaceTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); +}; + +void AmsIpcAppMgrInterfaceTest::SetUpTestCase() +{} + +void AmsIpcAppMgrInterfaceTest::TearDownTestCase() +{} + +void AmsIpcAppMgrInterfaceTest::SetUp() +{} + +void AmsIpcAppMgrInterfaceTest::TearDown() +{} + +/* + * Feature: AMS + * Function: IPC + * SubFunction: appmgr interface + * FunctionPoints: interface + * CaseDescription: test interface of AttachApplication + */ +HWTEST_F(AmsIpcAppMgrInterfaceTest, Interface_001, TestSize.Level0) +{ + APP_LOGD("AppMgrIpcInterfaceTest_AppMgr_001 start"); + sptr mockAppMgr(new MockAppMgrService()); + sptr appMgrClient = iface_cast(mockAppMgr); + sptr app(new MockApplication()); + + EXPECT_CALL(*mockAppMgr, AttachApplication(_)) + .WillOnce(InvokeWithoutArgs(mockAppMgr.GetRefPtr(), &MockAppMgrService::Post)); + appMgrClient->AttachApplication(app); + mockAppMgr->Wait(); + APP_LOGD("AppMgrIpcInterfaceTest_AppMgr_001 end"); +} + +/* + * Feature: AMS + * Function: IPC + * SubFunction: appmgr interface + * FunctionPoints: interface + * CaseDescription: test interface of ApplicationForegrounded + */ +HWTEST_F(AmsIpcAppMgrInterfaceTest, Interface_002, TestSize.Level0) +{ + APP_LOGD("AppMgrIpcInterfaceTest_AppMgr_002 start"); + sptr mockAppMgr(new MockAppMgrService()); + sptr appMgrClient = iface_cast(mockAppMgr); + + EXPECT_CALL(*mockAppMgr, ApplicationForegrounded(_)) + .WillOnce(InvokeWithoutArgs(mockAppMgr.GetRefPtr(), &MockAppMgrService::Post)); + auto recordId = AppRecordId::Create(); + appMgrClient->ApplicationForegrounded(recordId); + mockAppMgr->Wait(); + APP_LOGD("AppMgrIpcInterfaceTest_AppMgr_002 end"); +} + +/* + * Feature: AMS + * Function: IPC + * SubFunction: appmgr interface + * FunctionPoints: interface + * CaseDescription: test interface of ApplicationBackgrounded + */ +HWTEST_F(AmsIpcAppMgrInterfaceTest, Interface_003, TestSize.Level0) +{ + APP_LOGD("AppMgrIpcInterfaceTest_AppMgr_003 start"); + sptr mockAppMgr(new MockAppMgrService()); + sptr appMgrClient = iface_cast(mockAppMgr); + + EXPECT_CALL(*mockAppMgr, ApplicationBackgrounded(_)) + .WillOnce(InvokeWithoutArgs(mockAppMgr.GetRefPtr(), &MockAppMgrService::Post)); + auto recordId = AppRecordId::Create(); + appMgrClient->ApplicationBackgrounded(recordId); + mockAppMgr->Wait(); + APP_LOGD("AppMgrIpcInterfaceTest_AppMgr_003 end"); +} + +/* + * Feature: AMS + * Function: IPC + * SubFunction: appmgr interface + * FunctionPoints: interface + * CaseDescription: test interface of ApplicationTerminated + */ +HWTEST_F(AmsIpcAppMgrInterfaceTest, Interface_004, TestSize.Level0) +{ + APP_LOGD("AppMgrIpcInterfaceTest_AppMgr_004 start"); + sptr mockAppMgr(new MockAppMgrService()); + sptr appMgrClient = iface_cast(mockAppMgr); + + EXPECT_CALL(*mockAppMgr, ApplicationTerminated(_)) + .WillOnce(InvokeWithoutArgs(mockAppMgr.GetRefPtr(), &MockAppMgrService::Post)); + auto recordId = AppRecordId::Create(); + appMgrClient->ApplicationTerminated(recordId); + mockAppMgr->Wait(); + APP_LOGD("AppMgrIpcInterfaceTest_AppMgr_004 end"); +} + +/* + * Feature: AMS + * Function: IPC + * SubFunction: appmgr interface + * FunctionPoints: interface + * CaseDescription: test interface of CheckPermission + */ +HWTEST_F(AmsIpcAppMgrInterfaceTest, Interface_005, TestSize.Level0) +{ + APP_LOGD("AppMgrIpcInterfaceTest_AppMgr_005 start"); + sptr mockAppMgr(new MockAppMgrService()); + sptr appMgrClient = iface_cast(mockAppMgr); + + EXPECT_CALL(*mockAppMgr, CheckPermission(_, _)).Times(1).WillOnce(Return(OHOS::NO_ERROR)); + auto recordId = AppRecordId::Create(); + int ret = appMgrClient->CheckPermission(recordId, "write"); + EXPECT_EQ(OHOS::NO_ERROR, ret); + + EXPECT_CALL(*mockAppMgr, CheckPermission(_, _)).Times(1).WillOnce(Return(OHOS::NO_ERROR)); + ret = appMgrClient->CheckPermission(recordId, "read"); + EXPECT_EQ(OHOS::NO_ERROR, ret); + + EXPECT_CALL(*mockAppMgr, CheckPermission(_, _)).Times(1).WillOnce(Return(OHOS::ERR_INVALID_STATE)); + ret = appMgrClient->CheckPermission(recordId, "location"); + EXPECT_EQ(OHOS::ERR_INVALID_STATE, ret); + + APP_LOGD("AppMgrIpcInterfaceTest_AppMgr_005 end"); +} + +/* + * Feature: AMS + * Function: IPC + * SubFunction: appmgr interface + * FunctionPoints: interface + * CaseDescription: test IPC can transact data + */ +HWTEST_F(AmsIpcAppMgrInterfaceTest, Interface_006, TestSize.Level0) +{ + APP_LOGD("AppMgrIpcInterfaceTest_AppMgr_006 start"); + sptr mockAppMgr(new MockAppMgrService()); + sptr appMgrClient = iface_cast(mockAppMgr); + + EXPECT_CALL(*mockAppMgr, CheckPermission(_, _)) + .Times(1) + .WillOnce(Invoke(mockAppMgr.GetRefPtr(), &MockAppMgrService::CheckPermissionImpl)); + auto recordId = AppRecordId::Create(); + int ret = appMgrClient->CheckPermission(recordId, "write"); + EXPECT_EQ(0, ret); + EXPECT_EQ("write", mockAppMgr->GetData()); + APP_LOGD("AppMgrIpcInterfaceTest_AppMgr_006 end"); +} + +/* + * Feature: AMS + * Function: IPC + * SubFunction: appmgr interface + * FunctionPoints: KillApplication interface + * CaseDescription: test IPC can transact data + */ +HWTEST_F(AmsIpcAppMgrInterfaceTest, ClearUpApplicationData_008, TestSize.Level0) +{ + APP_LOGD("ClearUpApplicationData_008 start"); + + sptr mockAppMgr(new MockAppMgrService()); + sptr appMgrClient = iface_cast(mockAppMgr); + + EXPECT_CALL(*mockAppMgr, ClearUpApplicationData(_)).Times(1); + + appMgrClient->ClearUpApplicationData("PROCESS"); + + APP_LOGD("ClearUpApplicationData_008 end"); +} + +/* + * Feature: AMS + * Function: IPC IsBackgroundRunningRestricted + * SubFunction: appmgr interface + * FunctionPoints: Check background operation + * CaseDescription: test IPC can transact data + */ +HWTEST_F(AmsIpcAppMgrInterfaceTest, IsBackgroundRunningRestricted_009, TestSize.Level0) +{ + APP_LOGD("IsBackgroundRunningRestricted_009 start"); + + sptr mockAppMgr(new MockAppMgrService()); + sptr appMgrClient = iface_cast(mockAppMgr); + + EXPECT_CALL(*mockAppMgr, IsBackgroundRunningRestricted(_)).Times(1).WillOnce(Return(OHOS::NO_ERROR)); + + int32_t ret = appMgrClient->IsBackgroundRunningRestricted("PROCESS"); + + EXPECT_EQ(ret, OHOS::NO_ERROR); + // Returns 32 when the bundle name is empty + EXPECT_CALL(*mockAppMgr, IsBackgroundRunningRestricted(_)).Times(1).WillOnce(Return(32)); + ret = appMgrClient->IsBackgroundRunningRestricted(""); + + EXPECT_EQ(ret, 32); + APP_LOGD("IsBackgroundRunningRestricted_009 end"); +} + +/* + * Feature: AMS + * Function: IPC + * SubFunction: appmgr interface + * FunctionPoints: KillApplication interface + * CaseDescription: test IPC can transact data + */ +HWTEST_F(AmsIpcAppMgrInterfaceTest, GetAllRunningProcesses_010, TestSize.Level0) +{ + APP_LOGD("GetAllRunningProcesses_009 start"); + + sptr mockAppMgr(new MockAppMgrService()); + sptr appMgrClient = iface_cast(mockAppMgr); + + EXPECT_CALL(*mockAppMgr, GetAllRunningProcesses(_)).Times(1).WillOnce(Return(OHOS::ERR_NULL_OBJECT)); + + std::shared_ptr runningProcessInfo; + int32_t ret = appMgrClient->GetAllRunningProcesses(runningProcessInfo); + EXPECT_EQ(ret, OHOS::ERR_NULL_OBJECT); + + EXPECT_CALL(*mockAppMgr, GetAllRunningProcesses(_)).Times(1).WillOnce(Return(OHOS::ERR_NONE)); + ret = appMgrClient->GetAllRunningProcesses(runningProcessInfo); + EXPECT_EQ(ret, OHOS::ERR_NONE); + + APP_LOGD("GetAllRunningProcesses_009 end"); +} \ No newline at end of file diff --git a/services/appmgr/test/unittest/ams_ipc_interface_test/ams_ipc_appscheduler_interface_test.cpp b/services/appmgr/test/unittest/ams_ipc_interface_test/ams_ipc_appscheduler_interface_test.cpp new file mode 100644 index 000000000..13c113d46 --- /dev/null +++ b/services/appmgr/test/unittest/ams_ipc_interface_test/ams_ipc_appscheduler_interface_test.cpp @@ -0,0 +1,287 @@ +/* + * 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_scheduler_proxy.h" +#include +#include "app_log_wrapper.h" +#include "app_scheduler_host.h" +#include "mock_ability_token.h" +#include "mock_application.h" + +using namespace testing::ext; +using namespace OHOS::AppExecFwk; +using OHOS::iface_cast; +using OHOS::sptr; +using testing::_; +using testing::Invoke; +using testing::InvokeWithoutArgs; + +class AmsIpcAppSchedulerInterfaceTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + sptr GetMockToken() const + { + return mock_token_; + } + +private: + sptr mock_token_; +}; + +void AmsIpcAppSchedulerInterfaceTest::SetUpTestCase() +{} + +void AmsIpcAppSchedulerInterfaceTest::TearDownTestCase() +{} + +void AmsIpcAppSchedulerInterfaceTest::SetUp() +{ + mock_token_ = new (std::nothrow) MockAbilityToken(); +} + +void AmsIpcAppSchedulerInterfaceTest::TearDown() +{} + +/* + * Feature: AppScheduler ZIDL interface + * Function: ScheduleForegroundApplication + * SubFunction: NA + * FunctionPoints: ScheduleForegroundApplication interface + * EnvConditions: Application already running + * CaseDescription: Test the interface ScheduleForegroundApplication of AppScheduler + */ +HWTEST_F(AmsIpcAppSchedulerInterfaceTest, Interface_001, TestSize.Level0) +{ + APP_LOGD("AppSchedulerInterfaceTest_001 start"); + sptr mockApplication(new MockApplication()); + sptr client = iface_cast(mockApplication); + + EXPECT_CALL(*mockApplication, ScheduleForegroundApplication()) + .Times(1) + .WillOnce(InvokeWithoutArgs(mockApplication.GetRefPtr(), &MockApplication::Post)); + client->ScheduleForegroundApplication(); + mockApplication->Wait(); + APP_LOGD("AppSchedulerInterfaceTest_001 end"); +} + +/* + * Feature: AppScheduler ZIDL interface + * Function: ScheduleBackgroundApplication + * SubFunction: NA + * FunctionPoints: scheduleBackgroundApplication interface + * EnvConditions: Application already running + * CaseDescription: Test the interface ScheduleBackgroundApplication of AppScheduler + */ +HWTEST_F(AmsIpcAppSchedulerInterfaceTest, Interface_002, TestSize.Level0) +{ + APP_LOGD("AppSchedulerInterfaceTest_002 start"); + sptr mockApplication(new MockApplication()); + sptr client = iface_cast(mockApplication); + + EXPECT_CALL(*mockApplication, ScheduleBackgroundApplication()) + .Times(1) + .WillOnce(InvokeWithoutArgs(mockApplication.GetRefPtr(), &MockApplication::Post)); + client->ScheduleBackgroundApplication(); + mockApplication->Wait(); + APP_LOGD("AppSchedulerInterfaceTest_002 end"); +} + +/* + * Feature: AppScheduler ZIDL interface + * Function: ScheduleTerminateApplication + * SubFunction: NA + * FunctionPoints: scheduleTerminateApplication interface + * EnvConditions: Application already running + * CaseDescription: Test the interface ScheduleTerminateApplication of AppScheduler + */ +HWTEST_F(AmsIpcAppSchedulerInterfaceTest, Interface_003, TestSize.Level0) +{ + APP_LOGD("AppSchedulerInterfaceTest_003 start"); + sptr mockApplication(new MockApplication()); + sptr client = iface_cast(mockApplication); + + EXPECT_CALL(*mockApplication, ScheduleTerminateApplication()) + .Times(1) + .WillOnce(InvokeWithoutArgs(mockApplication.GetRefPtr(), &MockApplication::Post)); + client->ScheduleTerminateApplication(); + mockApplication->Wait(); + APP_LOGD("AppSchedulerInterfaceTest_003 end"); +} + +/* + * Feature: AppScheduler ZIDL interface + * Function: ScheduleShrinkMemory + * SubFunction: NA + * FunctionPoints: scheduleShrinkMemory interface + * EnvConditions: Application already running + * CaseDescription: Test the interface ScheduleShrinkMemory of AppScheduler + */ +HWTEST_F(AmsIpcAppSchedulerInterfaceTest, Interface_004, TestSize.Level0) +{ + APP_LOGD("AppSchedulerInterfaceTest_004 start"); + sptr mockApplication(new MockApplication()); + sptr client = iface_cast(mockApplication); + int level = 1; + + EXPECT_CALL(*mockApplication, ScheduleShrinkMemory(_)) + .Times(1) + .WillOnce(Invoke(mockApplication.GetRefPtr(), &MockApplication::ShrinkMemory)); + client->ScheduleShrinkMemory(level); + mockApplication->Wait(); + + int shrinkLevel = mockApplication->GetShrinkLevel(); + EXPECT_EQ(level, shrinkLevel); + APP_LOGD("AppSchedulerInterfaceTest_004 end"); +} + +/* + * Feature: AppScheduler ZIDL interface + * Function: ScheduleLowMemory + * SubFunction: NA + * FunctionPoints: scheduleLowMemory interface + * EnvConditions: Application already running + * CaseDescription: Test the interface ScheduleLowMemory of AppScheduler + */ +HWTEST_F(AmsIpcAppSchedulerInterfaceTest, Interface_005, TestSize.Level0) +{ + APP_LOGD("AppSchedulerInterfaceTest_005 start"); + sptr mockApplication(new MockApplication()); + sptr client = iface_cast(mockApplication); + + EXPECT_CALL(*mockApplication, ScheduleLowMemory()) + .Times(1) + .WillOnce(InvokeWithoutArgs(mockApplication.GetRefPtr(), &MockApplication::Post)); + client->ScheduleLowMemory(); + mockApplication->Wait(); + APP_LOGD("AppSchedulerInterfaceTest_005 end"); +} + +/* + * Feature: AppScheduler ZIDL interface + * Function: ScheduleLaunchApplication + * SubFunction: NA + * FunctionPoints: scheduleLaunchApplication interface + * EnvConditions: Application already running + * CaseDescription: Test the interface ScheduleLaunchApplication of AppScheduler + */ +HWTEST_F(AmsIpcAppSchedulerInterfaceTest, Interface_006, TestSize.Level0) +{ + APP_LOGD("AppSchedulerInterfaceTest_006 start"); + sptr mockApplication(new MockApplication()); + sptr client = iface_cast(mockApplication); + + std::string applicationName("mockApplicationInfo"); + ApplicationInfo applicationInfo; + applicationInfo.name = applicationName; + std::string profileName("mockProfile"); + Profile profile(profileName); + std::string processName("mockProcessInfo"); + ProcessInfo processInfo(processName, 1); + + AppLaunchData launchData; + launchData.SetApplicationInfo(applicationInfo); + launchData.SetProfile(profile); + launchData.SetProcessInfo(processInfo); + + EXPECT_CALL(*mockApplication, ScheduleLaunchApplication(_)) + .Times(1) + .WillOnce(Invoke(mockApplication.GetRefPtr(), &MockApplication::LaunchApplication)); + client->ScheduleLaunchApplication(launchData); + mockApplication->Wait(); + + bool isEqual = mockApplication->CompareAppLaunchData(launchData); + EXPECT_EQ(true, isEqual); + APP_LOGD("AppSchedulerInterfaceTest_006 end"); +} + +/* + * Feature: AppScheduler ZIDL interface + * Function: ScheduleLaunchAbility + * SubFunction: NA + * FunctionPoints: scheduleLaunchAbility interface + * EnvConditions: Application already running + * CaseDescription: Test the interface ScheduleLaunchAbility of AppScheduler + */ +HWTEST_F(AmsIpcAppSchedulerInterfaceTest, Interface_007, TestSize.Level0) +{ + APP_LOGD("AppSchedulerInterfaceTest_007 start"); + sptr mockApplication(new MockApplication()); + sptr client = iface_cast(mockApplication); + std::string abilityName("mockAbilityInfo"); + AbilityInfo info; + info.name = abilityName; + + EXPECT_CALL(*mockApplication, ScheduleLaunchAbility(_, _)) + .Times(1) + .WillOnce(Invoke(mockApplication.GetRefPtr(), &MockApplication::LaunchAbility)); + client->ScheduleLaunchAbility(info, GetMockToken()); + mockApplication->Wait(); + + bool isEqual = mockApplication->CompareAbilityInfo(info); + EXPECT_EQ(true, isEqual); + APP_LOGD("AppSchedulerInterfaceTest_007 end"); +} + +/* + * Feature: AppScheduler ZIDL interface + * Function: ScheduleCleanAbility + * SubFunction: NA + * FunctionPoints: scheduleCleanAbility interface + * EnvConditions: Application already running + * CaseDescription: Test the interface ScheduleCleanAbility of AppScheduler + */ +HWTEST_F(AmsIpcAppSchedulerInterfaceTest, Interface_008, TestSize.Level0) +{ + APP_LOGD("AppSchedulerInterfaceTest_008 start"); + sptr mockApplication(new MockApplication()); + sptr client = iface_cast(mockApplication); + + EXPECT_CALL(*mockApplication, ScheduleCleanAbility(_)) + .Times(1) + .WillOnce(InvokeWithoutArgs(mockApplication.GetRefPtr(), &MockApplication::Post)); + client->ScheduleCleanAbility(GetMockToken()); + mockApplication->Wait(); + APP_LOGD("AppSchedulerInterfaceTest_008 end"); +} + +/* + * Feature: AppScheduler ZIDL interface + * Function: ScheduleCleanAbility + * SubFunction: NA + * FunctionPoints: scheduleProfileChanged interface + * EnvConditions: Application already running + * CaseDescription: Test the interface ScheduleProfileChanged of AppScheduler + */ +HWTEST_F(AmsIpcAppSchedulerInterfaceTest, Interface_009, TestSize.Level0) +{ + APP_LOGD("AppSchedulerInterfaceTest_009 start"); + sptr mockApplication(new MockApplication()); + sptr client = iface_cast(mockApplication); + std::string profileName("mockProfile"); + Profile profile(profileName); + + EXPECT_CALL(*mockApplication, ScheduleProfileChanged(_)) + .Times(1) + .WillOnce(Invoke(mockApplication.GetRefPtr(), &MockApplication::ProfileChanged)); + client->ScheduleProfileChanged(profile); + mockApplication->Wait(); + + bool isEqual = mockApplication->CompareProfile(profile); + EXPECT_EQ(true, isEqual); + APP_LOGD("AppSchedulerInterfaceTest_009 end"); +} diff --git a/services/appmgr/test/unittest/ams_mgr_scheduler_test/BUILD.gn b/services/appmgr/test/unittest/ams_mgr_scheduler_test/BUILD.gn new file mode 100644 index 000000000..f4f470ac3 --- /dev/null +++ b/services/appmgr/test/unittest/ams_mgr_scheduler_test/BUILD.gn @@ -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. + +import("//build/test.gni") +import("//foundation/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/appmgrservice" + +ohos_unittest("AmsMgrSchedulerTest") { + module_out_path = module_output_path + + include_dirs = [ + "//foundation/aafwk/standard/interfaces/innerkits/base/include", + "//foundation/aafwk/standard/interfaces/innerkits/want/include", + "//foundation/appexecfwk/standard/services/appmgr/include", + "//foundation/distributedschedule/dmsfwk/services/dtbschedmgr/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include", + ] + + sources = [ "${services_path}/appmgr/src/ams_mgr_scheduler.cpp" ] + + sources += [ "ams_mgr_scheduler_test.cpp" ] + + configs = [ + "${services_path}/appmgr/test:appmgr_test_config", + "${libs_path}/libeventhandler:libeventhandler_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${libs_path}/libeventhandler:libeventhandler_target", + "${services_path}/appmgr/test:appmgr_test_source", + "//foundation/appexecfwk/standard/services/appmgr:libams", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":AmsMgrSchedulerTest" ] +} diff --git a/services/appmgr/test/unittest/ams_mgr_scheduler_test/ams_mgr_scheduler_test.cpp b/services/appmgr/test/unittest/ams_mgr_scheduler_test/ams_mgr_scheduler_test.cpp new file mode 100644 index 000000000..d1568e48e --- /dev/null +++ b/services/appmgr/test/unittest/ams_mgr_scheduler_test/ams_mgr_scheduler_test.cpp @@ -0,0 +1,409 @@ +/* + * 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 +#include "ams_mgr_scheduler.h" +#undef private + +#include "app_log_wrapper.h" +#include "mock_app_mgr_service_inner.h" +#include "mock_ability_token.h" +#include "app_state_callback_host.h" + +using namespace testing; +using namespace testing::ext; +using testing::_; +using testing::Return; + +namespace OHOS { +namespace AppExecFwk { + +class AmsMgrSchedulerTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + +public: +protected: + static const std::string GetTestAppName() + { + return "test_app_name"; + } + static const std::string GetTestAbilityName() + { + return "test_ability_name"; + } + + std::shared_ptr GetMockAppMgrServiceInner(); + std::shared_ptr GetAmsEventHandler(); + +private: + std::shared_ptr mockAppMgrServiceInner_; + std::shared_ptr amsEventHandler_; +}; + +void AmsMgrSchedulerTest::SetUpTestCase() +{} + +void AmsMgrSchedulerTest::TearDownTestCase() +{} + +void AmsMgrSchedulerTest::SetUp() +{} + +void AmsMgrSchedulerTest::TearDown() +{ + amsEventHandler_.reset(); + mockAppMgrServiceInner_.reset(); +} + +std::shared_ptr AmsMgrSchedulerTest::GetMockAppMgrServiceInner() +{ + if (!mockAppMgrServiceInner_) { + mockAppMgrServiceInner_ = std::make_shared(); + } + return mockAppMgrServiceInner_; +} + +std::shared_ptr AmsMgrSchedulerTest::GetAmsEventHandler() +{ + if (!amsEventHandler_) { + auto mockAppMgrServiceInner = GetMockAppMgrServiceInner(); + amsEventHandler_ = + std::make_shared(EventRunner::Create("AmsMgrSchedulerTest"), mockAppMgrServiceInner); + } + return amsEventHandler_; +} + +/* + * Feature: AMS + * Function: AmsMgrScheduler + * SubFunction: LoadAbility + * FunctionPoints: Act normal + * EnvConditions: Mobile that can run ohos test framework. + * CaseDescription: Verify the function LoadAbility can works. + */ +HWTEST_F(AmsMgrSchedulerTest, AmsMgrScheduler_001, TestSize.Level0) +{ + APP_LOGD("AmsMgrScheduler_001 start."); + + auto mockAppMgrServiceInner = GetMockAppMgrServiceInner(); + auto amsEventHandler = GetAmsEventHandler(); + std::unique_ptr amsMgrScheduler = + std::make_unique(mockAppMgrServiceInner, amsEventHandler); + + sptr token = new MockAbilityToken(); + sptr preToken = new MockAbilityToken(); + std::shared_ptr abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + std::shared_ptr applicationInfo = std::make_shared(); + applicationInfo->name = GetTestAppName(); + + EXPECT_CALL(*mockAppMgrServiceInner, LoadAbility(_, _, _, _)) + .WillOnce(InvokeWithoutArgs(mockAppMgrServiceInner.get(), &MockAppMgrServiceInner::Post)); + amsMgrScheduler->LoadAbility(token, preToken, abilityInfo, applicationInfo); + mockAppMgrServiceInner->Wait(); + + APP_LOGD("AmsMgrScheduler_001 end."); +} + +/* + * Feature: AMS + * Function: AmsMgrScheduler + * SubFunction: LoadAbility + * FunctionPoints: Check params + * EnvConditions: Mobile that can run ohos test framework. + * CaseDescription: Verify the function LoadAbility can check appInfo and abilityInfo. + */ +HWTEST_F(AmsMgrSchedulerTest, AmsMgrScheduler_002, TestSize.Level0) +{ + APP_LOGD("AmsMgrScheduler_002 start."); + + auto mockAppMgrServiceInner = std::make_shared(); + auto eventRunner = EventRunner::Create("AmsMgrSchedulerTest"); + auto amsEventHandler = std::make_shared(eventRunner, mockAppMgrServiceInner); + std::unique_ptr amsMgrScheduler = + std::make_unique(mockAppMgrServiceInner, amsEventHandler); + + sptr token = new MockAbilityToken(); + sptr preToken = new MockAbilityToken(); + std::shared_ptr abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + std::shared_ptr applicationInfo = std::make_shared(); + applicationInfo->name = GetTestAppName(); + + // check token parameter + EXPECT_CALL(*mockAppMgrServiceInner, LoadAbility(_, _, _, _)).Times(0); + amsMgrScheduler->LoadAbility(token, preToken, nullptr, applicationInfo); + + // check pretoken parameter + EXPECT_CALL(*mockAppMgrServiceInner, LoadAbility(_, _, _, _)).Times(0); + amsMgrScheduler->LoadAbility(token, preToken, abilityInfo, nullptr); + + APP_LOGD("AmsMgrScheduler_002 end."); +} + +/* + * Feature: AMS + * Function: AmsMgrScheduler + * SubFunction: UpdateAbilityState + * FunctionPoints: Act normal + * EnvConditions: Mobile that can run ohos test framework. + * CaseDescription: Verify the function UpdateAbilityState can works. + */ +HWTEST_F(AmsMgrSchedulerTest, AmsMgrScheduler_003, TestSize.Level0) +{ + APP_LOGD("AmsMgrScheduler_003 start."); + + auto mockAppMgrServiceInner = GetMockAppMgrServiceInner(); + auto amsEventHandler = GetAmsEventHandler(); + std::unique_ptr amsMgrScheduler = + std::make_unique(mockAppMgrServiceInner, amsEventHandler); + + sptr token = new MockAbilityToken(); + AbilityState abilityState = AbilityState::ABILITY_STATE_BEGIN; + + EXPECT_CALL(*mockAppMgrServiceInner, UpdateAbilityState(_, _)) + .WillOnce(InvokeWithoutArgs(mockAppMgrServiceInner.get(), &MockAppMgrServiceInner::Post)); + amsMgrScheduler->UpdateAbilityState(token, abilityState); + mockAppMgrServiceInner->Wait(); + + APP_LOGD("AmsMgrScheduler_003 end."); +} + +/* + * Feature: AMS + * Function: AmsMgrScheduler + * SubFunction: TerminateAbility + * FunctionPoints: Act normal + * EnvConditions: Mobile that can run ohos test framework. + * CaseDescription: Verify the function TerminateAbility can works. + */ +HWTEST_F(AmsMgrSchedulerTest, AmsMgrScheduler_004, TestSize.Level0) +{ + APP_LOGD("AmsMgrScheduler_004 start."); + + auto mockAppMgrServiceInner = GetMockAppMgrServiceInner(); + auto amsEventHandler = GetAmsEventHandler(); + std::unique_ptr amsMgrScheduler = + std::make_unique(mockAppMgrServiceInner, amsEventHandler); + sptr token = new MockAbilityToken(); + + EXPECT_CALL(*mockAppMgrServiceInner, TerminateAbility(_)) + .WillOnce(InvokeWithoutArgs(mockAppMgrServiceInner.get(), &MockAppMgrServiceInner::Post)); + amsMgrScheduler->TerminateAbility(token); + mockAppMgrServiceInner->Wait(); + + APP_LOGD("AmsMgrScheduler_004 end."); +} + +/* + * Feature: AMS + * Function: AmsMgrScheduler + * SubFunction: RegisterAppStateCallback + * FunctionPoints: Act normal + * EnvConditions: Mobile that can run ohos test framework. + * CaseDescription: Verify the function RegisterAppStateCallback can works. + */ +HWTEST_F(AmsMgrSchedulerTest, AmsMgrScheduler_005, TestSize.Level0) +{ + APP_LOGD("AmsMgrScheduler_005 start."); + + auto mockAppMgrServiceInner = GetMockAppMgrServiceInner(); + auto amsEventHandler = GetAmsEventHandler(); + std::unique_ptr amsMgrScheduler = + std::make_unique(mockAppMgrServiceInner, amsEventHandler); + + sptr appStateCallbackHost = new AppStateCallbackHost(); + EXPECT_CALL(*mockAppMgrServiceInner, RegisterAppStateCallback(_)) + .WillOnce(InvokeWithoutArgs(mockAppMgrServiceInner.get(), &MockAppMgrServiceInner::Post)); + amsMgrScheduler->RegisterAppStateCallback(appStateCallbackHost); + mockAppMgrServiceInner->Wait(); + + APP_LOGD("AmsMgrScheduler_005 end."); +} + +/* + * Feature: AMS + * Function: AmsMgrScheduler + * SubFunction: Reset + * FunctionPoints: Act normal + * EnvConditions: Mobile that can run ohos test framework. + * CaseDescription: Verify the function Reset can works. + */ +HWTEST_F(AmsMgrSchedulerTest, AmsMgrScheduler_006, TestSize.Level0) +{ + APP_LOGD("AmsMgrScheduler_006 start."); + + auto mockAppMgrServiceInner = GetMockAppMgrServiceInner(); + auto amsEventHandler = GetAmsEventHandler(); + std::unique_ptr amsMgrScheduler = + std::make_unique(mockAppMgrServiceInner, amsEventHandler); + + sptr appStateCallbackHost = new AppStateCallbackHost(); + EXPECT_CALL(*mockAppMgrServiceInner, StopAllProcess()) + .WillOnce(InvokeWithoutArgs(mockAppMgrServiceInner.get(), &MockAppMgrServiceInner::Post)); + amsMgrScheduler->Reset(); + mockAppMgrServiceInner->Wait(); + + APP_LOGD("AmsMgrScheduler_006 end."); +} + +/* + * Feature: AMS + * Function: AmsMgrScheduler + * SubFunction: IsReady + * FunctionPoints: Check Params + * EnvConditions: Mobile that can run ohos test framework. + * CaseDescription: Verify the function IsReady can check params. + */ +HWTEST_F(AmsMgrSchedulerTest, AmsMgrScheduler_007, TestSize.Level0) +{ + APP_LOGD("AmsMgrScheduler_007 start."); + + auto mockAppMgrServiceInner = GetMockAppMgrServiceInner(); + auto amsEventHandler = GetAmsEventHandler(); + + // act normal + std::unique_ptr amsMgrScheduler = + std::make_unique(mockAppMgrServiceInner, amsEventHandler); + EXPECT_EQ(true, amsMgrScheduler->IsReady()); + + // check params AppMgrServiceInner + std::unique_ptr amsMgrScheduler2 = std::make_unique(nullptr, amsEventHandler); + EXPECT_EQ(false, amsMgrScheduler2->IsReady()); + + // check params AMSEventHandler + std::unique_ptr amsMgrScheduler3 = + std::make_unique(mockAppMgrServiceInner, nullptr); + EXPECT_EQ(false, amsMgrScheduler3->IsReady()); + + APP_LOGD("AmsMgrScheduler_007 end."); +} + +/* + * Feature: AMS + * Function: KillApplication + * SubFunction: IsReady + * FunctionPoints: Check Params + * EnvConditions: Mobile that can run ohos test framework. + * CaseDescription: Kill apps by name + */ +HWTEST_F(AmsMgrSchedulerTest, AmsMgrScheduler_008, TestSize.Level0) +{ + APP_LOGD("AmsMgrScheduler_008 start."); + + auto mockAppMgrServiceInner = GetMockAppMgrServiceInner(); + auto amsEventHandler = GetAmsEventHandler(); + + EXPECT_CALL(*mockAppMgrServiceInner, KillApplication(_)).Times(1).WillOnce(Return(ERR_OK)); + + // check params AppMgrServiceInner + std::unique_ptr amsMgrScheduler2 = std::make_unique(nullptr, amsEventHandler); + EXPECT_EQ(false, amsMgrScheduler2->IsReady()); + + EXPECT_EQ(ERR_INVALID_OPERATION, amsMgrScheduler2->KillApplication(GetTestAppName())); + + // check params AMSEventHandler + std::unique_ptr amsMgrScheduler3 = + std::make_unique(mockAppMgrServiceInner, nullptr); + EXPECT_EQ(false, amsMgrScheduler3->IsReady()); + + EXPECT_EQ(ERR_INVALID_OPERATION, amsMgrScheduler3->KillApplication(GetTestAppName())); + + // act normal + std::unique_ptr amsMgrScheduler4 = + std::make_unique(mockAppMgrServiceInner, amsEventHandler); + EXPECT_EQ(true, amsMgrScheduler4->IsReady()); + + EXPECT_EQ(ERR_OK, amsMgrScheduler4->KillApplication(GetTestAppName())); + + APP_LOGD("AmsMgrScheduler_008 end."); +} + +/* + * Feature: AMS + * Function: AbilityBehaviorAnalysis + * SubFunction: IsReady + * FunctionPoints: Check Params + * EnvConditions: Mobile that can run ohos test framework. + * CaseDescription: Optimize based on visibility and perception + */ +HWTEST_F(AmsMgrSchedulerTest, AmsMgrScheduler_009, TestSize.Level0) +{ + APP_LOGD("AmsMgrScheduler_009 start."); + + auto mockAppMgrServiceInner = GetMockAppMgrServiceInner(); + auto amsEventHandler = GetAmsEventHandler(); + std::unique_ptr amsMgrScheduler = + std::make_unique(mockAppMgrServiceInner, amsEventHandler); + EXPECT_EQ(true, amsMgrScheduler->IsReady()); + + EXPECT_CALL(*mockAppMgrServiceInner, AbilityBehaviorAnalysis(_, _, _, _, _)) + .Times(1) + .WillOnce(InvokeWithoutArgs(mockAppMgrServiceInner.get(), &MockAppMgrServiceInner::Post)); + + sptr token; + sptr preToken; + int32_t visibility = 0; + int32_t perceptibility = 0; + int32_t connectionState = 0; + + amsMgrScheduler->AbilityBehaviorAnalysis(token, preToken, visibility, perceptibility, connectionState); + + mockAppMgrServiceInner->Wait(); + + mockAppMgrServiceInner.reset(); + amsEventHandler.reset(); + + APP_LOGD("AmsMgrScheduler_009 end."); +} + +/* + * Feature: AMS + * Function: AbilityBehaviorAnalysis + * SubFunction: IsReady + * FunctionPoints: Check Params + * EnvConditions: Mobile that can run ohos test framework. + * CaseDescription: Optimize based on visibility and perception + */ +HWTEST_F(AmsMgrSchedulerTest, AmsMgrScheduler_010, TestSize.Level0) +{ + APP_LOGD("AmsMgrScheduler_010 start."); + + auto mockAppMgrServiceInner = GetMockAppMgrServiceInner(); + + std::unique_ptr amsMgrScheduler = std::make_unique(nullptr, nullptr); + EXPECT_EQ(false, amsMgrScheduler->IsReady()); + + EXPECT_CALL(*mockAppMgrServiceInner, AbilityBehaviorAnalysis(_, _, _, _, _)).Times(0); + + sptr token; + sptr preToken; + int32_t visibility = 0; + int32_t perceptibility = 0; + int32_t connectionState = 0; + + amsMgrScheduler->AbilityBehaviorAnalysis(token, preToken, visibility, perceptibility, connectionState); + + APP_LOGD("AmsMgrScheduler_010 end."); +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/appmgr/test/unittest/ams_recent_app_list_test/BUILD.gn b/services/appmgr/test/unittest/ams_recent_app_list_test/BUILD.gn new file mode 100644 index 000000000..ff0241d1b --- /dev/null +++ b/services/appmgr/test/unittest/ams_recent_app_list_test/BUILD.gn @@ -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. + +import("//build/test.gni") +import("//foundation/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/appmgrservice" +ohos_unittest("AmsRecentAppListTest") { + module_out_path = module_output_path + + include_dirs = [ + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include/", + "//foundation/distributedschedule/samgr/adapter/interfaces/innerkits/include/", + ] + + sources = [ + "${services_path}/appmgr/src/ability_running_record.cpp", + "${services_path}/appmgr/src/app_lifecycle_deal.cpp", + "${services_path}/appmgr/src/app_mgr_service_inner.cpp", + "${services_path}/appmgr/src/app_process_manager.cpp", + "${services_path}/appmgr/src/app_running_manager.cpp", + "${services_path}/appmgr/src/app_running_record.cpp", + "${services_path}/appmgr/src/app_spawn_client.cpp", + "${services_path}/appmgr/src/app_spawn_msg_wrapper.cpp", + "${services_path}/appmgr/src/app_spawn_socket.cpp", + "${services_path}/appmgr/src/cgroup_manager.cpp", + "${services_path}/appmgr/src/lmk_util.cpp", + "${services_path}/appmgr/src/lmkd_client.cpp", + "${services_path}/appmgr/src/process_optimizer.cpp", + "${services_path}/appmgr/src/process_optimizer_uba.cpp", + "${services_path}/appmgr/src/remote_client_manager.cpp", + "${services_path}/appmgr/test/mock/src/mock_bundle_manager.cpp", + ] + + sources += [ "ams_recent_app_list_test.cpp" ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + configs = [ "${libs_path}/libeventhandler:libeventhandler_config" ] + + deps = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${libs_path}/libeventhandler:libeventhandler_target", + "${services_path}/appmgr/test:appmgr_test_source", + "//base/startup/appspawn_standard:appspawn_socket_client", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler:libeventhandler", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":AmsRecentAppListTest" ] +} 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 new file mode 100644 index 000000000..600d39d12 --- /dev/null +++ b/services/appmgr/test/unittest/ams_recent_app_list_test/ams_recent_app_list_test.cpp @@ -0,0 +1,414 @@ +/* + * 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. + */ + +#define private public +#include "app_running_record.h" +#include "app_mgr_service_inner.h" +#undef private + +#include +#include +#include "iremote_object.h" +#include "refbase.h" +#include "mock_bundle_manager.h" +#include "mock_ability_token.h" +#include "mock_app_scheduler.h" +#include "mock_app_spawn_client.h" + +using namespace testing::ext; +using testing::_; +using testing::Return; +using testing::SetArgReferee; +namespace OHOS { +namespace AppExecFwk { +namespace { +const int32_t INDEX_NUM_1 = 1; +const int32_t INDEX_NUM_2 = 2; +const int32_t INDEX_NUM_3 = 3; +const int32_t PID_MAX = 0x8000; +} // namespace +class AmsRecentAppListTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + +protected: + const std::shared_ptr GetAbilityInfoByIndex(const int32_t index) const; + const std::shared_ptr GetApplicationByIndex(const int32_t index) const; + const std::shared_ptr GetAppRunningRecordByIndex(const int32_t index) const; + void StartProcessSuccess(const int32_t index) const; + + std::unique_ptr serviceInner_; + sptr mockToken_; + sptr mockBundleMgr; +}; + +void AmsRecentAppListTest::SetUpTestCase() +{} + +void AmsRecentAppListTest::TearDownTestCase() +{} + +void AmsRecentAppListTest::SetUp() +{ + serviceInner_.reset(new (std::nothrow) AppMgrServiceInner()); + mockBundleMgr = new (std::nothrow) BundleMgrService(); + serviceInner_->SetBundleManager(mockBundleMgr); +} + +void AmsRecentAppListTest::TearDown() +{} + +const std::shared_ptr AmsRecentAppListTest::GetAbilityInfoByIndex(const int32_t index) const +{ + std::shared_ptr abilityInfo = std::make_shared(); + abilityInfo->name = "test_ability" + std::to_string(index); + abilityInfo->applicationName = "test_app" + std::to_string(index); + return abilityInfo; +} + +const std::shared_ptr AmsRecentAppListTest::GetApplicationByIndex(const int32_t index) const +{ + std::shared_ptr appInfo = std::make_shared(); + appInfo->name = "test_app" + std::to_string(index); + appInfo->bundleName = "test_app" + std::to_string(index); + return appInfo; +} + +const std::shared_ptr AmsRecentAppListTest::GetAppRunningRecordByIndex(const int32_t index) const +{ + auto appInfo = GetApplicationByIndex(index); + auto appRecord = serviceInner_->GetAppRunningRecordByAppName(appInfo->name); + EXPECT_NE(nullptr, appRecord); + return appRecord; +} + +void AmsRecentAppListTest::StartProcessSuccess(const int32_t index) const +{ + pid_t pid = PID_MAX - index; + auto abilityInfo = GetAbilityInfoByIndex(index); + auto appInfo = GetApplicationByIndex(index); + sptr token = new (std::nothrow) MockAbilityToken(); + MockAppSpawnClient *mockClientPtr = new (std::nothrow) MockAppSpawnClient(); + ASSERT_TRUE(mockClientPtr); + + // mock start process success, and pid is right. + EXPECT_CALL(*mockClientPtr, StartProcess(_, _)).Times(1).WillOnce(DoAll(SetArgReferee<1>(pid), Return(ERR_OK))); + serviceInner_->SetAppSpawnClient(std::unique_ptr(mockClientPtr)); + + serviceInner_->LoadAbility(token, nullptr, abilityInfo, appInfo); + return; +} + +/* + * Feature: Ams + * Function: RecentAppList + * SubFunction: create + * FunctionPoints: Add app to RecentAppList when start a new process success. + * EnvConditions: RecentAppList is empty. + * CaseDescription: Verity ams can add app to RecentAppList success when start a new process success. + */ +HWTEST_F(AmsRecentAppListTest, Create_001, TestSize.Level0) +{ + // get the recent app list before test. + EXPECT_TRUE(serviceInner_->GetRecentAppList().empty()); + + for (int32_t index = INDEX_NUM_1; index <= INDEX_NUM_3; index++) { + StartProcessSuccess(index); + EXPECT_EQ(index, static_cast(serviceInner_->GetRecentAppList().size())); + } +} + +/* + * Feature: Ams + * Function: RecentAppList + * SubFunction: create + * FunctionPoints: The size of RecentAppList remains the same when start a new process failed. + * EnvConditions: RecentAppList is empty. + * CaseDescription: Verity ams can not add app to RecentAppList when start a new process failed. + */ +HWTEST_F(AmsRecentAppListTest, Create_002, TestSize.Level0) +{ + auto abilityInfo = GetAbilityInfoByIndex(1); + auto appInfo = GetApplicationByIndex(INDEX_NUM_1); + sptr token = new (std::nothrow) MockAbilityToken(); + EXPECT_TRUE(serviceInner_->GetRecentAppList().empty()); + + // mock start process failed. + MockAppSpawnClient *mockClientPtr = new (std::nothrow) MockAppSpawnClient(); + ASSERT_TRUE(mockClientPtr); + + EXPECT_CALL(*mockClientPtr, StartProcess(_, _)).WillOnce(Return(ERR_APPEXECFWK_ASSEMBLE_START_MSG_FAILED)); + serviceInner_->SetAppSpawnClient(std::unique_ptr(mockClientPtr)); + serviceInner_->LoadAbility(token, nullptr, abilityInfo, appInfo); + EXPECT_TRUE(serviceInner_->GetRecentAppList().empty()); +} + +/* + * Feature: Ams + * Function: RecentAppList + * SubFunction: create + * FunctionPoints: The size of RecentAppList remains the same when start an already exist process. + * EnvConditions: RecentAppList is empty. + * CaseDescription: Verity ams can not add app to RecentAppList when start an already exist process. + */ +HWTEST_F(AmsRecentAppListTest, Create_003, TestSize.Level0) +{ + EXPECT_TRUE(serviceInner_->GetRecentAppList().empty()); + + pid_t pid = INDEX_NUM_1; + auto abilityInfo = GetAbilityInfoByIndex(INDEX_NUM_1); + auto appInfo = GetApplicationByIndex(INDEX_NUM_1); + sptr token = new (std::nothrow) MockAbilityToken(); + MockAppSpawnClient *mockClientPtr = new (std::nothrow) MockAppSpawnClient(); + ASSERT_TRUE(mockClientPtr); + + // mock start process success, and pid is right. + EXPECT_CALL(*mockClientPtr, StartProcess(_, _)).Times(1).WillOnce(DoAll(SetArgReferee<1>(pid), Return(ERR_OK))); + serviceInner_->SetAppSpawnClient(std::unique_ptr(mockClientPtr)); + + serviceInner_->LoadAbility(token, nullptr, abilityInfo, appInfo); + EXPECT_EQ(INDEX_NUM_1, static_cast(serviceInner_->GetRecentAppList().size())); + + // Load ability1, start process 1 again. + serviceInner_->LoadAbility(token, nullptr, abilityInfo, appInfo); + EXPECT_EQ(INDEX_NUM_1, static_cast(serviceInner_->GetRecentAppList().size())); +} + +/* + * Feature: Ams + * Function: RecentAppList + * SubFunction: update + * FunctionPoints: Remove app from RecentAppList when app terminated. + * EnvConditions: RecentAppList has application. + * CaseDescription: Verity ams can remove app from RecentAppList when app terminated. + */ +HWTEST_F(AmsRecentAppListTest, Update_001, TestSize.Level0) +{ + StartProcessSuccess(INDEX_NUM_1); + EXPECT_EQ(INDEX_NUM_1, static_cast(serviceInner_->GetRecentAppList().size())); + auto appRecord = GetAppRunningRecordByIndex(INDEX_NUM_1); + appRecord->SetState(ApplicationState::APP_STATE_BACKGROUND); + sptr mockAppScheduler = new (std::nothrow) MockAppScheduler(); + sptr client = iface_cast(mockAppScheduler.GetRefPtr()); + appRecord->SetApplicationClient(client); + serviceInner_->ApplicationTerminated(appRecord->GetRecordId()); + EXPECT_TRUE(serviceInner_->GetRecentAppList().empty()); +} + +/* + * Feature: Ams + * Function: RecentAppList + * SubFunction: update + * FunctionPoints: Remove app from RecentAppList when app died. + * EnvConditions: RecentAppList has application. + * CaseDescription: Verity ams can remove app from RecentAppList when app died. + */ +HWTEST_F(AmsRecentAppListTest, Update_002, TestSize.Level0) +{ + StartProcessSuccess(INDEX_NUM_1); + EXPECT_EQ(INDEX_NUM_1, static_cast(serviceInner_->GetRecentAppList().size())); + auto appRecord = GetAppRunningRecordByIndex(INDEX_NUM_1); + + sptr mockAppScheduler = new (std::nothrow) MockAppScheduler(); + sptr client = iface_cast(mockAppScheduler.GetRefPtr()); + appRecord->SetApplicationClient(client); + sptr object = client->AsObject(); + wptr app = object; + serviceInner_->OnRemoteDied(app); + EXPECT_TRUE(serviceInner_->GetRecentAppList().empty()); +} + +/* + * Feature: Ams + * Function: RecentAppList + * SubFunction: update + * FunctionPoints: Push app front. + * EnvConditions: RecentAppList has application. + * CaseDescription: Verity ams can push app front when app is foregrounded. + */ +HWTEST_F(AmsRecentAppListTest, Update_003, TestSize.Level0) +{ + for (int32_t index = INDEX_NUM_1; index <= INDEX_NUM_3; index++) { + StartProcessSuccess(index); + EXPECT_EQ(index, static_cast(serviceInner_->GetRecentAppList().size())); + } + + for (int32_t index = INDEX_NUM_1; index <= INDEX_NUM_3; index++) { + auto appRecord = GetAppRunningRecordByIndex(index); + serviceInner_->ApplicationForegrounded(appRecord->GetRecordId()); + auto appTaskInfo = serviceInner_->GetRecentAppList().front(); + EXPECT_NE(nullptr, appTaskInfo); + EXPECT_EQ(appRecord->GetRecordId(), appTaskInfo->GetRecordId()); + } +} + +/* + * Feature: Ams + * Function: RecentAppList + * SubFunction: remove + * FunctionPoints: Remove app from RecentAppList. + * EnvConditions: RecentAppList has application. + * CaseDescription: Verity ams can remove app from RecentAppList when call RemoveAppFromRecentList. + */ +HWTEST_F(AmsRecentAppListTest, Remove_001, TestSize.Level0) +{ + StartProcessSuccess(INDEX_NUM_1); + EXPECT_EQ(INDEX_NUM_1, static_cast(serviceInner_->GetRecentAppList().size())); + auto appInfo = GetApplicationByIndex(INDEX_NUM_1); + + sptr mockAppScheduler = new MockAppScheduler(); + sptr client = iface_cast(mockAppScheduler.GetRefPtr()); + auto appRecord = GetAppRunningRecordByIndex(INDEX_NUM_1); + appRecord->SetApplicationClient(client); + EXPECT_CALL(*mockAppScheduler, ScheduleProcessSecurityExit()).Times(1); + + serviceInner_->RemoveAppFromRecentList(appInfo->name, appInfo->bundleName); + EXPECT_TRUE(serviceInner_->GetRecentAppList().empty()); +} + +/* + * Feature: Ams + * Function: RecentAppList + * SubFunction: remove + * FunctionPoints: Remove app from RecentAppList. + * EnvConditions: RecentAppList has application. + * CaseDescription: Verity ams can not remove app from RecentAppList when app name is not correct. + */ +HWTEST_F(AmsRecentAppListTest, Remove_002, TestSize.Level0) +{ + StartProcessSuccess(INDEX_NUM_1); + EXPECT_EQ(INDEX_NUM_1, static_cast(serviceInner_->GetRecentAppList().size())); + + auto appInfo = GetApplicationByIndex(INDEX_NUM_2); + serviceInner_->RemoveAppFromRecentList(appInfo->name, appInfo->bundleName); + EXPECT_EQ(INDEX_NUM_1, static_cast(serviceInner_->GetRecentAppList().size())); +} + +/* + * Feature: Ams + * Function: RecentAppList + * SubFunction: remove + * FunctionPoints: Remove app from RecentAppList. + * EnvConditions: RecentAppList has application. + * CaseDescription: Verity ams can not remove app from RecentAppList when app name is empty. + */ +HWTEST_F(AmsRecentAppListTest, Remove_003, TestSize.Level0) +{ + StartProcessSuccess(INDEX_NUM_1); + EXPECT_EQ(INDEX_NUM_1, static_cast(serviceInner_->GetRecentAppList().size())); + + serviceInner_->RemoveAppFromRecentList("", ""); + EXPECT_EQ(INDEX_NUM_1, static_cast(serviceInner_->GetRecentAppList().size())); +} + +/* + * Feature: Ams + * Function: RecentAppList + * SubFunction: clear + * FunctionPoints: Clear RecentAppList. + * EnvConditions: RecentAppList has application. + * CaseDescription: Verity ams can clear RecentAppList when call ClearRecentAppList. + */ +HWTEST_F(AmsRecentAppListTest, Clear_001, TestSize.Level0) +{ + StartProcessSuccess(INDEX_NUM_1); + EXPECT_EQ(INDEX_NUM_1, static_cast(serviceInner_->GetRecentAppList().size())); + + sptr mockAppScheduler = new MockAppScheduler(); + sptr client = iface_cast(mockAppScheduler.GetRefPtr()); + auto appRecord = GetAppRunningRecordByIndex(INDEX_NUM_1); + appRecord->SetApplicationClient(client); + EXPECT_CALL(*mockAppScheduler, ScheduleProcessSecurityExit()).Times(1); + + serviceInner_->ClearRecentAppList(); + EXPECT_TRUE(!serviceInner_->GetRecentAppList().empty()); +} + +/* + * Feature: Ams + * Function: RecentAppList + * SubFunction: clear + * FunctionPoints: Clear RecentAppList. + * EnvConditions: RecentAppList has application. + * CaseDescription: Verity ams can clear RecentAppList when RecentAppList is empty. + */ +HWTEST_F(AmsRecentAppListTest, Clear_002, TestSize.Level0) +{ + EXPECT_TRUE(serviceInner_->GetRecentAppList().empty()); + serviceInner_->ClearRecentAppList(); + EXPECT_TRUE(serviceInner_->GetRecentAppList().empty()); +} + +/* + * Feature: Ams + * Function: RecentAppList + * SubFunction: Add + * FunctionPoints: Add RecentAppList. + * EnvConditions: RecentAppList has application. + * CaseDescription: Verity ams can Add RecentAppList when RecentAppList is empty. + */ +HWTEST_F(AmsRecentAppListTest, RecentAppList_001, TestSize.Level0) +{ + EXPECT_TRUE(serviceInner_->GetRecentAppList().empty()); + pid_t pid = INDEX_NUM_1; + auto abilityInfo = GetAbilityInfoByIndex(INDEX_NUM_1); + auto appInfo = GetApplicationByIndex(INDEX_NUM_1); + sptr token = new (std::nothrow) MockAbilityToken(); + MockAppSpawnClient *mockClientPtr = new (std::nothrow) MockAppSpawnClient(); + ASSERT_TRUE(mockClientPtr); + + EXPECT_CALL(*mockClientPtr, StartProcess(_, _)).Times(1).WillOnce(DoAll(SetArgReferee<1>(pid), Return(ERR_OK))); + serviceInner_->SetAppSpawnClient(std::unique_ptr(mockClientPtr)); + + serviceInner_->LoadAbility(token, nullptr, abilityInfo, appInfo); + EXPECT_EQ(INDEX_NUM_1, static_cast(serviceInner_->GetRecentAppList().size())); + auto appRecord = GetAppRunningRecordByIndex(INDEX_NUM_1); + serviceInner_->AddAppDeathRecipient(pid, nullptr); + EXPECT_EQ(nullptr, appRecord->appDeathRecipient_); +} + +/* + * Feature: Ams + * Function: PushAppFront + * SubFunction: PushAppFront + * FunctionPoints: PushAppFront. + * EnvConditions: app has application. + * CaseDescription: Verity ams can PushAppFront when App is not empty. + */ +HWTEST_F(AmsRecentAppListTest, PushAppFront_001, TestSize.Level0) +{ + EXPECT_TRUE(serviceInner_->GetRecentAppList().empty()); + pid_t pid = INDEX_NUM_1; + auto abilityInfo = GetAbilityInfoByIndex(INDEX_NUM_1); + auto appInfo = GetApplicationByIndex(INDEX_NUM_1); + sptr token = new (std::nothrow) MockAbilityToken(); + MockAppSpawnClient *mockClientPtr = new (std::nothrow) MockAppSpawnClient(); + ASSERT_TRUE(mockClientPtr); + + EXPECT_CALL(*mockClientPtr, StartProcess(_, _)).Times(1).WillOnce(DoAll(SetArgReferee<1>(pid), Return(ERR_OK))); + serviceInner_->SetAppSpawnClient(std::unique_ptr(mockClientPtr)); + + serviceInner_->LoadAbility(token, nullptr, abilityInfo, appInfo); + EXPECT_EQ(INDEX_NUM_1, static_cast(serviceInner_->GetRecentAppList().size())); + auto appRecord = GetAppRunningRecordByIndex(INDEX_NUM_1); + serviceInner_->PushAppFront(appRecord->GetRecordId()); + EXPECT_NE(nullptr, serviceInner_->GetAppTaskInfoById(appRecord->GetRecordId())); +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/appmgr/test/unittest/ams_service_app_spawn_client_test/BUILD.gn b/services/appmgr/test/unittest/ams_service_app_spawn_client_test/BUILD.gn new file mode 100644 index 000000000..bc0b303ff --- /dev/null +++ b/services/appmgr/test/unittest/ams_service_app_spawn_client_test/BUILD.gn @@ -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. + +import("//build/test.gni") +import("//foundation/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/appmgrservice" + +ohos_unittest("AmsServiceAppSpawnClientTest") { + module_out_path = module_output_path + + include_dirs = [ + "//foundation/appexecfwk/standard/services/appmgr/test/mock/include", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include/", + "//foundation/distributedschedule/samgr/adapter/interfaces/innerkits/include/", + ] + + defines = [ "usleep(time) = MockSleep(time)" ] + + sources = [ + "${services_path}/appmgr/src/ability_running_record.cpp", + "${services_path}/appmgr/src/app_death_recipient.cpp", + "${services_path}/appmgr/src/app_mgr_service.cpp", + "${services_path}/appmgr/src/app_mgr_service_event_handler.cpp", + "${services_path}/appmgr/src/app_mgr_service_inner.cpp", + "${services_path}/appmgr/src/app_running_record.cpp", + "${services_path}/appmgr/src/app_spawn_client.cpp", + "${services_path}/appmgr/src/app_spawn_msg_wrapper.cpp", + "${services_path}/appmgr/src/app_spawn_socket.cpp", + ] + + sources += [ "ams_service_app_spawn_client_test.cpp" ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + configs = [ "${libs_path}/libeventhandler:libeventhandler_config" ] + + deps = [ + "${libs_path}/libeventhandler:libeventhandler_target", + "${services_path}/appmgr/test:appmgr_test_source", + "//base/startup/appspawn_standard:appspawn_socket_client", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "//foundation/appexecfwk/standard/services/appmgr:libams", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":AmsServiceAppSpawnClientTest" ] +} diff --git a/services/appmgr/test/unittest/ams_service_app_spawn_client_test/ams_service_app_spawn_client_test.cpp b/services/appmgr/test/unittest/ams_service_app_spawn_client_test/ams_service_app_spawn_client_test.cpp new file mode 100644 index 000000000..dd365f78d --- /dev/null +++ b/services/appmgr/test/unittest/ams_service_app_spawn_client_test/ams_service_app_spawn_client_test.cpp @@ -0,0 +1,748 @@ +/* + * 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. + */ + +#define private public +#define protected public +#include "app_mgr_service.h" +#undef private +#undef protected +#include +#include "securec.h" +#include "app_log_wrapper.h" +#include "mock_app_spawn_socket.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; +using testing::_; +using testing::AtLeast; +using testing::InSequence; +using testing::Invoke; +using testing::Return; + +// keep same with app_spawn_client.cpp +const int32_t CONNECT_RETRY_MAX_TIMES = 15; + +// this function is only used to mock sleep method so ut can run without delay. +int MockSleep([[maybe_unused]] uint32_t seconds) +{ + return 0; +} + +class AppMgrServiceInnerMock : public AppMgrServiceInner { +public: + AppMgrServiceInnerMock() + : socket_(std::make_shared()), appSpawnClient_(std::make_unique()) + { + appSpawnClient_->SetSocket(socket_); + } + + ~AppMgrServiceInnerMock() + {} + + virtual ErrCode OpenAppSpawnConnection() override + { + if (appSpawnClient_.get() != nullptr) { + return appSpawnClient_->OpenConnection(); + } + return -1; + } + + virtual SpawnConnectionState QueryAppSpawnConnectionState() const override + { + if (appSpawnClient_) { + return appSpawnClient_->QueryConnectionState(); + } + return SpawnConnectionState::STATE_NOT_CONNECT; + } + + void CloseAppSpawnConnection() const override + { + if (appSpawnClient_) { + appSpawnClient_->CloseConnection(); + } + } + + const std::shared_ptr &GetSocket() const + { + return socket_; + } + +private: + std::shared_ptr socket_; + std::unique_ptr appSpawnClient_; +}; + +class AmsServiceAppSpawnClientTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); +}; + +void AmsServiceAppSpawnClientTest::SetUpTestCase() +{} + +void AmsServiceAppSpawnClientTest::TearDownTestCase() +{} + +void AmsServiceAppSpawnClientTest::SetUp() +{} + +void AmsServiceAppSpawnClientTest::TearDown() +{} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: AppSpawnClient + * FunctionPoints: Create AppSpawnClient and connect to AppSpawnDaemon in AppMgrService_001 + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if AppMgrService act normal when create appspawnclient and connect to AppSpawnDaemon + */ +HWTEST_F(AmsServiceAppSpawnClientTest, AppSpawnClient_001, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_client_001 start"); + std::shared_ptr appMgrService = std::make_shared(); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appMgrService->QueryServiceState().connectionState); + std::shared_ptr innerService = std::make_shared(); + appMgrService->SetInnerService(innerService); + EXPECT_CALL(*(innerService->GetSocket()), OpenAppSpawnConnection()).WillOnce(Return(ERR_OK)); + appMgrService->OnStart(); + EXPECT_EQ(SpawnConnectionState::STATE_CONNECTED, appMgrService->QueryServiceState().connectionState); + EXPECT_CALL(*(innerService->GetSocket()), CloseAppSpawnConnection()).Times(1); + appMgrService->OnStop(); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appMgrService->QueryServiceState().connectionState); + APP_LOGI("ams_service_app_spawn_client_001 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: AppSpawnClient + * FunctionPoints: Create AppSpawnClient and connect to AppSpawnDaemon in AppMgrService_002 + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if AppMgrService act normal when create appspawnclient and failed connect to AppSpawnDaemon + */ +HWTEST_F(AmsServiceAppSpawnClientTest, AppSpawnClient_002, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_client_002 start"); + std::shared_ptr appMgrService = std::make_shared(); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appMgrService->QueryServiceState().connectionState); + std::shared_ptr innerService = std::make_shared(); + appMgrService->SetInnerService(innerService); + EXPECT_CALL(*(innerService->GetSocket()), OpenAppSpawnConnection()) + .WillRepeatedly(Return(ERR_APPEXECFWK_CONNECT_APPSPAWN_FAILED)); + appMgrService->OnStart(); + EXPECT_EQ(SpawnConnectionState::STATE_CONNECT_FAILED, appMgrService->QueryServiceState().connectionState); + appMgrService->OnStop(); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appMgrService->QueryServiceState().connectionState); + APP_LOGI("ams_service_app_spawn_client_002 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: AppSpawnClient + * FunctionPoints: AppSpawnClient connect to AppSpawnDaemon_001 + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify if AppSpawnClient act normal when successfully connect to AppSpawnDaemon + */ +HWTEST_F(AmsServiceAppSpawnClientTest, AppSpawnClient_003, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_client_003 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr socketMock = std::make_shared(); + appSpawnClient->SetSocket(socketMock); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appSpawnClient->QueryConnectionState()); + EXPECT_CALL(*socketMock, OpenAppSpawnConnection()).WillOnce(Return(ERR_OK)); + EXPECT_EQ(ERR_OK, appSpawnClient->OpenConnection()); + EXPECT_EQ(SpawnConnectionState::STATE_CONNECTED, appSpawnClient->QueryConnectionState()); + APP_LOGI("ams_service_app_spawn_client_003 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: AppSpawnClient + * FunctionPoints: AppSpawnClient connect to AppSpawnDaemon_002 + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify if AppSpawnClient act normal when failed to connect to AppSpawnDaemon + */ +HWTEST_F(AmsServiceAppSpawnClientTest, AppSpawnClient_004, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_client_004 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr socketMock = std::make_shared(); + appSpawnClient->SetSocket(socketMock); + EXPECT_CALL(*socketMock, OpenAppSpawnConnection()).WillRepeatedly(Return(ERR_APPEXECFWK_CONNECT_APPSPAWN_FAILED)); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appSpawnClient->QueryConnectionState()); + EXPECT_EQ(ERR_APPEXECFWK_CONNECT_APPSPAWN_FAILED, appSpawnClient->OpenConnection()); + EXPECT_EQ(SpawnConnectionState::STATE_CONNECT_FAILED, appSpawnClient->QueryConnectionState()); + APP_LOGI("ams_service_app_spawn_client_004 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: AppSpawnClient + * FunctionPoints: AppSpawnClient request new process_001 + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify if AppSpawnClient act normal when successfully to send fork request + */ +HWTEST_F(AmsServiceAppSpawnClientTest, AppSpawnClient_005, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_client_005 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr socketMock = std::make_shared(); + appSpawnClient->SetSocket(socketMock); + EXPECT_CALL(*socketMock, OpenAppSpawnConnection()).WillOnce(Return(ERR_OK)); + EXPECT_EQ(ERR_OK, appSpawnClient->OpenConnection()); + EXPECT_CALL(*socketMock, WriteMessage(_, _)).WillOnce(Return(ERR_OK)); + EXPECT_CALL(*socketMock, ReadMessage(_, _)).WillOnce(Invoke(socketMock.get(), &MockAppSpawnSocket::ReadImpl)); + EXPECT_CALL(*socketMock, CloseAppSpawnConnection()).Times(1); + AppSpawnStartMsg params = {10001, 10001, {10001, 10002}, "processName", "soPath"}; + pid_t expectPid = 11111; + pid_t newPid = 0; + socketMock->SetExpectPid(expectPid); + appSpawnClient->StartProcess(params, newPid); + EXPECT_EQ(expectPid, newPid); + APP_LOGI("ams_service_app_spawn_client_005 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: AppSpawnClient + * FunctionPoints: AppSpawnClient request new process_002 + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify if AppSpawnClient act normal when failed to connect daemon but reconnect success + * when try to send fork request + */ +HWTEST_F(AmsServiceAppSpawnClientTest, AppSpawnClient_006, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_client_006 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr socketMock = std::make_shared(); + appSpawnClient->SetSocket(socketMock); + EXPECT_CALL(*socketMock, OpenAppSpawnConnection()).WillRepeatedly(Return(ERR_APPEXECFWK_CONNECT_APPSPAWN_FAILED)); + EXPECT_EQ(ERR_APPEXECFWK_CONNECT_APPSPAWN_FAILED, appSpawnClient->OpenConnection()); + EXPECT_CALL(*socketMock, OpenAppSpawnConnection()).WillOnce(Return(ERR_OK)); + EXPECT_CALL(*socketMock, WriteMessage(_, _)).WillOnce(Return(ERR_OK)); + EXPECT_CALL(*socketMock, ReadMessage(_, _)).WillOnce(Invoke(socketMock.get(), &MockAppSpawnSocket::ReadImpl)); + EXPECT_CALL(*socketMock, CloseAppSpawnConnection()).Times(1); + AppSpawnStartMsg params = {10001, 10001, {10001, 10002}, "processName", "soPath"}; + pid_t expectPid = 11111; + pid_t newPid = 0; + socketMock->SetExpectPid(expectPid); + appSpawnClient->StartProcess(params, newPid); + EXPECT_EQ(expectPid, newPid); + APP_LOGI("ams_service_app_spawn_client_006 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: AppSpawnClient + * FunctionPoints: AppSpawnClient request new process_003 + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify if AppSpawnClient act normal when failed to connect daemon and reconnect fail + * when try to send fork request + */ +HWTEST_F(AmsServiceAppSpawnClientTest, AppSpawnClient_007, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_client_007 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr socketMock = std::make_shared(); + appSpawnClient->SetSocket(socketMock); + EXPECT_CALL(*socketMock, OpenAppSpawnConnection()).WillRepeatedly(Return(ERR_APPEXECFWK_CONNECT_APPSPAWN_FAILED)); + EXPECT_EQ(ERR_APPEXECFWK_CONNECT_APPSPAWN_FAILED, appSpawnClient->OpenConnection()); + AppSpawnStartMsg params = {10001, 10001, {10001, 10002}, "processName", "soPath"}; + pid_t newPid = 0; + ErrCode result = appSpawnClient->StartProcess(params, newPid); + EXPECT_EQ(ERR_APPEXECFWK_CONNECT_APPSPAWN_FAILED, result); + APP_LOGI("ams_service_app_spawn_client_007 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: AppSpawnClient + * FunctionPoints: AppSpawnClient request new process_004 + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify if AppSpawnClient act normal when try to send request without connect but reconnect success + */ +HWTEST_F(AmsServiceAppSpawnClientTest, AppSpawnClient_008, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_client_008 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr socketMock = std::make_shared(); + appSpawnClient->SetSocket(socketMock); + EXPECT_CALL(*socketMock, OpenAppSpawnConnection()).WillOnce(Return(ERR_OK)); + EXPECT_CALL(*socketMock, WriteMessage(_, _)).WillOnce(Return(ERR_OK)); + EXPECT_CALL(*socketMock, ReadMessage(_, _)).WillOnce(Invoke(socketMock.get(), &MockAppSpawnSocket::ReadImpl)); + EXPECT_CALL(*socketMock, CloseAppSpawnConnection()).Times(1); + AppSpawnStartMsg params = {10001, 10001, {10001, 10002}, "processName", "soPath"}; + pid_t expectPid = 11111; + pid_t newPid = 0; + socketMock->SetExpectPid(expectPid); + appSpawnClient->StartProcess(params, newPid); + EXPECT_EQ(expectPid, newPid); + APP_LOGI("ams_service_app_spawn_client_008 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: AppSpawnClient + * FunctionPoints: AppSpawnClient request new process_005 + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify if AppSpawnClient act normal when try to send request without connect and reconnect failed + */ +HWTEST_F(AmsServiceAppSpawnClientTest, AppSpawnClient_009, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_client_009 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr socketMock = std::make_shared(); + appSpawnClient->SetSocket(socketMock); + EXPECT_CALL(*socketMock, OpenAppSpawnConnection()).WillRepeatedly(Return(ERR_APPEXECFWK_CONNECT_APPSPAWN_FAILED)); + AppSpawnStartMsg params = {10001, 10001, {10001, 10002}, "processName", "soPath"}; + pid_t newPid = 0; + ErrCode result = appSpawnClient->StartProcess(params, newPid); + EXPECT_EQ(ERR_APPEXECFWK_CONNECT_APPSPAWN_FAILED, result); + APP_LOGI("ams_service_app_spawn_client_009 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: AppSpawnClient + * FunctionPoints: AppSpawnClient request new process_006 + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify if AppSpawnClient act normal when failed to send message to AppSpawnDaemon + */ +HWTEST_F(AmsServiceAppSpawnClientTest, AppSpawnClient_010, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_client_010 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr socketMock = std::make_shared(); + appSpawnClient->SetSocket(socketMock); + EXPECT_CALL(*socketMock, OpenAppSpawnConnection()).WillRepeatedly(Return(ERR_OK)); + EXPECT_CALL(*socketMock, WriteMessage(_, _)).WillRepeatedly(Return(ERR_APPEXECFWK_SOCKET_WRITE_FAILED)); + EXPECT_CALL(*socketMock, CloseAppSpawnConnection()).Times(AtLeast(1)); + EXPECT_EQ(ERR_OK, appSpawnClient->OpenConnection()); + AppSpawnStartMsg params = {10001, 10001, {10001, 10002}, "processName", "soPath"}; + pid_t newPid = 0; + ErrCode result = appSpawnClient->StartProcess(params, newPid); + EXPECT_EQ(ERR_APPEXECFWK_SOCKET_WRITE_FAILED, result); + APP_LOGI("ams_service_app_spawn_client_010 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: AppSpawnClient + * FunctionPoints: AppSpawnClient request new process_007 + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify if AppSpawnClient act normal when failed to read message from AppSpawnDaemon + */ +HWTEST_F(AmsServiceAppSpawnClientTest, AppSpawnClient_011, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_client_011 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr socketMock = std::make_shared(); + appSpawnClient->SetSocket(socketMock); + EXPECT_CALL(*socketMock, OpenAppSpawnConnection()).WillRepeatedly(Return(ERR_OK)); + EXPECT_CALL(*socketMock, WriteMessage(_, _)).WillRepeatedly(Return(ERR_OK)); + EXPECT_CALL(*socketMock, ReadMessage(_, _)).WillRepeatedly(Return(ERR_APPEXECFWK_SOCKET_READ_FAILED)); + EXPECT_CALL(*socketMock, CloseAppSpawnConnection()).Times(AtLeast(1)); + EXPECT_EQ(ERR_OK, appSpawnClient->OpenConnection()); + AppSpawnStartMsg params = {10001, 10001, {10001, 10002}, "processName", "soPath"}; + pid_t newPid = 0; + ErrCode result = appSpawnClient->StartProcess(params, newPid); + EXPECT_EQ(ERR_APPEXECFWK_SOCKET_READ_FAILED, result); + APP_LOGI("ams_service_app_spawn_client_011 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: AppSpawnClient + * FunctionPoints: AppSpawnClient request new process_008 + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify if AppSpawnClient act normal when pass invalid param procName(empty) + */ +HWTEST_F(AmsServiceAppSpawnClientTest, AppSpawnClient_012, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_client_012 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr socketMock = std::make_shared(); + appSpawnClient->SetSocket(socketMock); + EXPECT_CALL(*socketMock, OpenAppSpawnConnection()).WillRepeatedly(Return(ERR_OK)); + EXPECT_CALL(*socketMock, CloseAppSpawnConnection()).Times(AtLeast(1)); + EXPECT_EQ(ERR_OK, appSpawnClient->OpenConnection()); + AppSpawnStartMsg params = {10001, 10001, {10001, 10002}, "", "soPath"}; + pid_t newPid = 0; + ErrCode result = appSpawnClient->StartProcess(params, newPid); + EXPECT_EQ(ERR_APPEXECFWK_ASSEMBLE_START_MSG_FAILED, result); + APP_LOGI("ams_service_app_spawn_client_012 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: AppSpawnClient + * FunctionPoints: AppSpawnClient request new process_011 + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify if AppSpawnClient act normal when pass invalid param soPath(empty) + */ +HWTEST_F(AmsServiceAppSpawnClientTest, AppSpawnClient_013, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_client_013 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr socketMock = std::make_shared(); + + EXPECT_CALL(*socketMock, OpenAppSpawnConnection()).WillRepeatedly(Return(ERR_OK)); + EXPECT_CALL(*socketMock, CloseAppSpawnConnection()).Times(AtLeast(1)); + EXPECT_CALL(*socketMock, WriteMessage(_, _)).WillRepeatedly(Return(ERR_OK)); + EXPECT_CALL(*socketMock, ReadMessage(_, _)).WillRepeatedly(Return(ERR_OK)); + + appSpawnClient->SetSocket(socketMock); + + EXPECT_EQ(ERR_OK, appSpawnClient->OpenConnection()); + + AppSpawnStartMsg params = {10001, 10001, {10001, 10002}, "", ""}; + pid_t newPid = 0; + ErrCode result = appSpawnClient->StartProcess(params, newPid); + EXPECT_EQ(ERR_APPEXECFWK_ASSEMBLE_START_MSG_FAILED, result); + APP_LOGI("ams_service_app_spawn_client_013 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: AppSpawnClient + * FunctionPoints: AppSpawnClient request new process_012 + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify if AppSpawnClient act normal when pass invalid param procName(oversize) + */ +HWTEST_F(AmsServiceAppSpawnClientTest, AppSpawnClient_014, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_client_014 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr socketMock = std::make_shared(); + appSpawnClient->SetSocket(socketMock); + EXPECT_CALL(*socketMock, OpenAppSpawnConnection()).WillRepeatedly(Return(ERR_OK)); + EXPECT_CALL(*socketMock, CloseAppSpawnConnection()).Times(AtLeast(1)); + EXPECT_EQ(ERR_OK, appSpawnClient->OpenConnection()); + std::string invalidParam = "invalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalid\ + invalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalid\ + invalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalid\ + invalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalid"; + AppSpawnStartMsg params = {10001, 10001, {10001, 10002}, invalidParam, "soPath"}; + pid_t newPid = 0; + ErrCode result = appSpawnClient->StartProcess(params, newPid); + EXPECT_EQ(ERR_APPEXECFWK_ASSEMBLE_START_MSG_FAILED, result); + APP_LOGI("ams_service_app_spawn_client_014 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: AppSpawnClient + * FunctionPoints: AppSpawnClient request new process_015 + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify if AppSpawnClient act normal when pass invalid param soPath(oversize) + */ +HWTEST_F(AmsServiceAppSpawnClientTest, AppSpawnClient_015, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_client_015 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr socketMock = std::make_shared(); + appSpawnClient->SetSocket(socketMock); + EXPECT_CALL(*socketMock, OpenAppSpawnConnection()).WillRepeatedly(Return(ERR_OK)); + EXPECT_CALL(*socketMock, CloseAppSpawnConnection()).Times(AtLeast(1)); + EXPECT_EQ(ERR_OK, appSpawnClient->OpenConnection()); + std::string invalidParam = "invalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalid\ + invalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalid\ + invalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalid\ + invalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalidinvalid"; + AppSpawnStartMsg params = {10001, 10001, {10001, 10002}, "processName", invalidParam}; + pid_t newPid = 0; + ErrCode result = appSpawnClient->StartProcess(params, newPid); + EXPECT_EQ(ERR_APPEXECFWK_ASSEMBLE_START_MSG_FAILED, result); + APP_LOGI("ams_service_app_spawn_client_015 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: AppSpawnClient + * FunctionPoints: AppSpawnClient close connection with AppSpawnDaemon_001 + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify if AppSpawnClient CloseConnection act normal after OpenConnection + */ +HWTEST_F(AmsServiceAppSpawnClientTest, AppSpawnClient_016, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_client_016 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr socketMock = std::make_shared(); + appSpawnClient->SetSocket(socketMock); + EXPECT_CALL(*socketMock, OpenAppSpawnConnection()).WillRepeatedly(Return(ERR_OK)); + EXPECT_CALL(*socketMock, CloseAppSpawnConnection()).Times(AtLeast(1)); + EXPECT_EQ(ERR_OK, appSpawnClient->OpenConnection()); + appSpawnClient->CloseConnection(); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appSpawnClient->QueryConnectionState()); + APP_LOGI("ams_service_app_spawn_client_016 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: AppSpawnClient + * FunctionPoints: AppSpawnClient close connection with AppSpawnDaemon_002 + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify if AppSpawnClient CloseConnection act normal without OpenConnection + */ +HWTEST_F(AmsServiceAppSpawnClientTest, AppSpawnClient_017, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_client_017 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr socketMock = std::make_shared(); + appSpawnClient->SetSocket(socketMock); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appSpawnClient->QueryConnectionState()); + appSpawnClient->CloseConnection(); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appSpawnClient->QueryConnectionState()); + APP_LOGI("ams_service_app_spawn_client_017 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: AppSpawnClient + * FunctionPoints: AppSpawnClient close connection with AppSpawnDaemon_003 + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify if AppSpawnClient CloseConnection act normal when OpenConnection failed + */ +HWTEST_F(AmsServiceAppSpawnClientTest, AppSpawnClient_018, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_client_018 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr socketMock = std::make_shared(); + appSpawnClient->SetSocket(socketMock); + EXPECT_CALL(*socketMock, OpenAppSpawnConnection()).WillRepeatedly(Return(ERR_APPEXECFWK_CONNECT_APPSPAWN_FAILED)); + EXPECT_EQ(ERR_APPEXECFWK_CONNECT_APPSPAWN_FAILED, appSpawnClient->OpenConnection()); + appSpawnClient->CloseConnection(); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appSpawnClient->QueryConnectionState()); + APP_LOGI("ams_service_app_spawn_client_018 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: AppSpawnClient + * FunctionPoints: AppSpawnClient close connection with AppSpawnDaemon_004 + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify if after close connection with appspawn, appspawnclient startprocess + * will invoke openconnection. + */ +HWTEST_F(AmsServiceAppSpawnClientTest, AppSpawnClient_019, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_client_019 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr socketMock = std::make_shared(); + appSpawnClient->SetSocket(socketMock); + EXPECT_CALL(*socketMock, OpenAppSpawnConnection()).WillOnce(Return(ERR_OK)); + EXPECT_CALL(*socketMock, CloseAppSpawnConnection()).Times(1); + EXPECT_EQ(ERR_OK, appSpawnClient->OpenConnection()); + appSpawnClient->CloseConnection(); + EXPECT_CALL(*socketMock, OpenAppSpawnConnection()).WillOnce(Return(ERR_OK)); + EXPECT_CALL(*socketMock, WriteMessage(_, _)).WillOnce(Return(ERR_OK)); + EXPECT_CALL(*socketMock, ReadMessage(_, _)).WillOnce(Invoke(socketMock.get(), &MockAppSpawnSocket::ReadImpl)); + EXPECT_CALL(*socketMock, CloseAppSpawnConnection()).Times(1); + AppSpawnStartMsg params = {10001, 10001, {10001, 10002}, "processName", "soPath"}; + pid_t expectPid = 11111; + pid_t newPid = 0; + socketMock->SetExpectPid(expectPid); + ErrCode result = appSpawnClient->StartProcess(params, newPid); + EXPECT_EQ(expectPid, newPid); + EXPECT_EQ(ERR_OK, result); + APP_LOGI("ams_service_app_spawn_client_019 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: ReConnectAppSpawn + * FunctionPoints: Test AppSpawnClient reconnect functions. + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify if AppSpawnClient first time connection fail, but second time is success. + */ +HWTEST_F(AmsServiceAppSpawnClientTest, ReConnectAppSpawn_001, TestSize.Level0) +{ + APP_LOGI("ams_service_reconnect_app_spawn_001 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr socketMock = std::make_shared(); + appSpawnClient->SetSocket(socketMock); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appSpawnClient->QueryConnectionState()); + EXPECT_CALL(*socketMock, OpenAppSpawnConnection()) + .WillOnce(Return(ERR_APPEXECFWK_CONNECT_APPSPAWN_FAILED)) + .WillOnce(Return(ERR_OK)); + EXPECT_EQ(ERR_OK, appSpawnClient->OpenConnection()); + EXPECT_EQ(SpawnConnectionState::STATE_CONNECTED, appSpawnClient->QueryConnectionState()); + APP_LOGI("ams_service_reconnect_app_spawn_001 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: ReConnectAppSpawn + * FunctionPoints: Test AppSpawnClient reconnect functions. + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify if AppSpawnClient first n time connection fail, but last time is success. + */ +HWTEST_F(AmsServiceAppSpawnClientTest, ReConnectAppSpawn_002, TestSize.Level0) +{ + APP_LOGI("ams_service_reconnect_app_spawn_002 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr socketMock = std::make_shared(); + appSpawnClient->SetSocket(socketMock); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appSpawnClient->QueryConnectionState()); + InSequence seq; + EXPECT_CALL(*socketMock, OpenAppSpawnConnection()) + .Times(CONNECT_RETRY_MAX_TIMES) + .WillRepeatedly(Return(ERR_APPEXECFWK_CONNECT_APPSPAWN_FAILED)) + .RetiresOnSaturation(); + EXPECT_CALL(*socketMock, OpenAppSpawnConnection()).WillOnce(Return(ERR_OK)); + + EXPECT_EQ(ERR_OK, appSpawnClient->OpenConnection()); + EXPECT_EQ(SpawnConnectionState::STATE_CONNECTED, appSpawnClient->QueryConnectionState()); + APP_LOGI("ams_service_reconnect_app_spawn_002 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: ReConnectAppSpawn + * FunctionPoints: Test AppSpawnClient reconnect functions. + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify if AppSpawnClient all (n+1) times connection fail. + */ +HWTEST_F(AmsServiceAppSpawnClientTest, ReConnectAppSpawn_003, TestSize.Level0) +{ + APP_LOGI("ams_service_reconnect_app_spawn_003 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr socketMock = std::make_shared(); + appSpawnClient->SetSocket(socketMock); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appSpawnClient->QueryConnectionState()); + EXPECT_CALL(*socketMock, OpenAppSpawnConnection()) + .Times(CONNECT_RETRY_MAX_TIMES + 1) + .WillRepeatedly(Return(ERR_APPEXECFWK_CONNECT_APPSPAWN_FAILED)); + + EXPECT_EQ(ERR_APPEXECFWK_CONNECT_APPSPAWN_FAILED, appSpawnClient->OpenConnection()); + EXPECT_EQ(SpawnConnectionState::STATE_CONNECT_FAILED, appSpawnClient->QueryConnectionState()); + APP_LOGI("ams_service_reconnect_app_spawn_003 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: ReConnectAppSpawn + * FunctionPoints: Test AppSpawnClient reconnect functions. + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify if AppSpawnClient first time start process fail, but second time is success. + */ +HWTEST_F(AmsServiceAppSpawnClientTest, ReConnectAppSpawn_004, TestSize.Level0) +{ + APP_LOGI("ams_service_reconnect_app_spawn_004 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr socketMock = std::make_shared(); + appSpawnClient->SetSocket(socketMock); + EXPECT_CALL(*socketMock, OpenAppSpawnConnection()).WillRepeatedly(Return(ERR_OK)); + EXPECT_CALL(*socketMock, WriteMessage(_, _)).WillRepeatedly(Return(ERR_OK)); + EXPECT_CALL(*socketMock, ReadMessage(_, _)) + .WillOnce(Return(ERR_APPEXECFWK_SOCKET_READ_FAILED)) + .WillOnce(Invoke(socketMock.get(), &MockAppSpawnSocket::ReadImpl)); + EXPECT_CALL(*socketMock, CloseAppSpawnConnection()).Times(AtLeast(1)); + AppSpawnStartMsg params = {10001, 10001, {10001, 10002}, "processName", "soPath"}; + pid_t expectPid = 11111; + pid_t newPid = 0; + socketMock->SetExpectPid(expectPid); + ErrCode result = appSpawnClient->StartProcess(params, newPid); + EXPECT_EQ(expectPid, newPid); + EXPECT_EQ(ERR_OK, result); + APP_LOGI("ams_service_reconnect_app_spawn_004 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: ReConnectAppSpawn + * FunctionPoints: Test AppSpawnClient reconnect functions. + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify if AppSpawnClient first n time start process fail, but last time is success. + */ +HWTEST_F(AmsServiceAppSpawnClientTest, ReConnectAppSpawn_005, TestSize.Level0) +{ + APP_LOGI("ams_service_reconnect_app_spawn_005 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr socketMock = std::make_shared(); + appSpawnClient->SetSocket(socketMock); + InSequence seq; + for (int i = 0; i < CONNECT_RETRY_MAX_TIMES; i++) { + EXPECT_CALL(*socketMock, OpenAppSpawnConnection()).WillOnce(Return(ERR_OK)); + EXPECT_CALL(*socketMock, WriteMessage(_, _)).WillOnce(Return(ERR_OK)); + EXPECT_CALL(*socketMock, ReadMessage(_, _)).WillOnce(Return(ERR_APPEXECFWK_SOCKET_READ_FAILED)); + EXPECT_CALL(*socketMock, CloseAppSpawnConnection()).Times(1); + } + EXPECT_CALL(*socketMock, OpenAppSpawnConnection()).WillOnce(Return(ERR_OK)); + EXPECT_CALL(*socketMock, WriteMessage(_, _)).WillOnce(Return(ERR_OK)); + EXPECT_CALL(*socketMock, ReadMessage(_, _)).WillOnce(Invoke(socketMock.get(), &MockAppSpawnSocket::ReadImpl)); + EXPECT_CALL(*socketMock, CloseAppSpawnConnection()).Times(1); + AppSpawnStartMsg params = {10001, 10001, {10001, 10002}, "processName", "soPath"}; + pid_t expectPid = 11111; + pid_t newPid = 0; + socketMock->SetExpectPid(expectPid); + ErrCode result = appSpawnClient->StartProcess(params, newPid); + EXPECT_EQ(expectPid, newPid); + EXPECT_EQ(ERR_OK, result); + APP_LOGI("ams_service_reconnect_app_spawn_005 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: ReConnectAppSpawn + * FunctionPoints: Test AppSpawnClient reconnect functions. + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify if AppSpawnClient all(n+1) times start process fail. + */ +HWTEST_F(AmsServiceAppSpawnClientTest, ReConnectAppSpawn_006, TestSize.Level0) +{ + APP_LOGI("ams_service_reconnect_app_spawn_006 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr socketMock = std::make_shared(); + appSpawnClient->SetSocket(socketMock); + EXPECT_CALL(*socketMock, OpenAppSpawnConnection()).WillRepeatedly(Return(ERR_OK)); + EXPECT_CALL(*socketMock, WriteMessage(_, _)).WillRepeatedly(Return(ERR_OK)); + EXPECT_CALL(*socketMock, ReadMessage(_, _)).WillRepeatedly(Return(ERR_APPEXECFWK_SOCKET_READ_FAILED)); + EXPECT_CALL(*socketMock, CloseAppSpawnConnection()).Times(AtLeast(1)); + AppSpawnStartMsg params = {10001, 10001, {10001, 10002}, "processName", "soPath"}; + pid_t newPid = 0; + ErrCode result = appSpawnClient->StartProcess(params, newPid); + EXPECT_EQ(ERR_APPEXECFWK_SOCKET_READ_FAILED, result); + APP_LOGI("ams_service_reconnect_app_spawn_006 end"); +} diff --git a/services/appmgr/test/unittest/ams_service_app_spawn_msg_wrapper_test/BUILD.gn b/services/appmgr/test/unittest/ams_service_app_spawn_msg_wrapper_test/BUILD.gn new file mode 100644 index 000000000..7b5a7da57 --- /dev/null +++ b/services/appmgr/test/unittest/ams_service_app_spawn_msg_wrapper_test/BUILD.gn @@ -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. + +import("//build/test.gni") +import("//foundation/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/appmgrservice" + +ohos_unittest("AmsServiceAppSpawnMsgWrapperTest") { + module_out_path = module_output_path + + include_dirs = [] + + defines = [ "usleep(time) = MockSleep(time)" ] + + sources = [ + "${services_path}/appmgr/src/app_spawn_msg_wrapper.cpp", + "${services_path}/appmgr/src/app_spawn_socket.cpp", + ] + + sources += [ "ams_service_app_spawn_msg_wrapper_test.cpp" ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + configs = [ "${libs_path}/libeventhandler:libeventhandler_config" ] + + deps = [ + "${libs_path}/libeventhandler:libeventhandler_target", + "${services_path}/appmgr/test:appmgr_test_source", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":AmsServiceAppSpawnMsgWrapperTest" ] +} diff --git a/services/appmgr/test/unittest/ams_service_app_spawn_msg_wrapper_test/ams_service_app_spawn_msg_wrapper_test.cpp b/services/appmgr/test/unittest/ams_service_app_spawn_msg_wrapper_test/ams_service_app_spawn_msg_wrapper_test.cpp new file mode 100644 index 000000000..39da2bbdf --- /dev/null +++ b/services/appmgr/test/unittest/ams_service_app_spawn_msg_wrapper_test/ams_service_app_spawn_msg_wrapper_test.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 + +#include "securec.h" +#include "app_log_wrapper.h" +#include "app_spawn_msg_wrapper.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; + +// this function is only used to mock sleep method so ut can run without delay. +int MockSleep([[maybe_unused]] uint32_t seconds) +{ + return 0; +} + +class AmsServiceAppSpawnMsgWrapperTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); +}; + +void AmsServiceAppSpawnMsgWrapperTest::SetUpTestCase() +{} + +void AmsServiceAppSpawnMsgWrapperTest::TearDownTestCase() +{} + +void AmsServiceAppSpawnMsgWrapperTest::SetUp() +{} + +void AmsServiceAppSpawnMsgWrapperTest::TearDown() +{} + +/* + * Feature: AppMgrService + * Function: AppSpawnMsgWrapper + * SubFunction: AssembleMsg + * FunctionPoints: check message + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify the function AssembleMsg can check the invalid uid. + */ +HWTEST(AmsServiceAppSpawnMsgWrapperTest, AppSpawnMsgWrapper_001, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_msg_wrapper_001 start"); + + std::unique_ptr appSpawnMsgWrapper = std::make_unique(); + + AppSpawnStartMsg params = {10000, 10000, {10001, 10002}, "processName", "soPath"}; + EXPECT_EQ(true, appSpawnMsgWrapper->AssembleMsg(params)); + + APP_LOGI("ams_service_app_spawn_msg_wrapper_001 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnMsgWrapper + * SubFunction: AssembleMsg + * FunctionPoints: check message + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify the function AssembleMsg can check the invalid gid. + */ +HWTEST(AmsServiceAppSpawnMsgWrapperTest, AppSpawnMsgWrapper_002, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_msg_wrapper_002 start"); + + std::unique_ptr appSpawnMsgWrapper = std::make_unique(); + + AppSpawnStartMsg params = {10000, 10000, {10001, 10002}, "processName", "soPath"}; + EXPECT_EQ(true, appSpawnMsgWrapper->AssembleMsg(params)); + + APP_LOGI("ams_service_app_spawn_msg_wrapper_002 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnMsgWrapper + * SubFunction: AssembleMsg + * FunctionPoints: check message + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify the function AssembleMsg can check gid count which exceeds the max limit. + */ +HWTEST(AmsServiceAppSpawnMsgWrapperTest, AppSpawnMsgWrapper_003, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_msg_wrapper_003 start"); + + std::unique_ptr appSpawnMsgWrapper = std::make_unique(); + // gids limit, max 64 + AppSpawnStartMsg params = {10000, + 10000, + {10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001, + 10001}, + "processName", + "soPath"}; + EXPECT_EQ(false, appSpawnMsgWrapper->AssembleMsg(params)); + + APP_LOGI("ams_service_app_spawn_msg_wrapper_003 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnMsgWrapper + * SubFunction: AssembleMsg + * FunctionPoints: check message + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify the function AssembleMsg can check the process name is empty. + */ +HWTEST(AmsServiceAppSpawnMsgWrapperTest, AppSpawnMsgWrapper_004, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_msg_wrapper_004 start"); + + std::unique_ptr appSpawnMsgWrapper = std::make_unique(); + AppSpawnStartMsg params = {10000, 10000, {10001, 10001}, "", "soPath"}; + EXPECT_EQ(false, appSpawnMsgWrapper->AssembleMsg(params)); + + APP_LOGI("ams_service_app_spawn_msg_wrapper_004 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnMsgWrapper + * SubFunction: AssembleMsg + * FunctionPoints: check message + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify the function AssembleMsg can check the process name exceeds the max length. + */ +HWTEST(AmsServiceAppSpawnMsgWrapperTest, AppSpawnMsgWrapper_005, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_msg_wrapper_005 start"); + + std::unique_ptr appSpawnMsgWrapper = std::make_unique(); + std::string invalid = + "InvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalid" + "InvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInval" + "id" + "InvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInval" + "id"; + AppSpawnStartMsg params = {10000, 10000, {10001, 10001}, invalid, "soPath"}; + EXPECT_EQ(false, appSpawnMsgWrapper->AssembleMsg(params)); + + APP_LOGI("ams_service_app_spawn_msg_wrapper_005 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnMsgWrapper + * SubFunction: AssembleMsg + * FunctionPoints: check message + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify the function AssembleMsg can check the so path is empty. + */ + +HWTEST(AmsServiceAppSpawnMsgWrapperTest, AppSpawnMsgWrapper_006, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_msg_wrapper_006 start"); + + std::unique_ptr appSpawnMsgWrapper = std::make_unique(); + AppSpawnStartMsg params = {10000, 10000, {10001, 10001}, "", ""}; + EXPECT_EQ(false, appSpawnMsgWrapper->AssembleMsg(params)); + + APP_LOGI("ams_service_app_spawn_msg_wrapper_006 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnMsgWrapper + * SubFunction: AssembleMsg + * FunctionPoints: check message + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify the function AssembleMsg can check the so path exceeds the max length. + */ +HWTEST(AmsServiceAppSpawnMsgWrapperTest, AppSpawnMsgWrapper_007, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_msg_wrapper_007 start"); + + std::unique_ptr appSpawnMsgWrapper = std::make_unique(); + std::string invalid = + "InvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalid" + "InvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInval" + "id" + "InvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInval" + "id"; + AppSpawnStartMsg params = {10000, 10000, {10001, 10001}, "processName", invalid}; + EXPECT_EQ(false, appSpawnMsgWrapper->AssembleMsg(params)); + + APP_LOGI("ams_service_app_spawn_msg_wrapper_007 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnMsgWrapper + * SubFunction: AssembleMsg + * FunctionPoints: check message + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify the function AssembleMsg check the valid message. + */ +HWTEST(AmsServiceAppSpawnMsgWrapperTest, AppSpawnMsgWrapper_008, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_msg_wrapper_008 start"); + + std::unique_ptr appSpawnMsgWrapper = std::make_unique(); + AppSpawnStartMsg params = {10000, 10000, {10001, 10001}, "processName", "soPath"}; + EXPECT_EQ(true, appSpawnMsgWrapper->AssembleMsg(params)); + + APP_LOGI("ams_service_app_spawn_msg_wrapper_008 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnMsgWrapper + * SubFunction: IsValid & GetMsgLength + * FunctionPoints: check message + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify if check the message pass, the length and valid value is right. + */ +HWTEST(AmsServiceAppSpawnMsgWrapperTest, AppSpawnMsgWrapper_009, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_msg_wrapper_009 start"); + + std::unique_ptr appSpawnMsgWrapper = std::make_unique(); + AppSpawnStartMsg params = {10000, 10000, {10001, 10001}, "processName", "soPath"}; + EXPECT_EQ(true, appSpawnMsgWrapper->AssembleMsg(params)); + EXPECT_EQ(true, appSpawnMsgWrapper->IsValid()); + int32_t lhs = sizeof(AppSpawnMsg); + EXPECT_EQ(lhs, appSpawnMsgWrapper->GetMsgLength()); + + APP_LOGI("ams_service_app_spawn_msg_wrapper_009 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnMsgWrapper + * SubFunction: IsValid & GetMsgLength + * FunctionPoints: check message + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify if check the message fail, the length and valid value is right. + */ +HWTEST(AmsServiceAppSpawnMsgWrapperTest, AppSpawnMsgWrapper_010, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_msg_wrapper_010 start"); + + std::unique_ptr appSpawnMsgWrapper = std::make_unique(); + AppSpawnStartMsg params = {10000, 10000, {10001, 10001}, "", "soPath"}; + EXPECT_EQ(false, appSpawnMsgWrapper->AssembleMsg(params)); + EXPECT_EQ(false, appSpawnMsgWrapper->IsValid()); + int32_t lhs = 0; + EXPECT_EQ(lhs, appSpawnMsgWrapper->GetMsgLength()); + + APP_LOGI("ams_service_app_spawn_msg_wrapper_010 end"); +} \ No newline at end of file diff --git a/services/appmgr/test/unittest/ams_service_app_spawn_socket_test/BUILD.gn b/services/appmgr/test/unittest/ams_service_app_spawn_socket_test/BUILD.gn new file mode 100644 index 000000000..2ad9d4a48 --- /dev/null +++ b/services/appmgr/test/unittest/ams_service_app_spawn_socket_test/BUILD.gn @@ -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. + +import("//build/test.gni") +import("//foundation/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/appmgrservice" + +ohos_unittest("AmsServiceAppSpawnSocketTest") { + module_out_path = module_output_path + + include_dirs = [ "//base/startup/appspawn_standard/test/mock/include" ] + + defines = [ "usleep(time) = MockSleep(time)" ] + + sources = [ "${services_path}/appmgr/src/app_spawn_socket.cpp" ] + + sources += [ "ams_service_app_spawn_socket_test.cpp" ] + + configs = [ "${libs_path}/libeventhandler:libeventhandler_config" ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${libs_path}/libeventhandler:libeventhandler_target", + "${services_path}/appmgr/test:appmgr_test_source", + "//base/startup/appspawn_standard:appspawn_socket_client", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":AmsServiceAppSpawnSocketTest" ] +} diff --git a/services/appmgr/test/unittest/ams_service_app_spawn_socket_test/ams_service_app_spawn_socket_test.cpp b/services/appmgr/test/unittest/ams_service_app_spawn_socket_test/ams_service_app_spawn_socket_test.cpp new file mode 100644 index 000000000..f5c1314e0 --- /dev/null +++ b/services/appmgr/test/unittest/ams_service_app_spawn_socket_test/ams_service_app_spawn_socket_test.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 "app_spawn_socket.h" +#include +#include "securec.h" +#include "app_log_wrapper.h" +#include "mock_client_socket.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; +using testing::_; +using testing::AtLeast; +using testing::InSequence; +using testing::Invoke; +using testing::Return; + +// this function is only used to mock sleep method so ut can run without delay. +int MockSleep([[maybe_unused]] uint32_t seconds) +{ + return 0; +} + +class AmsServiceAppSpawnSocketTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); +}; + +void AmsServiceAppSpawnSocketTest::SetUpTestCase() +{} + +void AmsServiceAppSpawnSocketTest::TearDownTestCase() +{} + +void AmsServiceAppSpawnSocketTest::SetUp() +{} + +void AmsServiceAppSpawnSocketTest::TearDown() +{} + +/* + * Feature: AppMgrService + * Function: AppSpawnSocket + * SubFunction: OpenAppSpawnConnection + * FunctionPoints: open connection + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify if create client socket fail, open connection error. + */ +HWTEST(AmsServiceAppSpawnSocketTest, AppSpawnSocket_001, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_socket_001 start"); + + std::shared_ptr mockClientSocket = + std::make_shared(); + std::unique_ptr appSpawnSocket = std::make_unique(); + + appSpawnSocket->SetClientSocket(mockClientSocket); + EXPECT_CALL(*mockClientSocket, CreateClient()).WillOnce(Return(-1)); + EXPECT_EQ(ERR_APPEXECFWK_BAD_APPSPAWN_CLIENT, appSpawnSocket->OpenAppSpawnConnection()); + + APP_LOGI("ams_service_app_spawn_socket_001 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnSocket + * SubFunction: OpenAppSpawnConnection + * FunctionPoints: open connection + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify if connect socket client fail, open connection error. + */ +HWTEST(AmsServiceAppSpawnSocketTest, AppSpawnSocket_002, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_socket_002 start"); + + std::shared_ptr mockClientSocket = + std::make_shared(); + std::unique_ptr appSpawnSocket = std::make_unique(); + + appSpawnSocket->SetClientSocket(mockClientSocket); + EXPECT_CALL(*mockClientSocket, CreateClient()).WillOnce(Return(ERR_OK)); + EXPECT_CALL(*mockClientSocket, ConnectSocket()).WillOnce(Return(-1)); + EXPECT_EQ(ERR_APPEXECFWK_CONNECT_APPSPAWN_FAILED, appSpawnSocket->OpenAppSpawnConnection()); + + APP_LOGI("ams_service_app_spawn_socket_002 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnSocket + * SubFunction: OpenAppSpawnConnection + * FunctionPoints: open connection + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify the function OpenAppSpawnConnection open connection success. + */ +HWTEST(AmsServiceAppSpawnSocketTest, AppSpawnSocket_003, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_socket_003 start"); + + std::shared_ptr mockClientSocket = + std::make_shared(); + std::unique_ptr appSpawnSocket = std::make_unique(); + + appSpawnSocket->SetClientSocket(mockClientSocket); + EXPECT_CALL(*mockClientSocket, CreateClient()).WillOnce(Return(ERR_OK)); + EXPECT_CALL(*mockClientSocket, ConnectSocket()).WillOnce(Return(ERR_OK)); + EXPECT_EQ(ERR_OK, appSpawnSocket->OpenAppSpawnConnection()); + + APP_LOGI("ams_service_app_spawn_socket_003 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnSocket + * SubFunction: ReadMessage + * FunctionPoints: check params + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify the function ReadMessage can check the invalid buffer point. + */ +HWTEST(AmsServiceAppSpawnSocketTest, AppSpawnSocket_004, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_socket_004 start"); + + std::shared_ptr mockClientSocket = + std::make_shared(); + std::unique_ptr appSpawnSocket = std::make_unique(); + std::unique_ptr buff = nullptr; + int32_t len = 10; + + appSpawnSocket->SetClientSocket(mockClientSocket); + EXPECT_EQ(ERR_INVALID_VALUE, appSpawnSocket->ReadMessage(buff.get(), len)); + + APP_LOGI("ams_service_app_spawn_socket_004 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnSocket + * SubFunction: ReadMessage + * FunctionPoints: check params + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify the function ReadMessage can check the buffer length is 0. + */ +HWTEST(AmsServiceAppSpawnSocketTest, AppSpawnSocket_005, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_socket_005 start"); + + std::shared_ptr mockClientSocket = + std::make_shared(); + std::unique_ptr appSpawnSocket = std::make_unique(); + std::unique_ptr buff = std::make_unique(10); + int32_t len = 0; + + appSpawnSocket->SetClientSocket(mockClientSocket); + EXPECT_EQ(ERR_INVALID_VALUE, appSpawnSocket->ReadMessage(buff.get(), len)); + + APP_LOGI("ams_service_app_spawn_socket_005 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnSocket + * SubFunction: ReadMessage + * FunctionPoints: check params + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify the function ReadMessage can check the buffer length < 0. + */ +HWTEST(AmsServiceAppSpawnSocketTest, AppSpawnSocket_006, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_socket_006 start"); + + std::shared_ptr mockClientSocket = + std::make_shared(); + std::unique_ptr appSpawnSocket = std::make_unique(); + std::unique_ptr buff = std::make_unique(10); + int32_t len = -1; + + appSpawnSocket->SetClientSocket(mockClientSocket); + EXPECT_EQ(ERR_INVALID_VALUE, appSpawnSocket->ReadMessage(buff.get(), len)); + + APP_LOGI("ams_service_app_spawn_socket_006 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnSocket + * SubFunction: ReadMessage + * FunctionPoints: read message + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify the function ReadMessage can read the valid message. + */ +HWTEST(AmsServiceAppSpawnSocketTest, AppSpawnSocket_007, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_socket_007 start"); + + std::shared_ptr mockClientSocket = + std::make_shared(); + std::unique_ptr appSpawnSocket = std::make_unique(); + std::unique_ptr buff = std::make_unique(10); + int32_t len = 10; + + appSpawnSocket->SetClientSocket(mockClientSocket); + EXPECT_CALL(*mockClientSocket, ReadSocketMessage(_, _)).WillOnce(Return(len)); + EXPECT_EQ(ERR_OK, appSpawnSocket->ReadMessage(buff.get(), len)); + + APP_LOGI("ams_service_app_spawn_socket_007 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnSocket + * SubFunction: ReadMessage + * FunctionPoints: check params + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify the function ReadMessage can check the message length. + */ +HWTEST(AmsServiceAppSpawnSocketTest, AppSpawnSocket_008, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_socket_008 start"); + + std::shared_ptr mockClientSocket = + std::make_shared(); + std::unique_ptr appSpawnSocket = std::make_unique(); + std::unique_ptr buff = std::make_unique(10); + int32_t len = 10; + + appSpawnSocket->SetClientSocket(mockClientSocket); + EXPECT_CALL(*mockClientSocket, ReadSocketMessage(_, _)).WillOnce(Return(11)); + EXPECT_EQ(ERR_APPEXECFWK_SOCKET_READ_FAILED, appSpawnSocket->ReadMessage(buff.get(), len)); + + APP_LOGI("ams_service_app_spawn_socket_008 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnSocket + * SubFunction: WriteMessage + * FunctionPoints: check params + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify the function WriteMessage can check the invalid buffer point. + */ +HWTEST(AmsServiceAppSpawnSocketTest, AppSpawnSocket_009, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_socket_009 start"); + std::shared_ptr mockClientSocket = + std::make_shared(); + std::unique_ptr appSpawnSocket = std::make_unique(); + std::unique_ptr buff = nullptr; + int32_t len = 10; + + appSpawnSocket->SetClientSocket(mockClientSocket); + EXPECT_EQ(ERR_INVALID_VALUE, appSpawnSocket->WriteMessage(buff.get(), len)); + + APP_LOGI("ams_service_app_spawn_socket_009 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnSocket + * SubFunction: WriteMessage + * FunctionPoints: check params + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify the function WriteMessage can check the buffer length is 0. + */ +HWTEST(AmsServiceAppSpawnSocketTest, AppSpawnSocket_010, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_socket_010 start"); + + std::shared_ptr mockClientSocket = + std::make_shared(); + std::unique_ptr appSpawnSocket = std::make_unique(); + std::unique_ptr buff = std::make_unique(10); + int32_t len = 0; + + appSpawnSocket->SetClientSocket(mockClientSocket); + EXPECT_EQ(ERR_INVALID_VALUE, appSpawnSocket->WriteMessage(buff.get(), len)); + + APP_LOGI("ams_service_app_spawn_socket_010 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnSocket + * SubFunction: WriteMessage + * FunctionPoints: check params + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify the function WriteMessage can check the buffer length < 0. + */ +HWTEST(AmsServiceAppSpawnSocketTest, AppSpawnSocket_011, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_socket_011 start"); + + std::shared_ptr mockClientSocket = + std::make_shared(); + std::unique_ptr appSpawnSocket = std::make_unique(); + std::unique_ptr buff = std::make_unique(10); + int32_t len = -1; + + appSpawnSocket->SetClientSocket(mockClientSocket); + EXPECT_EQ(ERR_INVALID_VALUE, appSpawnSocket->WriteMessage(buff.get(), len)); + + APP_LOGI("ams_service_app_spawn_socket_011 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnSocket + * SubFunction: WriteMessage + * FunctionPoints: write message + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify the function WriteMessage can write valid message. + */ +HWTEST(AmsServiceAppSpawnSocketTest, AppSpawnSocket_012, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_socket_012 start"); + + std::shared_ptr mockClientSocket = + std::make_shared(); + std::unique_ptr appSpawnSocket = std::make_unique(); + std::unique_ptr buff = std::make_unique(10); + int32_t len = 10; + + appSpawnSocket->SetClientSocket(mockClientSocket); + EXPECT_CALL(*mockClientSocket, WriteSocketMessage(_, _)).WillOnce(Return(len)); + EXPECT_EQ(ERR_OK, appSpawnSocket->WriteMessage(buff.get(), len)); + + APP_LOGI("ams_service_app_spawn_socket_012 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnSocket + * SubFunction: WriteMessage + * FunctionPoints: write message + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Verify the function WriteMessage can check the message length. + */ +HWTEST(AmsServiceAppSpawnSocketTest, AppSpawnSocket_013, TestSize.Level0) +{ + APP_LOGI("ams_service_app_spawn_socket_013 start"); + + std::shared_ptr mockClientSocket = + std::make_shared(); + std::unique_ptr appSpawnSocket = std::make_unique(); + std::unique_ptr buff = std::make_unique(10); + int32_t len = 10; + + appSpawnSocket->SetClientSocket(mockClientSocket); + EXPECT_CALL(*mockClientSocket, WriteSocketMessage(_, _)).WillOnce(Return(11)); + EXPECT_EQ(ERR_APPEXECFWK_SOCKET_WRITE_FAILED, appSpawnSocket->WriteMessage(buff.get(), len)); + + APP_LOGI("ams_service_app_spawn_socket_013 end"); +} diff --git a/services/appmgr/test/unittest/ams_service_event_drive_test/BUILD.gn b/services/appmgr/test/unittest/ams_service_event_drive_test/BUILD.gn new file mode 100644 index 000000000..90e9d95e7 --- /dev/null +++ b/services/appmgr/test/unittest/ams_service_event_drive_test/BUILD.gn @@ -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. + +import("//build/test.gni") +import("//foundation/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/appmgrservice" + +ohos_unittest("AmsServiceEventDriveTest") { + module_out_path = module_output_path + + include_dirs = [ + "//foundation/appexecfwk/standard/services/appmgr/test/mock/include", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk", + "//utils/native/base/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include/", + "//foundation/distributedschedule/samgr/adapter/interfaces/innerkits/include/", + ] + + sources = [ + "${services_path}/appmgr/src/ability_running_record.cpp", + "${services_path}/appmgr/src/app_death_recipient.cpp", + "${services_path}/appmgr/src/app_mgr_service.cpp", + "${services_path}/appmgr/src/app_mgr_service_event_handler.cpp", + "${services_path}/appmgr/src/app_mgr_service_inner.cpp", + "${services_path}/appmgr/src/app_running_record.cpp", + "${services_path}/appmgr/src/app_spawn_client.cpp", + "${services_path}/appmgr/src/app_spawn_msg_wrapper.cpp", + "${services_path}/appmgr/src/app_spawn_socket.cpp", + ] + + sources += [ "ams_service_event_drive_test.cpp" ] + + configs = [ "${libs_path}/libeventhandler:libeventhandler_config" ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${libs_path}/libeventhandler:libeventhandler_target", + "${services_path}/appmgr/test:appmgr_test_source", + "//base/startup/appspawn_standard:appspawn_socket_client", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "//foundation/appexecfwk/standard/services/appmgr:libams", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":AmsServiceEventDriveTest" ] +} diff --git a/services/appmgr/test/unittest/ams_service_event_drive_test/ams_service_event_drive_test.cpp b/services/appmgr/test/unittest/ams_service_event_drive_test/ams_service_event_drive_test.cpp new file mode 100644 index 000000000..76df7bb22 --- /dev/null +++ b/services/appmgr/test/unittest/ams_service_event_drive_test/ams_service_event_drive_test.cpp @@ -0,0 +1,961 @@ +/* + * 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. + */ + +// redefine private and protected since testcase need to invoke and test private function +#define private public +#define protected public +#include "app_mgr_service.h" +#undef private +#undef protected +#include +#include "app_log_wrapper.h" +#include "iremote_object.h" +#include "errors.h" +#include "mock_app_mgr_service_inner.h" + +using namespace testing; +using namespace testing::ext; +using namespace OHOS::AppExecFwk; +using OHOS::iface_cast; +using OHOS::IRemoteObject; +using OHOS::sptr; +using testing::_; +using testing::InvokeWithoutArgs; + +class AmsServiceEventDriveTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + + std::shared_ptr GetMockAppMgrServiceInner(); + std::shared_ptr GetAmsEventHandler(); + +protected: + std::shared_ptr appMgrService_; +}; + +void AmsServiceEventDriveTest::SetUpTestCase() +{} + +void AmsServiceEventDriveTest::TearDownTestCase() +{} + +void AmsServiceEventDriveTest::SetUp() +{ + appMgrService_ = std::make_shared(); +} + +void AmsServiceEventDriveTest::TearDown() +{} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if post AttachApplication task success + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_001, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_001 start"); + + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + innerService->SetWaitCount(2); + + EXPECT_CALL(*innerService, AddAppDeathRecipient(_, _)) + .WillOnce(InvokeWithoutArgs(innerService.get(), &MockAppMgrServiceInner::Post)); + EXPECT_CALL(*innerService, AttachApplication(_, _)) + .WillOnce(InvokeWithoutArgs(innerService.get(), &MockAppMgrServiceInner::Post)); + + sptr client; + appMgrService_->AttachApplication(client); + innerService->Wait(); + + APP_LOGI("ams_service_event_drive_test_001 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if post ApplicationForegrounded task success + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_002, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_002 start"); + + std::shared_ptr innerService = std::make_shared(); + std::unique_ptr appMgrService = std::make_unique(); + appMgrService->SetInnerService(innerService); + appMgrService->OnStart(); + + EXPECT_CALL(*innerService, ApplicationForegrounded(_)) + .WillOnce(InvokeWithoutArgs(innerService.get(), &MockAppMgrServiceInner::Post)); + + int32_t recordId = 0; + appMgrService->ApplicationForegrounded(recordId); + innerService->Wait(); + + APP_LOGI("ams_service_event_drive_test_002 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if post ApplicationBackgrounded task success + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_003, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_003 start"); + + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + + EXPECT_CALL(*innerService, ApplicationBackgrounded(_)) + .WillOnce(InvokeWithoutArgs(innerService.get(), &MockAppMgrServiceInner::Post)); + + int32_t recordId = 0; + appMgrService_->ApplicationBackgrounded(recordId); + innerService->Wait(); + + APP_LOGI("ams_service_event_drive_test_003 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if post ApplicationTerminated task success + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_004, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_004 start"); + + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + + EXPECT_CALL(*innerService, ApplicationTerminated(_)) + .WillOnce(InvokeWithoutArgs(innerService.get(), &MockAppMgrServiceInner::Post)); + + int32_t recordId = 0; + appMgrService_->ApplicationTerminated(recordId); + innerService->Wait(); + + APP_LOGI("ams_service_event_drive_test_004 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if post AbilityCleaned task success + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_005, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_005 start"); + + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + + EXPECT_CALL(*innerService, AbilityTerminated(_)) + .WillOnce(InvokeWithoutArgs(innerService.get(), &MockAppMgrServiceInner::Post)); + + sptr token; + appMgrService_->AbilityCleaned(token); + innerService->Wait(); + + APP_LOGI("ams_service_event_drive_test_005 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if post ClearUpApplicationData task success + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_006, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_006 start"); + + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + + EXPECT_CALL(*innerService, ClearUpApplicationData(_, _, _)) + .WillOnce(InvokeWithoutArgs(innerService.get(), &MockAppMgrServiceInner::Post)); + + std::string appName = "appName"; + appMgrService_->ClearUpApplicationData(appName); + innerService->Wait(); + + APP_LOGI("ams_service_event_drive_test_006 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if post IsBackgroundRunningRestricted task success + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_007, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_007 start"); + + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + + EXPECT_CALL(*innerService, IsBackgroundRunningRestricted(_)).WillOnce(Return(0)); + + std::string appName = "appName"; + EXPECT_EQ(0, appMgrService_->IsBackgroundRunningRestricted(appName)); + + APP_LOGI("ams_service_event_drive_test_007 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if post IsBackgroundRunningRestricted task success + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_008, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_008 start"); + + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + + EXPECT_CALL(*innerService, GetAllRunningProcesses(_)).WillOnce(Return(0)); + + std::shared_ptr runningProcessInfo = std::make_shared(); + EXPECT_EQ(0, appMgrService_->GetAllRunningProcesses(runningProcessInfo)); + + APP_LOGI("ams_service_event_drive_test_008 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if AttachApplication act normal without initialize AppMgrService + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_009, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_009 start"); + + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + + EXPECT_CALL(*innerService, AttachApplication(_, _)).Times(0); + + sptr client; + appMgrService_->AttachApplication(client); + + APP_LOGI("ams_service_event_drive_test_009 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if ApplicationForegrounded act normal without initialize AppMgrService + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_010, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_010 start"); + + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + + EXPECT_CALL(*innerService, ApplicationForegrounded(_)).Times(0); + + int32_t recordId = 0; + appMgrService_->ApplicationForegrounded(recordId); + + APP_LOGI("ams_service_event_drive_test_010 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if ApplicationBackgrounded act normal without initialize AppMgrService + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_011, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_011 start"); + + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + + EXPECT_CALL(*innerService, ApplicationBackgrounded(_)).Times(0); + + int32_t recordId = 0; + appMgrService_->ApplicationBackgrounded(recordId); + + APP_LOGI("ams_service_event_drive_test_011 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if ApplicationTerminated act normal without initialize AppMgrService + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_012, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_012 start"); + + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + + EXPECT_CALL(*innerService, ApplicationTerminated(_)).Times(0); + + int32_t recordId = 0; + appMgrService_->ApplicationTerminated(recordId); + + APP_LOGI("ams_service_event_drive_test_012 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if AbilityCleaned act normal without initialize AppMgrService + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_013, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_013 start"); + + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + + EXPECT_CALL(*innerService, AbilityTerminated(_)).Times(0); + + sptr token; + appMgrService_->AbilityCleaned(token); + + APP_LOGI("ams_service_event_drive_test_013 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if ClearUpApplicationData act normal without initialize AppMgrService + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_014, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_014 start"); + + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + + EXPECT_CALL(*innerService, ClearUpApplicationData(_, _, _)).Times(0); + + std::string appName = "appName"; + appMgrService_->ClearUpApplicationData(appName); + + APP_LOGI("ams_service_event_drive_test_014 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if IsBackgroundRunningRestricted act normal after AppMgrService stopped + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_015, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_015 start"); + + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + + std::string appName = "appName"; + EXPECT_EQ(OHOS::ERR_INVALID_OPERATION, appMgrService_->IsBackgroundRunningRestricted(appName)); + + APP_LOGI("ams_service_event_drive_test_015 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if GetAllRunningProcesses act normal after AppMgrService stopped + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_016, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_016 start"); + + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + + std::shared_ptr runningProcessInfo = std::make_shared(); + EXPECT_EQ(OHOS::ERR_INVALID_OPERATION, appMgrService_->GetAllRunningProcesses(runningProcessInfo)); + + APP_LOGI("ams_service_event_drive_test_016 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if AttachApplication act normal after AppMgrService stopped + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_017, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_017 start"); + + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + appMgrService_->OnStop(); + + EXPECT_CALL(*innerService, AttachApplication(_, _)).Times(0); + + sptr client; + appMgrService_->AttachApplication(client); + + APP_LOGI("ams_service_event_drive_test_017 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if ApplicationForegrounded act normal after AppMgrService stopped + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_018, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_018 start"); + + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + appMgrService_->OnStop(); + + EXPECT_CALL(*innerService, ApplicationForegrounded(_)).Times(0); + + int32_t recordId = 0; + appMgrService_->ApplicationForegrounded(recordId); + + APP_LOGI("ams_service_event_drive_test_018 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if ApplicationBackgrounded act normal after AppMgrService stopped + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_019, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_019 start"); + + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + appMgrService_->OnStop(); + + EXPECT_CALL(*innerService, ApplicationBackgrounded(_)).Times(0); + + int32_t recordId = 0; + appMgrService_->ApplicationBackgrounded(recordId); + + APP_LOGI("ams_service_event_drive_test_019 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if ApplicationTerminated act normal after AppMgrService stopped + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_020, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_020 start"); + + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + appMgrService_->OnStop(); + + EXPECT_CALL(*innerService, ApplicationTerminated(_)).Times(0); + + int32_t recordId = 0; + appMgrService_->ApplicationTerminated(recordId); + + APP_LOGI("ams_service_event_drive_test_020 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if AbilityCleaned act normal after AppMgrService stopped + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_021, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_021 start"); + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + appMgrService_->OnStop(); + + EXPECT_CALL(*innerService, AbilityTerminated(_)).Times(0); + + sptr token; + appMgrService_->AbilityCleaned(token); + + APP_LOGI("ams_service_event_drive_test_021 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if ClearUpApplicationData act normal after AppMgrService stopped + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_022, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_022 start"); + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + appMgrService_->OnStop(); + + EXPECT_CALL(*innerService, ClearUpApplicationData(_, _, _)).Times(0); + + std::string appName = "appName"; + appMgrService_->ClearUpApplicationData(appName); + + APP_LOGI("ams_service_event_drive_test_022 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if IsBackgroundRunningRestricted act normal after AppMgrService stopped + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_023, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_023 start"); + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + appMgrService_->OnStop(); + + std::string appName = "appName"; + EXPECT_EQ(OHOS::ERR_INVALID_OPERATION, appMgrService_->IsBackgroundRunningRestricted(appName)); + + APP_LOGI("ams_service_event_drive_test_023 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if GetAllRunningProcesses act normal after AppMgrService stopped + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_024, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_024 start"); + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + appMgrService_->OnStop(); + + appMgrService_->SetInnerService(innerService); + + std::shared_ptr runningProcessInfo = std::make_shared(); + EXPECT_EQ(OHOS::ERR_INVALID_OPERATION, appMgrService_->GetAllRunningProcesses(runningProcessInfo)); + + APP_LOGI("ams_service_event_drive_test_024 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if post application from background to foreground task act normal + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_025, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_025 start"); + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + int32_t waitCount = 2; + innerService->SetWaitCount(waitCount); + + EXPECT_CALL(*innerService, ApplicationBackgrounded(_)) + .WillOnce(InvokeWithoutArgs(innerService.get(), &MockAppMgrServiceInner::Post)); + EXPECT_CALL(*innerService, ApplicationForegrounded(_)) + .WillOnce(InvokeWithoutArgs(innerService.get(), &MockAppMgrServiceInner::Post)); + + int32_t recordId = 0; + appMgrService_->ApplicationBackgrounded(recordId); + appMgrService_->ApplicationForegrounded(recordId); + innerService->Wait(); + APP_LOGI("ams_service_event_drive_test_025 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if post application from foreground to background task act normal + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_026, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_026 start"); + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + int32_t waitCount = 2; + innerService->SetWaitCount(waitCount); + + EXPECT_CALL(*innerService, ApplicationForegrounded(_)) + .WillOnce(InvokeWithoutArgs(innerService.get(), &MockAppMgrServiceInner::Post)); + EXPECT_CALL(*innerService, ApplicationBackgrounded(_)) + .WillOnce(InvokeWithoutArgs(innerService.get(), &MockAppMgrServiceInner::Post)); + + int32_t recordId = 0; + appMgrService_->ApplicationForegrounded(recordId); + appMgrService_->ApplicationBackgrounded(recordId); + innerService->Wait(); + APP_LOGI("ams_service_event_drive_test_026 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if post application from background to terminate task act normal + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_027, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_027 start"); + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + int32_t waitCount = 2; + innerService->SetWaitCount(waitCount); + + EXPECT_CALL(*innerService, ApplicationBackgrounded(_)) + .WillOnce(InvokeWithoutArgs(innerService.get(), &MockAppMgrServiceInner::Post)); + EXPECT_CALL(*innerService, ApplicationTerminated(_)) + .WillOnce(InvokeWithoutArgs(innerService.get(), &MockAppMgrServiceInner::Post)); + + int32_t recordId = 0; + appMgrService_->ApplicationBackgrounded(recordId); + appMgrService_->ApplicationTerminated(recordId); + innerService->Wait(); + APP_LOGI("ams_service_event_drive_test_027 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if post application from foreground to terminated task act normal + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_028, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_028 start"); + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + int32_t waitCount = 2; + innerService->SetWaitCount(waitCount); + + EXPECT_CALL(*innerService, ApplicationForegrounded(_)) + .WillOnce(InvokeWithoutArgs(innerService.get(), &MockAppMgrServiceInner::Post)); + EXPECT_CALL(*innerService, ApplicationTerminated(_)) + .WillOnce(InvokeWithoutArgs(innerService.get(), &MockAppMgrServiceInner::Post)); + + int32_t recordId = 0; + appMgrService_->ApplicationForegrounded(recordId); + appMgrService_->ApplicationTerminated(recordId); + innerService->Wait(); + APP_LOGI("ams_service_event_drive_test_028 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if post application from terminate to foreground task act normal + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_029, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_029 start"); + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + int32_t waitCount = 2; + innerService->SetWaitCount(waitCount); + + EXPECT_CALL(*innerService, ApplicationTerminated(_)) + .WillOnce(InvokeWithoutArgs(innerService.get(), &MockAppMgrServiceInner::Post)); + EXPECT_CALL(*innerService, ApplicationForegrounded(_)) + .WillOnce(InvokeWithoutArgs(innerService.get(), &MockAppMgrServiceInner::Post)); + + int32_t recordId = 0; + appMgrService_->ApplicationTerminated(recordId); + appMgrService_->ApplicationForegrounded(recordId); + innerService->Wait(); + APP_LOGI("ams_service_event_drive_test_029 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework. + * CaseDescription: Verify if post application from terminate to background task act normal + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_030, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_030 start"); + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + int32_t waitCount = 2; + innerService->SetWaitCount(waitCount); + + EXPECT_CALL(*innerService, ApplicationTerminated(_)) + .WillOnce(InvokeWithoutArgs(innerService.get(), &MockAppMgrServiceInner::Post)); + EXPECT_CALL(*innerService, ApplicationBackgrounded(_)) + .WillOnce(InvokeWithoutArgs(innerService.get(), &MockAppMgrServiceInner::Post)); + + int32_t recordId = 0; + appMgrService_->ApplicationTerminated(recordId); + appMgrService_->ApplicationBackgrounded(recordId); + innerService->Wait(); + APP_LOGI("ams_service_event_drive_test_030 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if post AddAppDeathRecipient task success + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_034, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_034 start"); + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + + EXPECT_CALL(*innerService, AddAppDeathRecipient(_, _)) + .WillOnce(InvokeWithoutArgs(innerService.get(), &MockAppMgrServiceInner::Post)); + + pid_t pid = 1; + appMgrService_->AddAppDeathRecipient(pid); + innerService->Wait(); + APP_LOGI("ams_service_event_drive_test_034 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if AddAppDeathRecipient act normal without initialize AppMgrService + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_035, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_035 start"); + + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + + EXPECT_CALL(*innerService, AddAppDeathRecipient(_, _)).Times(0); + + pid_t pid = 1; + appMgrService_->AddAppDeathRecipient(pid); + + APP_LOGI("ams_service_event_drive_test_035 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if AddAppDeathRecipient act normal after AppMgrService stopped + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_036, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_036 start"); + + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + appMgrService_->OnStop(); + + EXPECT_CALL(*innerService, AddAppDeathRecipient(_, _)).Times(0); + + pid_t pid = 1; + appMgrService_->AddAppDeathRecipient(pid); + + APP_LOGI("ams_service_event_drive_test_036 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if QueryServiceState act normal + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_037, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_037 start"); + + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + + EXPECT_CALL(*innerService, QueryAppSpawnConnectionState()) + .WillRepeatedly(Return(SpawnConnectionState::STATE_CONNECTED)); + EXPECT_EQ(ServiceRunningState::STATE_RUNNING, appMgrService_->QueryServiceState().serviceRunningState); + EXPECT_EQ(SpawnConnectionState::STATE_CONNECTED, appMgrService_->QueryServiceState().connectionState); + + APP_LOGI("ams_service_event_drive_test_037 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if QueryServiceState act normal without initialize AppMgrService + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_038, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_038 start"); + + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + + EXPECT_CALL(*innerService, QueryAppSpawnConnectionState()).Times(2); + EXPECT_EQ(ServiceRunningState::STATE_NOT_START, appMgrService_->QueryServiceState().serviceRunningState); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appMgrService_->QueryServiceState().connectionState); + + APP_LOGI("ams_service_event_drive_test_038 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: EventDrive + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if QueryServiceState act normal after AppMgrService stopped + */ +HWTEST_F(AmsServiceEventDriveTest, EventDrive_039, TestSize.Level0) +{ + APP_LOGI("ams_service_event_drive_test_039 start"); + + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + appMgrService_->OnStop(); + + EXPECT_CALL(*innerService, QueryAppSpawnConnectionState()).Times(2); + EXPECT_EQ(ServiceRunningState::STATE_NOT_START, appMgrService_->QueryServiceState().serviceRunningState); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appMgrService_->QueryServiceState().connectionState); + + APP_LOGI("ams_service_event_drive_test_039 end"); +} diff --git a/services/appmgr/test/unittest/ams_service_load_ability_process_test/BUILD.gn b/services/appmgr/test/unittest/ams_service_load_ability_process_test/BUILD.gn new file mode 100644 index 000000000..eb3a57113 --- /dev/null +++ b/services/appmgr/test/unittest/ams_service_load_ability_process_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/appmgrservice" + +ohos_unittest("AmsServiceLoadAbilityProcessTest") { + module_out_path = module_output_path + + include_dirs = [ "${services_path}/appmgr/test/unittest/mocks" ] + + sources = [ + "${services_path}/appmgr/src/ability_running_record.cpp", + "${services_path}/appmgr/src/app_lifecycle_deal.cpp", + "${services_path}/appmgr/src/app_mgr_service_inner.cpp", + "${services_path}/appmgr/src/app_process_manager.cpp", + "${services_path}/appmgr/src/app_running_manager.cpp", + "${services_path}/appmgr/src/app_running_record.cpp", + "${services_path}/appmgr/src/app_spawn_client.cpp", + "${services_path}/appmgr/src/app_spawn_msg_wrapper.cpp", + "${services_path}/appmgr/src/app_spawn_socket.cpp", + "${services_path}/appmgr/src/cgroup_manager.cpp", + "${services_path}/appmgr/src/lmk_util.cpp", + "${services_path}/appmgr/src/lmkd_client.cpp", + "${services_path}/appmgr/src/process_optimizer.cpp", + "${services_path}/appmgr/src/process_optimizer_uba.cpp", + "${services_path}/appmgr/src/remote_client_manager.cpp", + "${services_path}/appmgr/test/mock/src/mock_bundle_manager.cpp", + ] + + sources += [ "ams_service_load_ability_process_test.cpp" ] + + configs = [ + "${services_path}/appmgr/test:appmgr_test_config", + "${libs_path}/libeventhandler:libeventhandler_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${libs_path}/libeventhandler:libeventhandler_target", + "${services_path}/appmgr/test:appmgr_test_source", + "//base/startup/appspawn_standard:appspawn_socket_client", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler:libeventhandler", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":AmsServiceLoadAbilityProcessTest" ] +} diff --git a/services/appmgr/test/unittest/ams_service_load_ability_process_test/ams_service_load_ability_process_test.cpp b/services/appmgr/test/unittest/ams_service_load_ability_process_test/ams_service_load_ability_process_test.cpp new file mode 100644 index 000000000..f6bc0a1ec --- /dev/null +++ b/services/appmgr/test/unittest/ams_service_load_ability_process_test/ams_service_load_ability_process_test.cpp @@ -0,0 +1,1094 @@ +/* + * 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. + */ + +#define private public +#include "app_mgr_service_inner.h" +#undef private + +#include +#include "gtest/gtest.h" +#include "ability_running_record.h" +#include "app_mgr_service.h" +#include "app_running_record.h" +#include "app_log_wrapper.h" +#include "app_record_id.h" +#include "ability_info.h" +#include "application_info.h" +#include "mock_app_scheduler.h" +#include "mock_bundle_manager.h" +#include "mock_ability_token.h" +#include "mock_app_spawn_client.h" + +using namespace testing::ext; +using testing::_; +using testing::Return; +using testing::SetArgReferee; +namespace OHOS { +namespace AppExecFwk { +class AmsServiceLoadAbilityProcessTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + +protected: + static const std::string GetTestAppName() + { + return "test_app_name"; + } + static const std::string GetTestAbilityName() + { + return "test_ability_name"; + } + + std::shared_ptr StartLoadAbility(const sptr &token, + const sptr &preToken, const std::shared_ptr &abilityInfo, + const std::shared_ptr &appInfo, const pid_t newPid) const; + + sptr GetMockToken() const + { + return mock_token_; + } + +protected: + std::unique_ptr service_; + sptr mock_token_; + sptr bundleMgr_; +}; + +void AmsServiceLoadAbilityProcessTest::SetUpTestCase() +{} + +void AmsServiceLoadAbilityProcessTest::TearDownTestCase() +{} + +void AmsServiceLoadAbilityProcessTest::SetUp() +{ + bundleMgr_ = new (std::nothrow) BundleMgrService(); + service_.reset(new (std::nothrow) AppMgrServiceInner()); + mock_token_ = new (std::nothrow) MockAbilityToken(); + if (service_) { + service_->SetBundleManager(bundleMgr_.GetRefPtr()); + } +} + +void AmsServiceLoadAbilityProcessTest::TearDown() +{} + +std::shared_ptr AmsServiceLoadAbilityProcessTest::StartLoadAbility(const sptr &token, + const sptr &preToken, const std::shared_ptr &abilityInfo, + const std::shared_ptr &appInfo, const pid_t newPid) const +{ + RecordQueryResult result; + std::shared_ptr mockClientPtr = std::make_shared(); + EXPECT_CALL(*mockClientPtr, StartProcess(_, _)).Times(1).WillOnce(DoAll(SetArgReferee<1>(newPid), Return(ERR_OK))); + + service_->SetAppSpawnClient(mockClientPtr); + service_->LoadAbility(token, preToken, abilityInfo, appInfo); + std::shared_ptr record = + service_->GetOrCreateAppRunningRecord(token, appInfo, abilityInfo, abilityInfo->process, 0, result); + EXPECT_EQ(record->GetPriorityObject()->GetPid(), newPid); + return record; +} + +/* + * Feature: AMS + * Function: Service + * SubFunction: NA + * FunctionPoints: When Service receive loadAbility requests. + * EnvConditions: NA + * CaseDescription: Normal loadAbility requesets handled inner service. + */ +HWTEST_F(AmsServiceLoadAbilityProcessTest, LoadAbility_001, TestSize.Level0) +{ + APP_LOGI("AmsServiceLoadAbilityProcessTest LoadAbility_001 start"); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + abilityInfo->process = GetTestAppName(); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + appInfo->bundleName = GetTestAppName(); + const pid_t PID = 1234; + EXPECT_TRUE(service_ != nullptr); + sptr token = GetMockToken(); + StartLoadAbility(token, nullptr, abilityInfo, appInfo, PID); + const auto &recordMap = service_->GetRecordMap(); + EXPECT_EQ(recordMap.size(), (uint32_t)1); + auto record = service_->GetAppRunningRecordByAppName(GetTestAppName()); + ASSERT_NE(record, nullptr); + EXPECT_EQ(record->GetState(), ApplicationState::APP_STATE_CREATE); + const auto &abilityMap = record->GetAbilities(); + EXPECT_EQ(abilityMap.size(), (uint32_t)1); + auto abilityRecord = record->GetAbilityRunningRecordByToken(token); + ASSERT_NE(abilityRecord, nullptr); + EXPECT_EQ(abilityRecord->GetState(), AbilityState::ABILITY_STATE_CREATE); + APP_LOGI("AmsServiceLoadAbilityProcessTest LoadAbility_001 end"); +} + +/* + * Feature: AMS + * Function: Service + * SubFunction: NA + * FunctionPoints: When Service receive loadAbility requests. + * EnvConditions: NA + * CaseDescription: Multiple different loadAbility requesets handled inner service. + */ +HWTEST_F(AmsServiceLoadAbilityProcessTest, LoadAbility_002, TestSize.Level0) +{ + APP_LOGI("AmsServiceLoadAbilityProcessTest LoadAbility_002 start"); + + EXPECT_TRUE(service_ != nullptr); + service_->ClearRecentAppList(); + + sptr token = GetMockToken(); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + abilityInfo->process = GetTestAppName(); + + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + appInfo->bundleName = GetTestAppName(); + appInfo->process = GetTestAppName(); + + const pid_t PID = 1234; + StartLoadAbility(token, nullptr, abilityInfo, appInfo, PID); + + const auto &recordMap = service_->GetRecordMap(); + EXPECT_EQ(recordMap.size(), (uint32_t)1); + auto record = service_->GetAppRunningRecordByAppName(GetTestAppName()); + ASSERT_NE(record, nullptr); + EXPECT_EQ(record->GetState(), ApplicationState::APP_STATE_CREATE); + const auto &abilityMap = record->GetAbilities(); + EXPECT_EQ(abilityMap.size(), (uint32_t)1); + + auto abilityRecord = record->GetAbilityRunningRecordByToken(token); + ASSERT_NE(abilityRecord, nullptr); + EXPECT_EQ(abilityRecord->GetState(), AbilityState::ABILITY_STATE_CREATE); + + sptr token2 = GetMockToken(); + auto abilityInfo2 = std::make_shared(); + abilityInfo2->name = GetTestAbilityName() + "_1"; + abilityInfo2->applicationName = GetTestAppName() + "_1"; + abilityInfo2->process = GetTestAppName() + "_1"; + + auto appInfo2 = std::make_shared(); + appInfo2->name = GetTestAppName() + "_1"; + appInfo2->bundleName = GetTestAppName() + "_1"; + const pid_t PID2 = 2234; + + StartLoadAbility(token2, nullptr, abilityInfo2, appInfo2, PID2); + const uint32_t EXPECT_MAP_SIZE = 2; + EXPECT_EQ(recordMap.size(), EXPECT_MAP_SIZE); + auto record2 = service_->GetAppRunningRecordByAppName(GetTestAppName() + "_1"); + ASSERT_NE(record2, nullptr); + EXPECT_EQ(record2->GetState(), ApplicationState::APP_STATE_CREATE); + auto abilityRecord2 = record2->GetAbilityRunningRecordByToken(token2); + ASSERT_NE(abilityRecord2, nullptr); + EXPECT_EQ(abilityRecord2->GetState(), AbilityState::ABILITY_STATE_CREATE); + APP_LOGI("AmsServiceLoadAbilityProcessTest LoadAbility_002 end"); +} + +/* + * Feature: AMS + * Function: Service + * SubFunction: NA + * FunctionPoints: When Service receive loadAbility requests. + * EnvConditions: NA + * CaseDescription: Null abilityId loadAbility requesets handled inner service. + */ +HWTEST_F(AmsServiceLoadAbilityProcessTest, LoadAbility_003, TestSize.Level0) +{ + APP_LOGI("AmsServiceLoadAbilityProcessTest LoadAbility_003 start"); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + appInfo->bundleName = GetTestAppName(); + EXPECT_TRUE(service_ != nullptr); + + std::shared_ptr mockClientPtr = std::make_shared(); + EXPECT_CALL(*mockClientPtr, StartProcess(_, _)).Times(0); + + service_->SetAppSpawnClient(mockClientPtr); + service_->LoadAbility(nullptr, nullptr, abilityInfo, appInfo); + + const auto &recordMap = service_->GetRecordMap(); + EXPECT_EQ(recordMap.size(), (uint32_t)0); + APP_LOGI("AmsServiceLoadAbilityProcessTest LoadAbility_003 end"); +} + +/* + * Feature: AMS + * Function: Service + * SubFunction: NA + * FunctionPoints: When Service receive loadAbility requests. + * EnvConditions: NA + * CaseDescription: Null abilityInfo name loadAbility requesets handled inner service. + */ +HWTEST_F(AmsServiceLoadAbilityProcessTest, LoadAbility_004, TestSize.Level0) +{ + APP_LOGI("AmsServiceLoadAbilityProcessTest LoadAbility_004 start"); + sptr token = GetMockToken(); + auto abilityInfo = std::make_shared(); + abilityInfo->name = ""; + abilityInfo->applicationName = GetTestAppName(); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + appInfo->bundleName = GetTestAppName(); + EXPECT_TRUE(service_ != nullptr); + + std::shared_ptr mockClientPtr = std::make_shared(); + EXPECT_CALL(*mockClientPtr, StartProcess(_, _)).Times(0); + + service_->SetAppSpawnClient(mockClientPtr); + service_->LoadAbility(token, nullptr, abilityInfo, appInfo); + const auto &recordMap = service_->GetRecordMap(); + EXPECT_EQ(recordMap.size(), (uint32_t)0); + APP_LOGI("AmsServiceLoadAbilityProcessTest LoadAbility_004 end"); +} + +/* + * Feature: AMS + * Function: Service + * SubFunction: NA + * FunctionPoints: When Service receive loadAbility requests. + * EnvConditions: NA + * CaseDescription: Null appInfo name loadAbility requesets handled inner service. + */ +HWTEST_F(AmsServiceLoadAbilityProcessTest, LoadAbility_005, TestSize.Level0) +{ + APP_LOGI("AmsServiceLoadAbilityProcessTest LoadAbility_005 start"); + sptr token = GetMockToken(); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = ""; + auto appInfo = std::make_shared(); + appInfo->name = ""; + appInfo->bundleName = ""; + EXPECT_TRUE(service_ != nullptr); + std::shared_ptr mockClientPtr = std::make_shared(); + EXPECT_CALL(*mockClientPtr, StartProcess(_, _)).Times(0); + + service_->SetAppSpawnClient(mockClientPtr); + service_->LoadAbility(token, nullptr, abilityInfo, appInfo); + const auto &recordMap = service_->GetRecordMap(); + EXPECT_EQ(recordMap.size(), (uint32_t)0); + APP_LOGI("AmsServiceLoadAbilityProcessTest LoadAbility_005 end"); +} + +/* + * Feature: AMS + * Function: Service + * SubFunction: NA + * FunctionPoints: When Service receive loadAbility requests. + * EnvConditions: NA + * CaseDescription: Different name loadAbility requesets handled inner service. + */ +HWTEST_F(AmsServiceLoadAbilityProcessTest, LoadAbility_006, TestSize.Level0) +{ + APP_LOGI("AmsServiceLoadAbilityProcessTest LoadAbility_006 start"); + sptr token = GetMockToken(); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName() + "_1"; + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + appInfo->bundleName = GetTestAppName(); + EXPECT_TRUE(service_ != nullptr); + + std::shared_ptr mockClientPtr = std::make_shared(); + EXPECT_CALL(*mockClientPtr, StartProcess(_, _)).Times(0); + + service_->SetAppSpawnClient(mockClientPtr); + service_->LoadAbility(token, nullptr, abilityInfo, appInfo); + const auto &recordMap = service_->GetRecordMap(); + EXPECT_EQ(recordMap.size(), (uint32_t)0); + APP_LOGI("AmsServiceLoadAbilityProcessTest LoadAbility_006 end"); +} + +/* + * Feature: AMS + * Function: Service + * SubFunction: NA + * FunctionPoints: When Service receive loadAbility requests. + * EnvConditions: NA + * CaseDescription: Multiple same loadAbility requesets handled inner service. + */ +HWTEST_F(AmsServiceLoadAbilityProcessTest, LoadAbility_007, TestSize.Level0) +{ + APP_LOGI("AmsServiceLoadAbilityProcessTest LoadAbility_007 start"); + sptr token = GetMockToken(); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + abilityInfo->process = GetTestAppName(); + + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + appInfo->bundleName = GetTestAppName(); + const pid_t PID = 1234; + EXPECT_TRUE(service_ != nullptr); + StartLoadAbility(token, nullptr, abilityInfo, appInfo, PID); + const auto &recordMap = service_->GetRecordMap(); + EXPECT_EQ(recordMap.size(), (uint32_t)1); + auto record = service_->GetAppRunningRecordByAppName(GetTestAppName()); + ASSERT_NE(record, nullptr); + EXPECT_EQ(record->GetState(), ApplicationState::APP_STATE_CREATE); + const auto &abilityMap = record->GetAbilities(); + EXPECT_EQ(abilityMap.size(), (uint32_t)1); + auto abilityRecord = record->GetAbilityRunningRecordByToken(token); + ASSERT_NE(abilityRecord, nullptr); + EXPECT_EQ(abilityRecord->GetState(), AbilityState::ABILITY_STATE_CREATE); + std::shared_ptr mockClientPtr = std::make_shared(); + EXPECT_CALL(*mockClientPtr, StartProcess(_, _)).Times(0); + + service_->SetAppSpawnClient(mockClientPtr); + service_->LoadAbility(token, nullptr, abilityInfo, appInfo); + EXPECT_EQ(recordMap.size(), (uint32_t)1); + auto record2 = service_->GetAppRunningRecordByAppName(GetTestAppName()); + EXPECT_EQ(record2, record); + const auto &abilityMap2 = record2->GetAbilities(); + EXPECT_EQ(abilityMap2.size(), (uint32_t)1); + APP_LOGI("AmsServiceLoadAbilityProcessTest LoadAbility_007 end"); +} + +/* + * Feature: AMS + * Function: Service + * SubFunction: NA + * FunctionPoints: When Service receive loadAbility requests. + * EnvConditions: NA + * CaseDescription: Multiple different ability with same appName loadAbility requesets handled inner service. + */ +HWTEST_F(AmsServiceLoadAbilityProcessTest, LoadAbility_008, TestSize.Level0) +{ + APP_LOGI("AmsServiceLoadAbilityProcessTest LoadAbility_008 start"); + sptr token = GetMockToken(); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + abilityInfo->process = GetTestAppName(); + + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + appInfo->bundleName = GetTestAppName(); + const pid_t PID = 1234; + EXPECT_TRUE(service_ != nullptr); + StartLoadAbility(token, nullptr, abilityInfo, appInfo, PID); + const auto &recordMap = service_->GetRecordMap(); + EXPECT_EQ(recordMap.size(), (uint32_t)1); + auto record = service_->GetAppRunningRecordByAppName(GetTestAppName()); + ASSERT_NE(record, nullptr); + EXPECT_EQ(record->GetState(), ApplicationState::APP_STATE_CREATE); + const auto &abilityMap = record->GetAbilities(); + EXPECT_EQ(abilityMap.size(), (uint32_t)1); + auto abilityRecord = record->GetAbilityRunningRecordByToken(token); + ASSERT_NE(abilityRecord, nullptr); + EXPECT_EQ(abilityRecord->GetState(), AbilityState::ABILITY_STATE_CREATE); + sptr token2 = new MockAbilityToken(); + sptr preToken = token; + auto abilityInfo2 = std::make_shared(); + abilityInfo2->name = GetTestAbilityName() + "_1"; + abilityInfo2->applicationName = GetTestAppName(); + const uint32_t EXPECT_MAP_SIZE = 2; + std::shared_ptr mockClientPtr = std::make_shared(); + EXPECT_CALL(*mockClientPtr, StartProcess(_, _)).Times(0); + + service_->SetAppSpawnClient(mockClientPtr); + service_->LoadAbility(token2, preToken, abilityInfo2, appInfo); + EXPECT_EQ(recordMap.size(), (uint32_t)1); + auto record2 = service_->GetAppRunningRecordByAppName(GetTestAppName()); + EXPECT_EQ(record2, record); + const auto &abilityMap2 = record2->GetAbilities(); + EXPECT_EQ(abilityMap2.size(), EXPECT_MAP_SIZE); + auto abilityRecord2 = record2->GetAbilityRunningRecordByToken(token2); + ASSERT_NE(abilityRecord2, nullptr); + EXPECT_EQ(abilityRecord2->GetState(), AbilityState::ABILITY_STATE_CREATE); + EXPECT_EQ(abilityRecord2->GetPreToken(), token); + APP_LOGI("AmsServiceLoadAbilityProcessTest LoadAbility_008 end"); +} + +/* + * Feature: AMS + * Function: Service + * SubFunction: NA + * FunctionPoints: When Service receive loadAbility requests and needd create new process. + * EnvConditions: NA + * CaseDescription: Normal loadAbility requesets handled when start process success. + */ +HWTEST_F(AmsServiceLoadAbilityProcessTest, RequestProcess_001, TestSize.Level0) +{ + APP_LOGI("AmsServiceLoadAbilityProcessTest RequestProcess_001 start"); + sptr token = GetMockToken(); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + abilityInfo->process = GetTestAppName(); + + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + appInfo->bundleName = GetTestAppName(); + const pid_t PID = 1234; + EXPECT_TRUE(service_ != nullptr); + std::shared_ptr mockClientPtr = std::make_shared(); + EXPECT_CALL(*mockClientPtr, StartProcess(_, _)).Times(1).WillOnce(DoAll(SetArgReferee<1>(PID), Return(ERR_OK))); + + service_->SetAppSpawnClient(mockClientPtr); + service_->LoadAbility(token, nullptr, abilityInfo, appInfo); + + const auto &recordMap = service_->GetRecordMap(); + EXPECT_EQ(recordMap.size(), (uint32_t)1); + auto record = service_->GetAppRunningRecordByAppName(GetTestAppName()); + ASSERT_NE(record, nullptr); + EXPECT_EQ(record->GetPriorityObject()->GetPid(), PID); + EXPECT_EQ(record->GetState(), ApplicationState::APP_STATE_CREATE); + APP_LOGI("AmsServiceLoadAbilityProcessTest RequestProcess_001 end"); +} + +/* + * Feature: AMS + * Function: Service + * SubFunction: NA + * FunctionPoints: When Service receive loadAbility requests and needd create new process. + * EnvConditions: NA + * CaseDescription: Normal loadAbility requesets handled when start process failed. + */ +HWTEST_F(AmsServiceLoadAbilityProcessTest, RequestProcess_002, TestSize.Level0) +{ + APP_LOGI("AmsServiceLoadAbilityProcessTest RequestProcess_002 start"); + sptr token = GetMockToken(); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + abilityInfo->process = GetTestAppName(); + + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + appInfo->bundleName = GetTestAppName(); + EXPECT_TRUE(service_ != nullptr); + std::shared_ptr mockClientPtr = std::make_shared(); + EXPECT_CALL(*mockClientPtr, StartProcess(_, _)).Times(1).WillOnce(Return(ERR_APPEXECFWK_INVALID_PID)); + + service_->SetAppSpawnClient(mockClientPtr); + service_->LoadAbility(token, nullptr, abilityInfo, appInfo); + + const auto &recordMap = service_->GetRecordMap(); + EXPECT_EQ(recordMap.size(), (uint32_t)0); + APP_LOGI("AmsServiceLoadAbilityProcessTest RequestProcess_002 end"); +} + +/* + * Feature: AMS + * Function: Service + * SubFunction: NA + * FunctionPoints: the Service save pid to app running record when create new process successfully. + * EnvConditions: NA + * CaseDescription: Normal loadAbility and save pid to app running record. + */ +HWTEST_F(AmsServiceLoadAbilityProcessTest, SavePid_001, TestSize.Level0) +{ + APP_LOGI("AmsServiceLoadAbilityProcessTest SavePid_001 start"); + sptr token = GetMockToken(); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + abilityInfo->process = GetTestAppName(); + + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + appInfo->bundleName = GetTestAppName(); + const pid_t PID = 1234; + EXPECT_TRUE(service_ != nullptr); + std::shared_ptr mockClientPtr = std::make_shared(); + EXPECT_CALL(*mockClientPtr, StartProcess(_, _)).Times(1).WillOnce(DoAll(SetArgReferee<1>(PID), Return(ERR_OK))); + + service_->SetAppSpawnClient(mockClientPtr); + service_->LoadAbility(token, nullptr, abilityInfo, appInfo); + + auto record = service_->GetAppRunningRecordByAppName(GetTestAppName()); + EXPECT_EQ(record->GetPriorityObject()->GetPid(), PID); + APP_LOGI("AmsServiceLoadAbilityProcessTest SavePid_001 end"); +} + +/* + * Feature: AMS + * Function: Service + * SubFunction: NA + * FunctionPoints: the Service save pid to app running record when create new process failed. + * EnvConditions: NA + * CaseDescription: The service can't save pid to app running record when create new process failed. + */ +HWTEST_F(AmsServiceLoadAbilityProcessTest, SavePid_002, TestSize.Level0) +{ + APP_LOGI("AmsServiceLoadAbilityProcessTest SavePid_002 start"); + sptr token = GetMockToken(); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + appInfo->bundleName = GetTestAppName(); + EXPECT_TRUE(service_ != nullptr); + std::shared_ptr mockClientPtr = std::make_shared(); + EXPECT_CALL(*mockClientPtr, StartProcess(_, _)).Times(1).WillOnce(Return(ERR_APPEXECFWK_INVALID_PID)); + + service_->SetAppSpawnClient(mockClientPtr); + service_->LoadAbility(token, nullptr, abilityInfo, appInfo); + + auto record = service_->GetAppRunningRecordByAppName(GetTestAppName()); + EXPECT_EQ(record, nullptr); + APP_LOGI("AmsServiceLoadAbilityProcessTest SavePid_002 end"); +} + +/* + * Feature: AMS + * Function: Service + * SubFunction: NA + * FunctionPoints: When Service receive loadAbility requests. + * EnvConditions: NA + * CaseDescription: Normal loadAbility requeset with singleton launch mode handled inner service. + */ +HWTEST_F(AmsServiceLoadAbilityProcessTest, LaunchMode_001, TestSize.Level0) +{ + APP_LOGI("AmsServiceLoadAbilityProcessTest LaunchMode_001 start"); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + abilityInfo->process = GetTestAppName(); + abilityInfo->launchMode = LaunchMode::SINGLETON; + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + appInfo->bundleName = GetTestAppName(); + const pid_t PID = 1234; + EXPECT_TRUE(service_ != nullptr); + sptr token = GetMockToken(); + StartLoadAbility(token, nullptr, abilityInfo, appInfo, PID); + const auto &recordMap = service_->GetRecordMap(); + EXPECT_EQ(recordMap.size(), (uint32_t)1); + auto record = service_->GetAppRunningRecordByAppName(GetTestAppName()); + ASSERT_NE(record, nullptr); + EXPECT_EQ(record->GetState(), ApplicationState::APP_STATE_CREATE); + const auto &abilityMap = record->GetAbilities(); + EXPECT_EQ(abilityMap.size(), (uint32_t)1); + auto abilityRecord = record->GetAbilityRunningRecordByToken(token); + ASSERT_NE(abilityRecord, nullptr); + EXPECT_EQ(abilityRecord->GetState(), AbilityState::ABILITY_STATE_CREATE); + APP_LOGI("AmsServiceLoadAbilityProcessTest LaunchMode_001 end"); +} + +/* + * Feature: AMS + * Function: Service + * SubFunction: NA + * FunctionPoints: When Service receive loadAbility requests. + * EnvConditions: NA + * CaseDescription: Multiple same loadAbility requesets with singleton launch mode and same ability info. + */ +HWTEST_F(AmsServiceLoadAbilityProcessTest, LaunchMode_002, TestSize.Level0) +{ + APP_LOGI("AmsServiceLoadAbilityProcessTest LaunchMode_002 start"); + sptr token = GetMockToken(); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + abilityInfo->process = GetTestAppName(); + abilityInfo->launchMode = LaunchMode::SINGLETON; + + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + appInfo->bundleName = GetTestAppName(); + const pid_t PID = 1234; + EXPECT_TRUE(service_ != nullptr); + StartLoadAbility(token, nullptr, abilityInfo, appInfo, PID); + const auto &recordMap = service_->GetRecordMap(); + EXPECT_EQ(recordMap.size(), (uint32_t)1); + auto record = service_->GetAppRunningRecordByAppName(GetTestAppName()); + ASSERT_NE(record, nullptr); + EXPECT_EQ(record->GetState(), ApplicationState::APP_STATE_CREATE); + const auto &abilityMap = record->GetAbilities(); + EXPECT_EQ(abilityMap.size(), (uint32_t)1); + auto abilityRecord = record->GetAbilityRunningRecordByToken(token); + ASSERT_NE(abilityRecord, nullptr); + EXPECT_EQ(abilityRecord->GetState(), AbilityState::ABILITY_STATE_CREATE); + std::shared_ptr mockClientPtr = std::make_shared(); + EXPECT_CALL(*mockClientPtr, StartProcess(_, _)).Times(0); + sptr token2 = new MockAbilityToken(); + sptr preToken = token; + service_->SetAppSpawnClient(mockClientPtr); + service_->LoadAbility(token2, preToken, abilityInfo, appInfo); + EXPECT_EQ(recordMap.size(), (uint32_t)1); + auto record2 = service_->GetAppRunningRecordByAppName(GetTestAppName()); + EXPECT_EQ(record2, record); + const auto &abilityMap2 = record2->GetAbilities(); + EXPECT_EQ(abilityMap2.size(), (uint32_t)1); + APP_LOGI("AmsServiceLoadAbilityProcessTest LaunchMode_002 end"); +} + +/* + * Feature: AMS + * Function: Service + * SubFunction: NA + * FunctionPoints: When Service receive startAbility requests. + * EnvConditions: NA + * CaseDescription: startAbility requesets with ability info. + */ +HWTEST_F(AmsServiceLoadAbilityProcessTest, StartAbility_001, TestSize.Level0) +{ + APP_LOGI("AmsServiceLoadAbilityProcessTest StartAbility_001 start"); + sptr token = GetMockToken(); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + abilityInfo->process = GetTestAppName(); + + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + appInfo->bundleName = GetTestAppName(); + const pid_t PID = 1234; + EXPECT_TRUE(service_ != nullptr); + StartLoadAbility(token, nullptr, abilityInfo, appInfo, PID); + const auto &recordMap = service_->GetRecordMap(); + EXPECT_EQ(recordMap.size(), (uint32_t)1); + auto record = service_->GetAppRunningRecordByAppName(GetTestAppName()); + ASSERT_NE(record, nullptr); + EXPECT_EQ(record->GetState(), ApplicationState::APP_STATE_CREATE); + const auto &abilityMap = record->GetAbilities(); + EXPECT_EQ(abilityMap.size(), (uint32_t)1); + auto abilityRecord = record->GetAbilityRunningRecordByToken(token); + ASSERT_NE(abilityRecord, nullptr); + EXPECT_EQ(abilityRecord->GetState(), AbilityState::ABILITY_STATE_CREATE); + sptr token2 = new MockAbilityToken(); + auto abilityInfo2 = std::make_shared(); + abilityInfo2->name = GetTestAbilityName() + "_1"; + abilityInfo2->applicationName = GetTestAppName(); + abilityInfo2->process = GetTestAppName(); + + record->SetState(ApplicationState::APP_STATE_FOREGROUND); + sptr mockAppScheduler = new MockAppScheduler(); + sptr client = iface_cast(mockAppScheduler.GetRefPtr()); + record->SetApplicationClient(client); + EXPECT_CALL(*mockAppScheduler, ScheduleLaunchAbility(_, _)).Times(1); + + service_->StartAbility(token2, token, abilityInfo2, record); + auto record1 = service_->GetAppRunningRecordByAppName(GetTestAppName()); + const auto &abilityMap1 = record1->GetAbilities(); + EXPECT_EQ(abilityMap1.size(), (uint32_t)2); + auto abilityrecord1 = record1->GetAbilityRunningRecordByToken(token2); + ASSERT_NE(abilityrecord1, nullptr); + EXPECT_EQ(abilityrecord1->GetState(), AbilityState::ABILITY_STATE_READY); + APP_LOGI("AmsServiceLoadAbilityProcessTest StartAbility_001 end"); +} + +/* + * Feature: AMS + * Function: Service + * SubFunction: NA + * FunctionPoints: When Service receive startAbility requests. + * EnvConditions: NA + * CaseDescription: startAbility requesets with not apprecord. + */ +HWTEST_F(AmsServiceLoadAbilityProcessTest, StartAbility_002, TestSize.Level0) +{ + APP_LOGI("AmsServiceLoadAbilityProcessTest StartAbility_002 start"); + sptr token = GetMockToken(); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + abilityInfo->process = GetTestAppName(); + + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + const pid_t PID = 1234; + EXPECT_TRUE(service_ != nullptr); + StartLoadAbility(token, nullptr, abilityInfo, appInfo, PID); + const auto &recordMap = service_->GetRecordMap(); + EXPECT_EQ(recordMap.size(), (uint32_t)1); + auto record = service_->GetAppRunningRecordByAppName(GetTestAppName()); + ASSERT_NE(record, nullptr); + EXPECT_EQ(record->GetState(), ApplicationState::APP_STATE_CREATE); + const auto &abilityMap = record->GetAbilities(); + EXPECT_EQ(abilityMap.size(), (uint32_t)1); + auto abilityRecord = record->GetAbilityRunningRecordByToken(token); + ASSERT_NE(abilityRecord, nullptr); + EXPECT_EQ(abilityRecord->GetState(), AbilityState::ABILITY_STATE_CREATE); + sptr token2 = new MockAbilityToken(); + auto abilityInfo2 = std::make_shared(); + abilityInfo2->name = GetTestAbilityName() + "_1"; + abilityInfo2->applicationName = GetTestAppName(); + abilityInfo2->process = GetTestAppName(); + record->SetState(ApplicationState::APP_STATE_FOREGROUND); + sptr mockAppScheduler = new MockAppScheduler(); + sptr client = iface_cast(mockAppScheduler.GetRefPtr()); + record->SetApplicationClient(client); + EXPECT_CALL(*mockAppScheduler, ScheduleLaunchAbility(_, _)).Times(0); + + service_->StartAbility(token2, token, abilityInfo2, nullptr); + auto record1 = service_->GetAppRunningRecordByAppName(GetTestAppName()); + const auto &abilityMap1 = record1->GetAbilities(); + EXPECT_EQ(abilityMap1.size(), (uint32_t)1); + APP_LOGI("AmsServiceLoadAbilityProcessTest StartAbility_002 end"); +} + +/* + * Feature: AMS + * Function: Service + * SubFunction: NA + * FunctionPoints: When Service receive startAbility requests. + * EnvConditions: NA + * CaseDescription: startAbility requesets with the same LaunchMode. + */ +HWTEST_F(AmsServiceLoadAbilityProcessTest, StartAbility_003, TestSize.Level0) +{ + APP_LOGI("AmsServiceLoadAbilityProcessTest StartAbility_003 start"); + sptr token = GetMockToken(); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + abilityInfo->process = GetTestAppName(); + abilityInfo->launchMode = LaunchMode::SINGLETON; + + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + appInfo->bundleName = GetTestAppName(); + + const pid_t PID = 1234; + EXPECT_TRUE(service_ != nullptr); + StartLoadAbility(token, nullptr, abilityInfo, appInfo, PID); + const auto &recordMap = service_->GetRecordMap(); + EXPECT_EQ(recordMap.size(), (uint32_t)1); + auto record = service_->GetAppRunningRecordByAppName(GetTestAppName()); + ASSERT_NE(record, nullptr); + EXPECT_EQ(record->GetState(), ApplicationState::APP_STATE_CREATE); + const auto &abilityMap = record->GetAbilities(); + EXPECT_EQ(abilityMap.size(), (uint32_t)1); + auto abilityRecord = record->GetAbilityRunningRecordByToken(token); + ASSERT_NE(abilityRecord, nullptr); + EXPECT_EQ(abilityRecord->GetState(), AbilityState::ABILITY_STATE_CREATE); + + sptr token2 = new MockAbilityToken(); + auto abilityInfo2 = std::make_shared(); + abilityInfo2->name = GetTestAbilityName() + "_1"; + abilityInfo2->launchMode = LaunchMode::SINGLETON; + abilityInfo2->process = GetTestAppName(); + abilityInfo2->applicationName = GetTestAppName(); + + record->SetState(ApplicationState::APP_STATE_FOREGROUND); + sptr mockAppScheduler = new MockAppScheduler(); + sptr client = iface_cast(mockAppScheduler.GetRefPtr()); + record->SetApplicationClient(client); + EXPECT_CALL(*mockAppScheduler, ScheduleLaunchAbility(_, _)).Times(0); + service_->StartAbility(token2, token, abilityInfo2, nullptr); + auto record1 = service_->GetAppRunningRecordByAppName(GetTestAppName()); + const auto &abilityMap1 = record1->GetAbilities(); + EXPECT_EQ(abilityMap1.size(), (uint32_t)1); + APP_LOGI("AmsServiceLoadAbilityProcessTest StartAbility_003 end"); +} + +/* + * Feature: AMS + * Function: Service + * SubFunction: NA + * FunctionPoints: When Service receive startAbility requests. + * EnvConditions: NA + * CaseDescription: startAbility requesets with not token. + */ +HWTEST_F(AmsServiceLoadAbilityProcessTest, StartAbility_004, TestSize.Level0) +{ + APP_LOGI("AmsServiceLoadAbilityProcessTest StartAbility_004 start"); + sptr token = GetMockToken(); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + abilityInfo->process = GetTestAppName(); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + appInfo->bundleName = GetTestAppName(); + const pid_t PID = 1234; + EXPECT_TRUE(service_ != nullptr); + StartLoadAbility(token, nullptr, abilityInfo, appInfo, PID); + const auto &recordMap = service_->GetRecordMap(); + EXPECT_EQ(recordMap.size(), (uint32_t)1); + auto record = service_->GetAppRunningRecordByAppName(GetTestAppName()); + ASSERT_NE(record, nullptr); + EXPECT_EQ(record->GetState(), ApplicationState::APP_STATE_CREATE); + const auto &abilityMap = record->GetAbilities(); + EXPECT_EQ(abilityMap.size(), (uint32_t)1); + auto abilityRecord = record->GetAbilityRunningRecordByToken(token); + ASSERT_NE(abilityRecord, nullptr); + EXPECT_EQ(abilityRecord->GetState(), AbilityState::ABILITY_STATE_CREATE); + auto abilityInfo2 = std::make_shared(); + abilityInfo2->name = GetTestAbilityName() + "_1"; + abilityInfo2->applicationName = GetTestAppName(); + abilityInfo2->process = GetTestAppName(); + record->SetState(ApplicationState::APP_STATE_FOREGROUND); + sptr mockAppScheduler = new MockAppScheduler(); + sptr client = iface_cast(mockAppScheduler.GetRefPtr()); + record->SetApplicationClient(client); + EXPECT_CALL(*mockAppScheduler, ScheduleLaunchAbility(_, _)).Times(0); + service_->StartAbility(nullptr, token, abilityInfo2, nullptr); + + auto record1 = service_->GetAppRunningRecordByAppName(GetTestAppName()); + const auto &abilityMap1 = record1->GetAbilities(); + EXPECT_EQ(abilityMap1.size(), (uint32_t)1); + APP_LOGI("AmsServiceLoadAbilityProcessTest StartAbility_004 end"); +} + +/* + * Feature: AMS + * Function: Service + * SubFunction: NA + * FunctionPoints: When Service receive startAbility requests. + * EnvConditions: NA + * CaseDescription: startAbility requesets with not preToken. + */ +HWTEST_F(AmsServiceLoadAbilityProcessTest, StartAbility_005, TestSize.Level0) +{ + APP_LOGI("AmsServiceLoadAbilityProcessTest StartAbility_005 start"); + sptr token = GetMockToken(); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + abilityInfo->process = GetTestAppName(); + + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + appInfo->bundleName = GetTestAppName(); + const pid_t PID = 1234; + + EXPECT_TRUE(service_ != nullptr); + StartLoadAbility(token, nullptr, abilityInfo, appInfo, PID); + const auto &recordMap = service_->GetRecordMap(); + EXPECT_EQ(recordMap.size(), (uint32_t)1); + auto record = service_->GetAppRunningRecordByAppName(GetTestAppName()); + ASSERT_NE(record, nullptr); + EXPECT_EQ(record->GetState(), ApplicationState::APP_STATE_CREATE); + const auto &abilityMap = record->GetAbilities(); + EXPECT_EQ(abilityMap.size(), (uint32_t)1); + auto abilityRecord = record->GetAbilityRunningRecordByToken(token); + ASSERT_NE(abilityRecord, nullptr); + EXPECT_EQ(abilityRecord->GetState(), AbilityState::ABILITY_STATE_CREATE); + sptr token2 = new MockAbilityToken(); + auto abilityInfo2 = std::make_shared(); + abilityInfo2->name = GetTestAbilityName() + "_1"; + abilityInfo2->applicationName = GetTestAppName(); + abilityInfo2->process = GetTestAppName(); + record->SetState(ApplicationState::APP_STATE_FOREGROUND); + sptr mockAppScheduler = new MockAppScheduler(); + sptr client = iface_cast(mockAppScheduler.GetRefPtr()); + record->SetApplicationClient(client); + EXPECT_CALL(*mockAppScheduler, ScheduleLaunchAbility(_, _)).Times(1); + service_->StartAbility(token2, nullptr, abilityInfo2, record); + auto record1 = service_->GetAppRunningRecordByAppName(GetTestAppName()); + const auto &abilityMap1 = record1->GetAbilities(); + EXPECT_EQ(abilityMap1.size(), (uint32_t)2); + auto abilityrecord1 = record1->GetAbilityRunningRecordByToken(token2); + ASSERT_NE(abilityrecord1, nullptr); + EXPECT_EQ(abilityrecord1->GetState(), AbilityState::ABILITY_STATE_READY); + APP_LOGI("AmsServiceLoadAbilityProcessTest StartAbility_005 end"); +} + +/* + * Feature: AMS + * Function: Service + * SubFunction: NA + * FunctionPoints: When Service receive startAbility requests. + * EnvConditions: NA + * CaseDescription: startAbility requesets with ABILITY_STATE_CREATE. + */ +HWTEST_F(AmsServiceLoadAbilityProcessTest, StartAbility_006, TestSize.Level0) +{ + APP_LOGI("AmsServiceLoadAbilityProcessTest StartAbility_006 start"); + sptr token = GetMockToken(); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + abilityInfo->process = GetTestAppName(); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + appInfo->bundleName = GetTestAppName(); + const pid_t PID = 1234; + EXPECT_TRUE(service_ != nullptr); + StartLoadAbility(token, nullptr, abilityInfo, appInfo, PID); + const auto &recordMap = service_->GetRecordMap(); + EXPECT_EQ(recordMap.size(), (uint32_t)1); + auto record = service_->GetAppRunningRecordByAppName(GetTestAppName()); + ASSERT_NE(record, nullptr); + EXPECT_EQ(record->GetState(), ApplicationState::APP_STATE_CREATE); + const auto &abilityMap = record->GetAbilities(); + EXPECT_EQ(abilityMap.size(), (uint32_t)1); + auto abilityRecord = record->GetAbilityRunningRecordByToken(token); + ASSERT_NE(abilityRecord, nullptr); + EXPECT_EQ(abilityRecord->GetState(), AbilityState::ABILITY_STATE_CREATE); + auto abilityInfo2 = std::make_shared(); + abilityInfo2->name = GetTestAbilityName() + "_1"; + abilityInfo2->applicationName = GetTestAppName(); + abilityInfo2->process = GetTestAppName(); + sptr mockAppScheduler = new MockAppScheduler(); + sptr client = iface_cast(mockAppScheduler.GetRefPtr()); + record->SetApplicationClient(client); + EXPECT_CALL(*mockAppScheduler, ScheduleLaunchAbility(_, _)).Times(0); + service_->StartAbility(nullptr, token, abilityInfo2, nullptr); + auto record1 = service_->GetAppRunningRecordByAppName(GetTestAppName()); + const auto &abilityMap1 = record1->GetAbilities(); + EXPECT_EQ(abilityMap1.size(), (uint32_t)1); + APP_LOGI("AmsServiceLoadAbilityProcessTest StartAbility_006 end"); +} + +/* + * Feature: AMS + * Function: Service + * SubFunction: NA + * FunctionPoints: When Service receive StartProcess requests. + * EnvConditions: NA + * CaseDescription: Normal StartProcess requesets handled inner service. + */ +HWTEST_F(AmsServiceLoadAbilityProcessTest, StartProcess001, TestSize.Level0) +{ + APP_LOGI("AmsServiceLoadAbilityProcessTest StartProcess001 start"); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + abilityInfo->process = GetTestAppName(); + + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + appInfo->bundleName = GetTestAppName(); + const pid_t PID = 1234; + EXPECT_TRUE(service_ != nullptr); + sptr token = GetMockToken(); + RecordQueryResult result; + std::shared_ptr mockClientPtr = std::make_shared(); + EXPECT_CALL(*mockClientPtr, StartProcess(_, _)).Times(1).WillOnce(DoAll(SetArgReferee<1>(PID), Return(ERR_OK))); + service_->SetAppSpawnClient(mockClientPtr); + std::shared_ptr record = + service_->GetOrCreateAppRunningRecord(token, appInfo, abilityInfo, GetTestAppName(), 0, result); + service_->StartProcess(abilityInfo->applicationName, GetTestAppName(), record); + const auto &recordMap = service_->GetRecordMap(); + EXPECT_EQ(recordMap.size(), (uint32_t)1); + auto record1 = service_->GetAppRunningRecordByAppName(GetTestAppName()); + EXPECT_EQ(record1->GetPriorityObject()->GetPid(), PID); + ASSERT_NE(record1, nullptr); + EXPECT_EQ(record1->GetState(), ApplicationState::APP_STATE_CREATE); + const auto &abilityMap = record1->GetAbilities(); + EXPECT_EQ(abilityMap.size(), (uint32_t)1); + auto abilityRecord = record1->GetAbilityRunningRecordByToken(token); + ASSERT_NE(abilityRecord, nullptr); + EXPECT_EQ(abilityRecord->GetState(), AbilityState::ABILITY_STATE_CREATE); + APP_LOGI("AmsServiceLoadAbilityProcessTest StartProcess001 end"); +} + +/* + * Feature: AMS + * Function: Service + * SubFunction: NA + * FunctionPoints: When Service receive StartProcess requests. + * EnvConditions: NA + * CaseDescription: Normal StartProcess requesets with not SpawnClient. + */ +HWTEST_F(AmsServiceLoadAbilityProcessTest, StartProcess002, TestSize.Level0) +{ + APP_LOGI("AmsServiceLoadAbilityProcessTest StartProcess002 start"); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + EXPECT_TRUE(service_ != nullptr); + sptr token = GetMockToken(); + RecordQueryResult result; + std::shared_ptr record = + service_->GetOrCreateAppRunningRecord(token, appInfo, abilityInfo, GetTestAppName(), 0, result); + service_->SetAppSpawnClient(nullptr); + service_->StartProcess(abilityInfo->applicationName, GetTestAppName(), record); + const auto &recordMap = service_->GetRecordMap(); + EXPECT_EQ(recordMap.size(), (uint32_t)1); + auto record1 = service_->GetAppRunningRecordByAppName(GetTestAppName()); + ASSERT_NE(record1, nullptr); + APP_LOGI("AmsServiceLoadAbilityProcessTest StartProcess002 end"); +} + +/* + * Feature: AMS + * Function: Service + * SubFunction: NA + * FunctionPoints: When Service receive StartProcess requests. + * EnvConditions: NA + * CaseDescription: Normal StartProcess requesets with not AppRecord. + */ +HWTEST_F(AmsServiceLoadAbilityProcessTest, StartProcess003, TestSize.Level0) +{ + APP_LOGI("AmsServiceLoadAbilityProcessTest StartProcess003 start"); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + EXPECT_TRUE(service_ != nullptr); + sptr token = GetMockToken(); + RecordQueryResult result; + std::shared_ptr mockClientPtr = std::make_shared(); + service_->SetAppSpawnClient(mockClientPtr); + std::shared_ptr record = + service_->GetOrCreateAppRunningRecord(token, appInfo, abilityInfo, GetTestAppName(), 0, result); + service_->StartProcess(abilityInfo->applicationName, GetTestAppName(), nullptr); + const auto &recordMap = service_->GetRecordMap(); + EXPECT_EQ(recordMap.size(), (uint32_t)1); + auto record1 = service_->GetAppRunningRecordByAppName(GetTestAppName()); + ASSERT_NE(record1, nullptr); + APP_LOGI("AmsServiceLoadAbilityProcessTest StartProcess003 end"); +} + +/* + * Feature: AMS + * Function: Service + * SubFunction: NA + * FunctionPoints: When Service receive StartProcess requests. + * EnvConditions: NA + * CaseDescription: Normal StartProcess requesets with StartProcess return fail. + */ +HWTEST_F(AmsServiceLoadAbilityProcessTest, StartProcess004, TestSize.Level0) +{ + APP_LOGI("AmsServiceLoadAbilityProcessTest StartProcess004 start"); + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(); + abilityInfo->applicationName = GetTestAppName(); + abilityInfo->process = GetTestAppName(); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(); + appInfo->bundleName = GetTestAppName(); + const pid_t PID = 1234; + EXPECT_TRUE(service_ != nullptr); + sptr token = GetMockToken(); + RecordQueryResult result; + std::shared_ptr mockClientPtr = std::make_shared(); + service_->SetAppSpawnClient(mockClientPtr); + EXPECT_CALL(*mockClientPtr, StartProcess(_, _)) + .Times(1) + .WillOnce(DoAll(SetArgReferee<1>(PID), Return(ERR_TIMED_OUT))); + std::shared_ptr record = + service_->GetOrCreateAppRunningRecord(token, appInfo, abilityInfo, GetTestAppName(), 0, result); + ASSERT_NE(record, nullptr); + service_->StartProcess(abilityInfo->applicationName, GetTestAppName(), record); + auto record1 = service_->GetAppRunningRecordByAppRecordId(record->GetRecordId()); + EXPECT_EQ(record1, nullptr); + APP_LOGI("AmsServiceLoadAbilityProcessTest StartProcess004 end"); +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/appmgr/test/unittest/ams_service_startup_test/BUILD.gn b/services/appmgr/test/unittest/ams_service_startup_test/BUILD.gn new file mode 100644 index 000000000..406be582d --- /dev/null +++ b/services/appmgr/test/unittest/ams_service_startup_test/BUILD.gn @@ -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. + +import("//build/test.gni") +import("//foundation/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/appmgrservice" + +ohos_unittest("AmsServiceStartupTest") { + module_out_path = module_output_path + + include_dirs = [ + "//foundation/appexecfwk/standard/services/appmgr/test/mock/include", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include/", + "//foundation/distributedschedule/samgr/adapter/interfaces/innerkits/include/", + ] + + sources = [ + "${services_path}/appmgr/src/ability_running_record.cpp", + "${services_path}/appmgr/src/app_death_recipient.cpp", + "${services_path}/appmgr/src/app_mgr_service.cpp", + "${services_path}/appmgr/src/app_mgr_service_event_handler.cpp", + "${services_path}/appmgr/src/app_mgr_service_inner.cpp", + "${services_path}/appmgr/src/app_running_record.cpp", + "${services_path}/appmgr/src/app_spawn_client.cpp", + "${services_path}/appmgr/src/app_spawn_msg_wrapper.cpp", + "${services_path}/appmgr/src/app_spawn_socket.cpp", + ] + + sources += [ "ams_service_startup_test.cpp" ] + + configs = [ "${libs_path}/libeventhandler:libeventhandler_config" ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${libs_path}/libeventhandler:libeventhandler_target", + "${services_path}/appmgr/test:appmgr_test_source", + "//base/startup/appspawn_standard:appspawn_socket_client", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "//foundation/appexecfwk/standard/services/appmgr:libams", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":AmsServiceStartupTest" ] +} diff --git a/services/appmgr/test/unittest/ams_service_startup_test/ams_service_startup_test.cpp b/services/appmgr/test/unittest/ams_service_startup_test/ams_service_startup_test.cpp new file mode 100644 index 000000000..80543102a --- /dev/null +++ b/services/appmgr/test/unittest/ams_service_startup_test/ams_service_startup_test.cpp @@ -0,0 +1,170 @@ +/* + * 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. + */ + +// redefine private and protected since testcase need to invoke and test private function +#define private public +#define protected public +#include "app_mgr_service.h" +#undef private +#undef protected +#include +#include "app_log_wrapper.h" + +using namespace testing::ext; +using namespace OHOS::AppExecFwk; + +class AppMgrServiceInnerMock : public AppMgrServiceInner { +public: + virtual int32_t OpenAppSpawnConnection() override + { + return 0; + } +}; + +class AmsServiceStartupTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); +}; + +void AmsServiceStartupTest::SetUpTestCase() +{} + +void AmsServiceStartupTest::TearDownTestCase() +{} + +void AmsServiceStartupTest::SetUp() +{} + +void AmsServiceStartupTest::TearDown() +{} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: StartUp + * FunctionPoints: AppMgrService startup + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if AppMgrService startup successfully + */ +HWTEST_F(AmsServiceStartupTest, Startup_001, TestSize.Level0) +{ + APP_LOGI("ams_service_startup_001 start"); + std::shared_ptr appMgrService = std::make_shared(); + std::shared_ptr innerService = std::make_shared(); + appMgrService->SetInnerService(innerService); + EXPECT_EQ(ServiceRunningState::STATE_NOT_START, appMgrService->QueryServiceState().serviceRunningState); + appMgrService->OnStart(); + EXPECT_EQ(ServiceRunningState::STATE_RUNNING, appMgrService->QueryServiceState().serviceRunningState); + appMgrService->OnStop(); + EXPECT_EQ(ServiceRunningState::STATE_NOT_START, appMgrService->QueryServiceState().serviceRunningState); + APP_LOGI("ams_service_startup_001 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: StartUp + * FunctionPoints: AppMgrService startup again + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if start up repeatly system act normal + */ +HWTEST_F(AmsServiceStartupTest, Startup_002, TestSize.Level0) +{ + APP_LOGI("ams_service_startup_002 start"); + std::shared_ptr appMgrService = std::make_shared(); + std::shared_ptr innerService = std::make_shared(); + appMgrService->SetInnerService(innerService); + EXPECT_EQ(ServiceRunningState::STATE_NOT_START, appMgrService->QueryServiceState().serviceRunningState); + appMgrService->OnStart(); + EXPECT_EQ(ServiceRunningState::STATE_RUNNING, appMgrService->QueryServiceState().serviceRunningState); + appMgrService->OnStart(); + EXPECT_EQ(ServiceRunningState::STATE_RUNNING, appMgrService->QueryServiceState().serviceRunningState); + appMgrService->OnStop(); + EXPECT_EQ(ServiceRunningState::STATE_NOT_START, appMgrService->QueryServiceState().serviceRunningState); + APP_LOGI("ams_service_startup_002 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: StartUp + * FunctionPoints: AppMgrService stop without start + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if stop without start system act normal + */ +HWTEST_F(AmsServiceStartupTest, Startup_003, TestSize.Level0) +{ + APP_LOGI("ams_service_startup_003 start"); + std::shared_ptr appMgrService = std::make_shared(); + std::shared_ptr innerService = std::make_shared(); + appMgrService->SetInnerService(innerService); + EXPECT_EQ(ServiceRunningState::STATE_NOT_START, appMgrService->QueryServiceState().serviceRunningState); + appMgrService->OnStop(); + EXPECT_EQ(ServiceRunningState::STATE_NOT_START, appMgrService->QueryServiceState().serviceRunningState); + APP_LOGI("ams_service_startup_003 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: StartUp + * FunctionPoints: AppMgrService stop repeatly + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if stop repeatly system act normal + */ +HWTEST_F(AmsServiceStartupTest, Startup_004, TestSize.Level0) +{ + APP_LOGI("ams_service_startup_004 start"); + std::shared_ptr appMgrService = std::make_shared(); + std::shared_ptr innerService = std::make_shared(); + appMgrService->SetInnerService(innerService); + EXPECT_EQ(ServiceRunningState::STATE_NOT_START, appMgrService->QueryServiceState().serviceRunningState); + appMgrService->OnStart(); + EXPECT_EQ(ServiceRunningState::STATE_RUNNING, appMgrService->QueryServiceState().serviceRunningState); + appMgrService->OnStop(); + EXPECT_EQ(ServiceRunningState::STATE_NOT_START, appMgrService->QueryServiceState().serviceRunningState); + appMgrService->OnStop(); + EXPECT_EQ(ServiceRunningState::STATE_NOT_START, appMgrService->QueryServiceState().serviceRunningState); + APP_LOGI("ams_service_startup_004 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: StartUp + * FunctionPoints: AppMgrService start and stop repeatly + * EnvConditions: Mobile that can run ohos test framework + * CaseDescription: Verify if start and stop repeatly system act normal + */ +HWTEST_F(AmsServiceStartupTest, Startup_005, TestSize.Level0) +{ + APP_LOGI("ams_service_startup_005 start"); + std::shared_ptr appMgrService = std::make_shared(); + std::shared_ptr innerService = std::make_shared(); + appMgrService->SetInnerService(innerService); + EXPECT_EQ(ServiceRunningState::STATE_NOT_START, appMgrService->QueryServiceState().serviceRunningState); + appMgrService->OnStart(); + EXPECT_EQ(ServiceRunningState::STATE_RUNNING, appMgrService->QueryServiceState().serviceRunningState); + appMgrService->OnStop(); + EXPECT_EQ(ServiceRunningState::STATE_NOT_START, appMgrService->QueryServiceState().serviceRunningState); + appMgrService->OnStart(); + EXPECT_EQ(ServiceRunningState::STATE_RUNNING, appMgrService->QueryServiceState().serviceRunningState); + appMgrService->OnStop(); + EXPECT_EQ(ServiceRunningState::STATE_NOT_START, appMgrService->QueryServiceState().serviceRunningState); + APP_LOGI("ams_service_startup_005 end"); +} \ No newline at end of file diff --git a/services/appmgr/test/unittest/ams_start_via_asan_test/BUILD.gn b/services/appmgr/test/unittest/ams_start_via_asan_test/BUILD.gn new file mode 100644 index 000000000..f10ca1d1d --- /dev/null +++ b/services/appmgr/test/unittest/ams_start_via_asan_test/BUILD.gn @@ -0,0 +1,36 @@ +# 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/appmgrservice" + +ohos_unittest("AmsStartViaAsanTest") { + module_out_path = module_output_path + + sources = [ + "${services_path}/appmgr/src/start_via_asan.cpp", + "ams_start_via_asan_test.cpp", + ] + + deps = [ "${services_path}/appmgr/test:appmgr_test_source" ] + + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] +} + +group("unittest") { + testonly = true + + deps = [ ":AmsStartViaAsanTest" ] +} diff --git a/services/appmgr/test/unittest/ams_start_via_asan_test/ams_start_via_asan_test.cpp b/services/appmgr/test/unittest/ams_start_via_asan_test/ams_start_via_asan_test.cpp new file mode 100644 index 000000000..edf2a7492 --- /dev/null +++ b/services/appmgr/test/unittest/ams_start_via_asan_test/ams_start_via_asan_test.cpp @@ -0,0 +1,79 @@ +/* + * 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 "start_via_asan.h" +#include +#include "properties.h" +#include "app_log_wrapper.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; + +class AmsStartViaAsanTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); +}; + +void AmsStartViaAsanTest::SetUpTestCase() +{} + +void AmsStartViaAsanTest::TearDownTestCase() +{} + +void AmsStartViaAsanTest::SetUp() +{} + +void AmsStartViaAsanTest::TearDown() +{} + +/* + * Feature: StartViaAsan + * Function: ASAN + * SubFunction: IsAsanVersion + * FunctionPoints: Use interface GetSysPara to get wrap.appName attribute. + * EnvConditions: NA + * CaseDescription: Judge whether the wrap attribute exists in the environment. + */ +HWTEST_F(AmsStartViaAsanTest, IsAsanVersion_001, TestSize.Level0) +{ + APP_LOGD("IsAsanVersion_001 start"); + std::string appName = "com.ohos.hiworld"; + bool result = DelayedSingleton::GetInstance()->IsAsanVersion(appName); + EXPECT_EQ(result, false); + + APP_LOGD("IsAsanVersion_001 end"); +} + +/* + * Feature: StartViaAsan + * Function: ASAN + * SubFunction: GetAsanStartMsg + * FunctionPoints: Add wrap attribute to AppSpawnStartMsg object + * EnvConditions: NA + * CaseDescription: Add the wrap attribute to the arg field of the AppSpawnStartMsg object + */ +HWTEST_F(AmsStartViaAsanTest, GetAsanStartMsg_001, TestSize.Level0) +{ + APP_LOGD("GetAsanStartMsg_001 start"); + std::string appName = "com.ohos.hiworld"; + AppSpawnStartMsg startMsg = {appName, "clsName", "funcName", "soPath"}; + DelayedSingleton::GetInstance()->GetAsanStartMsg(startMsg); + EXPECT_EQ(startMsg.arg, "wrap." + appName); + APP_LOGD("GetAsanStartMsg_001 end"); +} \ No newline at end of file diff --git a/services/appmgr/test/unittest/app_mgr_service_event_handler_test/BUILD.gn b/services/appmgr/test/unittest/app_mgr_service_event_handler_test/BUILD.gn new file mode 100644 index 000000000..8b4df060c --- /dev/null +++ b/services/appmgr/test/unittest/app_mgr_service_event_handler_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/appmgrservice" + +ohos_unittest("AMSEventHandlerTest") { + module_out_path = module_output_path + + sources = [ + "${services_path}/appmgr/src/ability_running_record.cpp", + "${services_path}/appmgr/src/app_death_recipient.cpp", + "${services_path}/appmgr/src/app_lifecycle_deal.cpp", + "${services_path}/appmgr/src/app_mgr_service_event_handler.cpp", + "${services_path}/appmgr/src/app_mgr_service_inner.cpp", + "${services_path}/appmgr/src/app_process_manager.cpp", + "${services_path}/appmgr/src/app_running_manager.cpp", + "${services_path}/appmgr/src/app_running_record.cpp", + "${services_path}/appmgr/src/app_spawn_client.cpp", + "${services_path}/appmgr/src/app_spawn_msg_wrapper.cpp", + "${services_path}/appmgr/src/app_spawn_socket.cpp", + "${services_path}/appmgr/src/cgroup_manager.cpp", + "${services_path}/appmgr/src/lmk_util.cpp", + "${services_path}/appmgr/src/lmkd_client.cpp", + "${services_path}/appmgr/src/process_optimizer.cpp", + "${services_path}/appmgr/src/process_optimizer_uba.cpp", + "${services_path}/appmgr/src/remote_client_manager.cpp", + ] + + sources += [ "app_mgr_service_event_handler_test.cpp" ] + + configs = [ + "${services_path}/appmgr/test:appmgr_test_config", + "${libs_path}/libeventhandler:libeventhandler_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${libs_path}/libeventhandler:libeventhandler_target", + "${services_path}/appmgr/test:appmgr_test_source", + "//base/startup/appspawn_standard:appspawn_socket_client", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler:libeventhandler", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/googletest:gtest_main", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":AMSEventHandlerTest" ] +} diff --git a/services/appmgr/test/unittest/app_mgr_service_event_handler_test/app_mgr_service_event_handler_test.cpp b/services/appmgr/test/unittest/app_mgr_service_event_handler_test/app_mgr_service_event_handler_test.cpp new file mode 100644 index 000000000..c4a9a27ff --- /dev/null +++ b/services/appmgr/test/unittest/app_mgr_service_event_handler_test/app_mgr_service_event_handler_test.cpp @@ -0,0 +1,176 @@ +/* + * 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. + */ + +#define private public +#include "app_mgr_service_event_handler.h" +#undef private + +#include "app_log_wrapper.h" +#include "app_mgr_service_inner.h" +#include +#include +#include "mock_app_scheduler.h" +#include "inner_event.h" + +#include + +using namespace testing::ext; + +namespace OHOS { +namespace AppExecFwk { + +static bool eventHandlerFlag_ = false; +class MockAMSEventHandler : public AMSEventHandler { + +public: + MockAMSEventHandler(const std::shared_ptr &runner, const std::shared_ptr &ams); + virtual ~MockAMSEventHandler(); + + virtual void ProcessEvent(const InnerEvent::Pointer &event) override + { + if (event->GetInnerEventId() == 10) { + eventHandlerFlag_ = true; + } + } +}; + +class AMSEventHandlerTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + +public: + std::shared_ptr testAms_; + std::shared_ptr eventHandler_; + std::shared_ptr runner_; +}; + +static void WaitUntilTaskFinished(std::shared_ptr handler) +{ + if (!handler) { + return; + } + + const uint32_t MAX_RETRY_COUNT = 1000; + const uint32_t SLEEP_TIME = 1000; + uint32_t count = 0; + std::atomic taskCalled(false); + auto f = [&taskCalled]() { taskCalled.store(true); }; + if (handler->PostTask(f)) { + while (!taskCalled.load()) { + ++count; + // if delay more than 1 second, break + if (count >= MAX_RETRY_COUNT) { + break; + } + + usleep(SLEEP_TIME); + } + } +} + +void AMSEventHandlerTest::SetUpTestCase() +{} + +void AMSEventHandlerTest::TearDownTestCase() +{} + +void AMSEventHandlerTest::SetUp() +{ + runner_ = EventRunner::Create("AMSEventHandlerTest"); + testAms_ = std::make_shared(); +} + +void AMSEventHandlerTest::TearDown() +{} + +MockAMSEventHandler ::MockAMSEventHandler( + const std::shared_ptr &runner, const std::shared_ptr &ams) + : AMSEventHandler(runner, ams) +{} + +MockAMSEventHandler::~MockAMSEventHandler() +{} + +/* + * Feature: AMS + * Function: AMSEventHandler + * SubFunction: AMSEventHandler + * FunctionPoints: init. + * EnvConditions: need to start a runner + * CaseDescription: Initialize message class + */ + +HWTEST_F(AMSEventHandlerTest, app_mgr_service_event_handler_test_001, TestSize.Level1) +{ + APP_LOGI("app_mgr_service_event_handler_test start"); + + if (!runner_) { + APP_LOGI("app_mgr_service_event_handler_test : runner_ is null"); + } + + if (!testAms_) { + APP_LOGI("app_mgr_service_event_handler_test : testAms_ is null"); + } + + EXPECT_FALSE(eventHandler_); + + // init + eventHandler_ = std::make_shared(runner_, testAms_); + + EXPECT_TRUE(eventHandler_); + EXPECT_TRUE(eventHandler_->ams_); + + APP_LOGI("app_mgr_service_event_handler_test end"); +} + +/* + * Feature: AMS + * Function: ProcessEvent + * SubFunction: AMSEventHandler + * FunctionPoints: postTask. + * EnvConditions: need to start a runner + * CaseDescription: Notification message + */ + +HWTEST_F(AMSEventHandlerTest, app_mgr_service_event_handler_test_002, TestSize.Level1) +{ + APP_LOGI("app_mgr_service_event_handler_test start"); + + if (!eventHandler_) { + eventHandler_ = std::make_shared(runner_, testAms_); + } + + // Error testing + eventHandler_->SendEvent(20); + + // waiting callback + WaitUntilTaskFinished(eventHandler_); + EXPECT_FALSE(eventHandlerFlag_); + + // test num == 10 + eventHandler_->SendEvent(10); + + // waiting callback + WaitUntilTaskFinished(eventHandler_); + EXPECT_TRUE(eventHandlerFlag_); + + APP_LOGI("app_mgr_service_event_handler_test end"); +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/appmgr/zidl/IAbilityScheduler.zidl b/services/appmgr/zidl/IAbilityScheduler.zidl new file mode 100644 index 000000000..6107b91f2 --- /dev/null +++ b/services/appmgr/zidl/IAbilityScheduler.zidl @@ -0,0 +1,21 @@ +/* + * 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. + */ + +interface IAbilityScheduler { + void scheduleLaunchAbilitySlice(in AbilitySliceInfo); + void scheduleForegroundAbility(); + void scheduleBackgroundAbility(); + void scheduleTerminateAbility(); +} \ No newline at end of file diff --git a/services/appmgr/zidl/IAppMgr.zidl b/services/appmgr/zidl/IAppMgr.zidl new file mode 100644 index 000000000..4e73f1395 --- /dev/null +++ b/services/appmgr/zidl/IAppMgr.zidl @@ -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. + */ + +interface OHOS.AppExecFwk.IAppScheduler; +interface OHOS.AppExecFwk.IAbilityScheduler; +interface OHOS.AppExecFwk.IAppStateCallback; + +parcelable OHOS.AppExecFwk.AppRecordId; +parcelable OHOS.AppExecFwk.AbilityInfo; +parcelable OHOS.AppExecFwk.AbilityRecordId; +parcelable OHOS.AppExecFwk.ApplicationInfo; + +interface OHOS.AppExecFwk.IAppMgr { + /* the function about ASMS begin */ + [oneway] void LoadAbility([in] IRemoteObject, [in] AbilityInfo, [in] ApplicationInfo); + [oneway] void TerminateAbility([in] IRemoteObject); + [oneway] void UpdateAbilityState([in] IRemoteObject, [in] int); + [oneway] void RegisterAppStateCallback([in] IAppStateCallback); + /* the function about ASMS end */ + + /* the function about Application begin */ + [oneway] void AttachApplication([in] IAppScheduler); + [oneway] void ApplicationForegrounded([in] AppRecordId); + [oneway] void ApplicationBackgrounded([in] AppRecordId); + [oneway] void ApplicationTerminated([in] AppRecordId); + int CheckPermission([in] AppRecordId, [in] String); + /* the function about Application end*/ +} \ No newline at end of file diff --git a/services/appmgr/zidl/IAppScheduler.zidl b/services/appmgr/zidl/IAppScheduler.zidl new file mode 100644 index 000000000..c905313e2 --- /dev/null +++ b/services/appmgr/zidl/IAppScheduler.zidl @@ -0,0 +1,30 @@ +/* + * 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. + */ + +parcelable OHOS.AppExecFwk.AbilityInfo; +parcelable OHOS.AppExecFwk.ApplicationInfo; +parcelable OHOS.AppExecFwk.Profile; + +interface OHOS.AppExecFwk.IAppScheduler { + [oneway] void ScheduleLaunchApplication([in] ApplicationInfo, [in] Profile); + [oneway] void ScheduleLaunchAbility([in] AbilityInfo, [in] IRemoteObject); + [oneway] void ScheduleCleanAbility([in] IRemoteObject); + [oneway] void ScheduleForegroundApplication(); + [oneway] void ScheduleBackgroundApplication(); + [oneway] void ScheduleTerminateApplication(); + [oneway] void ScheduleShrinkMemory([in] int); + [oneway] void ScheduleLowMemory(); + [oneway] void ScheduleProfileChanged([in] Profile); +} \ No newline at end of file diff --git a/services/appmgr/zidl/IAppStateCallback.zidl b/services/appmgr/zidl/IAppStateCallback.zidl new file mode 100644 index 000000000..fda532ca5 --- /dev/null +++ b/services/appmgr/zidl/IAppStateCallback.zidl @@ -0,0 +1,19 @@ +/* + * 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. + */ + +interface OHOS.AppExecFwk.IAppStateCallback { + [oneway] void OnAppStateChanged[in] String, [in] int); + [oneway] void OnAbilityRequestDone([in] IRemoteObject, [in] int ); +} \ No newline at end of file diff --git a/services/bundlemgr/BUILD.gn b/services/bundlemgr/BUILD.gn new file mode 100644 index 000000000..ddeb6e153 --- /dev/null +++ b/services/bundlemgr/BUILD.gn @@ -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. + +import("//build/ohos.gni") +import("//foundation/appexecfwk/standard/appexecfwk.gni") +import( + "//foundation/appexecfwk/standard/services/bundlemgr/appexecfwk_bundlemgr.gni") + +config("bundlemgr_config") { + include_dirs = [ + "include", + "//utils/system/safwk/native/include", + "//foundation/appexecfwk/standard/event/cesfwk/kits/native/include", + ] +} + +config("bundlemgr_common_config") { + include_dirs = [ + "include", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base/include", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core/include/bundlemgr", + "//utils/system/safwk/native/include", + "//base/security/permission/interfaces/innerkits/permission_standard/permissionsdk/main/cpp/include", + "//base/security/appverify/interfaces/innerkits/appverify/include", + ] + + defines = [ + "APP_LOG_TAG = \"BundleMgrService\"", + "LOG_DOMAIN = 0xD001120", + ] +} + +config("bundlemgr_parse_config") { + include_dirs = [ + "//third_party/json/include", + "//third_party/zlib/contrib/minizip", + "//third_party/zlib", + "//utils/native/base/include", + ] + + cflags_cc = [ "-fexceptions" ] +} + +bundlemgr_parser_common_config = [ + ":bundlemgr_common_config", + ":bundlemgr_parse_config", +] + +ohos_source_set("parser_common") { + sources = [ + "src/base_extractor.cpp", + "src/zip_file.cpp", + ] + + public_configs = bundlemgr_parser_common_config + + deps = [ + "${common_path}:libappexecfwk_common", + "//third_party/zlib:libz", + "//utils/native/base:utils", + ] + + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] +} + +ohos_source_set("bundle_parser") { + sources = [ + "include/bundle_extractor.h", + "include/bundle_parser.h", + "include/bundle_profile.h", + "src/bundle_extractor.cpp", + "src/bundle_parser.cpp", + "src/bundle_profile.cpp", + ] + + public_configs = bundlemgr_parser_common_config + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + ":parser_common", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${common_path}:libappexecfwk_common", + "//base/security/permission/interfaces/innerkits/permission_standard/permissionsdk:libpermissionsdk_standard", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("bms_target") { + deps = [ + ":installs", + ":installs.rc", + ":libbms", + ] +} + +ohos_shared_library("libbms") { + visibility = [ + "//foundation/*", + "//base/*", + ] + include_dirs = [ + "include", + "//foundation/aafwk/standard/interfaces/innerkits/want/include/ohos/aafwk/content/", + "//foundation/aafwk/standard/interfaces/innerkits/ability_manager/include", + "//foundation/distributedschedule/dmsfwk/services/dtbschedmgr/include", + "//base/notification/ces_standard/cesfwk/kits/native/include", + "//utils/system/safwk/native/include", + ] + + sources = [ + "src/bundle_data_mgr.cpp", + "src/bundle_data_storage.cpp", + "src/bundle_mgr_host_impl.cpp", + "src/bundle_mgr_service.cpp", + "src/bundle_mgr_service_event_handler.cpp", + "src/bundle_scanner.cpp", + "src/bundle_status_callback_death_recipient.cpp", + "src/system_ability_helper.cpp", + ] + + sources += bundle_install_sources + + defines = [ "APP_LOG_TAG = \"BundleMgrService\"" ] + + configs = [ + ":bundlemgr_config", + ":bundlemgr_common_config", + "${libs_path}/libeventhandler:libeventhandler_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + ":bundle_parser", + ":parser_common", + "${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", + "//base/notification/ces_standard/cesfwk/kits/native:cesfwk_kits", + "//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/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] + + subsystem_name = "appexecfwk" + part_name = "appexecfwk_standard" +} + +ohos_executable("installs") { + sources = [ + "src/installd/installd_main.cpp", + "src/system_ability_helper.cpp", + ] + + sources += install_daemon_sources + + defines = [ "APP_LOG_TAG = \"BundleMgrService\"" ] + + configs = [ ":bundlemgr_config" ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + ":bundle_parser", + ":parser_common", + "${common_path}:libappexecfwk_common", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] + + install_enable = true + subsystem_name = "appexecfwk" + part_name = "appexecfwk_standard" +} + +ohos_prebuilt_etc("installs.rc") { + source = "installs.rc" + relative_install_dir = "init" + subsystem_name = "appexecfwk" + part_name = "appexecfwk_standard" +} diff --git a/services/bundlemgr/appexecfwk_bundlemgr.gni b/services/bundlemgr/appexecfwk_bundlemgr.gni new file mode 100644 index 000000000..f07c56e85 --- /dev/null +++ b/services/bundlemgr/appexecfwk_bundlemgr.gni @@ -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. + +import("//foundation/appexecfwk/standard/appexecfwk.gni") + +install_daemon_sources = [ + "${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/installd_client.cpp", + "${services_path}/bundlemgr/src/ipc/installd_host.cpp", + "${services_path}/bundlemgr/src/ipc/installd_proxy.cpp", +] + +bundle_install_sources = [ + "${services_path}/bundlemgr/src/base_bundle_installer.cpp", + "${services_path}/bundlemgr/src/bundle_installer.cpp", + "${services_path}/bundlemgr/src/bundle_installer_host.cpp", + "${services_path}/bundlemgr/src/bundle_installer_manager.cpp", + "${services_path}/bundlemgr/src/bundle_permission_mgr.cpp", + "${services_path}/bundlemgr/src/bundle_util.cpp", + "${services_path}/bundlemgr/src/bundle_verify_mgr.cpp", + "${services_path}/bundlemgr/src/inner_bundle_info.cpp", + "${services_path}/bundlemgr/src/installd_client.cpp", + "${services_path}/bundlemgr/src/installd_death_recipient.cpp", + "${services_path}/bundlemgr/src/ipc/installd_host.cpp", + "${services_path}/bundlemgr/src/ipc/installd_proxy.cpp", + "${services_path}/bundlemgr/src/system_bundle_installer.cpp", +] + +bundle_install_deps = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "${services_path}/bundlemgr:bundle_parser", + "${services_path}/bundlemgr:parser_common", +] + +bundle_install_external_deps = [ + #"communication:ipc_core", +] diff --git a/services/bundlemgr/include/base_bundle_installer.h b/services/bundlemgr/include/base_bundle_installer.h new file mode 100644 index 000000000..22d0871bf --- /dev/null +++ b/services/bundlemgr/include/base_bundle_installer.h @@ -0,0 +1,257 @@ +/* + * 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_BASE_BUNDLE_INSTALLER_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BASE_BUNDLE_INSTALLER_H + +#include + +#include "nocopyable.h" + +#include "appexecfwk_errors.h" +#include "inner_bundle_info.h" +#include "install_param.h" +#include "bundle_data_mgr.h" + +namespace OHOS { +namespace AppExecFwk { + +class BaseBundleInstaller { +public: + BaseBundleInstaller(); + virtual ~BaseBundleInstaller(); + +protected: + enum class InstallerState { + INSTALL_START, + INSTALL_BUNDLE_CHECKED = 5, + INSTALL_PARSED = 10, + INSTALL_SIGNATURE_CHECKED = 15, + INSTALL_PERMS_REQ = 20, + INSTALL_CREATDIR = 40, + INSTALL_EXTRACTED = 60, + INSTALL_RENAMED = 80, + INSTALL_INFO_SAVED = 90, + INSTALL_SUCCESS = 100, + INSTALL_FAILED, + }; + + /** + * @brief The main function for system and normal bundle install. + * @param bundlePath Indicates the path for storing the HAP file of the application + * to install or update. + * @param installParam Indicates the install parameters. + * @param appType Indicates the application type. + * @return Returns ERR_OK if the application install successfully; returns error code otherwise. + */ + ErrCode InstallBundle( + const std::string &bundlePath, const InstallParam &installParam, const Constants::AppType appType); + /** + * @brief The main function for uninstall a bundle. + * @param bundleName Indicates the bundle name of the application to uninstall. + * @param installParam Indicates the uninstall parameters. + * @return Returns ERR_OK if the application uninstall successfully; returns error code otherwise. + */ + ErrCode UninstallBundle(const std::string &bundleName, const InstallParam &installParam); + /** + * @brief The main function 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. + * @return Returns ERR_OK if the application uninstall successfully; returns error code otherwise. + */ + ErrCode UninstallBundle( + const std::string &bundleName, const std::string &modulePackage, const InstallParam &installParam); + /** + * @brief Update the installer state. + * @attention This function changes the base class state only. + * @param state Indicates the state to be updated to. + * @return + */ + virtual void UpdateInstallerState(const InstallerState state); + /** + * @brief Get the installer state. + * @return The current state of the installer object. + */ + inline InstallerState GetInstallerState() + { + return state_; + } + /** + * @brief Get the installer state. + * @param state Indicates the state to be updated to. + * @return + */ + inline void SetInstallerState(InstallerState state) + { + state_ = state; + } + +private: + /** + * @brief The real procedure for system and normal bundle install. + * @param bundlePath Indicates the path for storing the HAP file of the application + * to install or update. + * @param installParam Indicates the install parameters. + * @param appType Indicates the application type. + * @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); + /** + * @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. + * @return Returns ERR_OK if the bundle uninstall successfully; returns error code otherwise. + */ + ErrCode ProcessBundleUninstall(const std::string &bundleName, const InstallParam &installParam); + /** + * @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. + * @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); + /** + * @brief The process of installing a new bundle. + * @param info Indicates the InnerBundleInfo parsed from the config.json in the HAP package. + * @return Returns ERR_OK if the new bundle install successfully; returns error code otherwise. + */ + ErrCode ProcessBundleInstallStatus(InnerBundleInfo &info); + /** + * @brief The process of updating an exist bundle. + * @param oldInfo Indicates the exist InnerBundleInfo object get from the database. + * @param newInfo Indicates the InnerBundleInfo object parsed from the config.json in the HAP package. + * @param isReplace Indicates whether there is the replace flag in the install flag. + * @return Returns ERR_OK if the bundle updating successfully; returns error code otherwise. + */ + ErrCode ProcessBundleUpdateStatus(InnerBundleInfo &oldInfo, InnerBundleInfo &newInfo, bool isReplace); + /** + * @brief Remove a whole bundle. + * @param info Indicates the InnerBundleInfo object of a bundle. + * @return Returns ERR_OK if the bundle removed successfully; returns error code otherwise. + */ + ErrCode RemoveBundle(InnerBundleInfo &info); + /** + * @brief Create the code and data directories of a bundle. + * @param info Indicates the InnerBundleInfo object of a bundle. + * @return Returns ERR_OK if the bundle directories created successfully; returns error code otherwise. + */ + ErrCode CreateBundleAndDataDir(InnerBundleInfo &info) const; + /** + * @brief Extract the code to temporilay directory and rename it. + * @param info Indicates the InnerBundleInfo object of a bundle. + * @return Returns ERR_OK if the bundle extract and renamed successfully; returns error code otherwise. + */ + ErrCode ExtractModuleAndRename(InnerBundleInfo &info); + /** + * @brief Remove the code and data directories of a bundle. + * @param info Indicates the InnerBundleInfo object of a bundle. + * @param isUninstall Indicates that whether the remove is in an uninstall process. + * @return Returns ERR_OK if the bundle directories removed successfully; returns error code otherwise. + */ + ErrCode RemoveBundleAndDataDir(InnerBundleInfo &info, bool isUninstall) const; + /** + * @brief Remove the code and data directories of a module in a bundle. + * @param info Indicates the InnerBundleInfo object of a bundle. + * @param modulePackage Indicates the module to be removed. + * @return Returns ERR_OK if the bundle directories removed successfully; returns error code otherwise. + */ + ErrCode RemoveModuleAndDataDir(InnerBundleInfo &info, const std::string &modulePackage) const; + /** + * @brief Parse the bundle config.json file. + * @param bundleFilePath Indicates the HAP file path. + * @param InnerBundleInfo Indicates the InnerBundleInfo object of a bundle. + * @return Returns ERR_OK if the bundle parsed successfully; returns error code otherwise. + */ + ErrCode ParseBundleInfo(const std::string &bundleFilePath, InnerBundleInfo &info) const; + /** + * @brief Remove the current installing module directory. + * @param info Indicates the InnerBundleInfo object of a bundle under installing. + * @return Returns ERR_OK if the module directory removed successfully; returns error code otherwise. + */ + ErrCode RemoveModuleDir(InnerBundleInfo &info) const; + /** + * @brief Extract files of the current installing module package. + * @param info Indicates the InnerBundleInfo object of a bundle under installing. + * @return Returns ERR_OK if the module files extraced successfully; returns error code otherwise. + */ + ErrCode ExtractModuleFiles(InnerBundleInfo &info); + /** + * @brief Create the data directories of current installing module package. + * @param info Indicates the InnerBundleInfo object of a bundle under installing. + * @return Returns ERR_OK if the module directory created successfully; returns error code otherwise. + */ + ErrCode CreateModuleDataDir(InnerBundleInfo &info) const; + /** + * @brief Remove the data directories of current installing module package. + * @param info Indicates the InnerBundleInfo object of a bundle under installing. + * @return Returns ERR_OK if the module directory removed successfully; returns error code otherwise. + */ + ErrCode RemoveModuleDataDir(InnerBundleInfo &info) const; + /** + * @brief Rename the directory of current installing module package. + * @param info Indicates the InnerBundleInfo object of a bundle under installing. + * @return Returns ERR_OK if the module directory renamed successfully; returns error code otherwise. + */ + ErrCode RenameModuleDir(InnerBundleInfo &info) const; + /** + * @brief Modify the install directory path for different install type. + * @param info Indicates the InnerBundleInfo object of a bundle under installing. + * @return Returns true if the path set successfully; returns false otherwise. + */ + bool ModifyInstallDirByHapType(InnerBundleInfo &info); + /** + * @brief Update the bundle paths in the InnerBundleInfo object. + * @param info Indicates the InnerBundleInfo object of a bundle under installing. + * @param baseDataPath Indicates the data file paths. + * @return Returns true if the path set successfully; returns false otherwise. + */ + bool UpdateBundlePaths(InnerBundleInfo &info, const std::string baseDataPath) const; + /** + * @brief The process of install a new module package. + * @param newInfo Indicates the InnerBundleInfo object parsed from the config.json in the HAP package. + * @param oldInfo Indicates the exist InnerBundleInfo object get from the database. + * @return Returns ERR_OK if the new module install successfully; returns error code otherwise. + */ + ErrCode ProcessNewModuleInstall(InnerBundleInfo &newInfo, InnerBundleInfo &oldInfo); + /** + * @brief The process of updating an exist module package. + * @param newInfo Indicates the InnerBundleInfo object parsed from the config.json in the HAP package. + * @param oldInfo Indicates the exist InnerBundleInfo object get from the database. + * @return Returns ERR_OK if the module updating successfully; returns error code otherwise. + */ + ErrCode ProcessModuleUpdate(InnerBundleInfo &newInfo, InnerBundleInfo &oldInfo); + +private: + InstallerState state_ = InstallerState::INSTALL_START; + std::shared_ptr dataMgr_ = nullptr; // this pointer will get when public functions called + std::string bundleName_; + std::string moduleTmpDir_; + std::string modulePath_; + std::string baseCodePath_; + std::string baseDataPath_; + std::string modulePackage_; + std::string mainAbility_; + bool isAppExist_ = false; + + DISALLOW_COPY_AND_MOVE(BaseBundleInstaller); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BASE_BUNDLE_INSTALLER_H \ No newline at end of file diff --git a/services/bundlemgr/include/base_extractor.h b/services/bundlemgr/include/base_extractor.h new file mode 100644 index 000000000..9f811b31b --- /dev/null +++ b/services/bundlemgr/include/base_extractor.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_BUNDLEMGR_INCLUDE_BASE_EXTRACTOR_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BASE_EXTRACTOR_H + +#include + +#include "zip_file.h" + +namespace OHOS { +namespace AppExecFwk { + +class BaseExtractor { +public: + explicit BaseExtractor(const std::string &source); + virtual ~BaseExtractor(); + /** + * @brief Open compressed file. + * @return Returns true if the file is successfully opened; returns false otherwise. + */ + virtual bool Init(); + /** + * @brief Extract the Profile to dest stream. + * @param dest Indicates the obtained std::ostream object.. + * @return Returns true if the profile extracted successfully; returns false otherwise. + */ + virtual bool ExtractProfile(std::ostream &dest) const = 0; + /** + * @brief Extract to dest stream by file name. + * @param fileName Indicates the file name. + * @param dest Indicates the obtained std::ostream object. + * @return Returns true if the file extracted successfully; returns false otherwise. + */ + bool ExtractByName(const std::string &fileName, std::ostream &dest) const; + /** + * @brief Extract to dest path on filesystem. + * @param fileName Indicates the file name. + * @param targetPath Indicates the target Path. + * @return Returns true if the file extracted to filesystem successfully; returns false otherwise. + */ + bool ExtractFile(const std::string &fileName, const std::string &targetPath) const; + /** + * @brief Get all file names in a hap file. + * @param fileName Indicates the obtained file names in hap. + * @return Returns true if the file names obtained successfully; returns false otherwise. + */ + bool GetZipFileNames(std::vector &fileNames); + +protected: + const std::string sourceFile_; + ZipFile zipFile_; + bool initial_ = false; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BASE_EXTRACTOR_H diff --git a/services/bundlemgr/include/bundle_data_mgr.h b/services/bundlemgr/include/bundle_data_mgr.h new file mode 100755 index 000000000..e057d233f --- /dev/null +++ b/services/bundlemgr/include/bundle_data_mgr.h @@ -0,0 +1,368 @@ +/* + * 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_DATA_MGR_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_DATA_MGR_H + +#include +#include +#include +#include + +#include "ohos/aafwk/content/want.h" + +#include "ability_info.h" +#include "application_info.h" +#include "inner_bundle_info.h" +#include "bundle_status_callback_interface.h" +#include "bundle_data_storage_interface.h" + +namespace OHOS { +namespace AppExecFwk { + +enum class NotifyType { INSTALL, UPDATE, UNINSTALL_BUNDLE, UNINSTALL_MODULE }; + +enum class InstallState { + INSTALL_START = 1, + INSTALL_SUCCESS, + INSTALL_FAIL, + UNINSTALL_START, + UNINSTALL_SUCCESS, + UNINSTALL_FAIL, + UPDATING_START, + UPDATING_SUCCESS, + UPDATING_FAIL, +}; + +class BundleDataMgr { +public: + using Want = OHOS::AAFwk::Want; + + // init state transfer map data. + BundleDataMgr(); + ~BundleDataMgr(); + + /** + * @brief Boot query persistent storage. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool LoadDataFromPersistentStorage(); + /** + * @brief Update internal state for whole bundle. + * @param bundleName Indicates the bundle name. + * @param state Indicates the install state to be set. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool UpdateBundleInstallState(const std::string &bundleName, const InstallState state); + /** + * @brief Add new InnerBundleInfo. + * @param bundleName Indicates the bundle name. + * @param info Indicates the InnerBundleInfo object to be save. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool AddInnerBundleInfo(const std::string &bundleName, InnerBundleInfo &info); + /** + * @brief Add new module info to an exist InnerBundleInfo. + * @param bundleName Indicates the bundle name. + * @param newInfo Indicates the new InnerBundleInfo object. + * @param oldInfo Indicates the old InnerBundleInfo object. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool AddNewModuleInfo(const std::string &bundleName, const InnerBundleInfo &newInfo, InnerBundleInfo &oldInfo); + /** + * @brief Remove module info from an exist InnerBundleInfo. + * @param bundleName Indicates the bundle name. + * @param modulePackage Indicates the module Package. + * @param oldInfo Indicates the old InnerBundleInfo object. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool RemoveModuleInfo(const std::string &bundleName, const std::string &modulePackage, InnerBundleInfo &oldInfo); + /** + * @brief Update module info of an exist module. + * @param bundleName Indicates the bundle name. + * @param newInfo Indicates the new InnerBundleInfo object. + * @param oldInfo Indicates the old InnerBundleInfo object. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool UpdateInnerBundleInfo(const std::string &bundleName, const InnerBundleInfo &newInfo, InnerBundleInfo &oldInfo); + /** + * @brief Get an InnerBundleInfo if exist (will change the status to DISABLED). + * @param bundleName Indicates the bundle name. + * @param deviceId Indicates this device Id corresponding to the bundle name. + * @param info Indicates the obtained InnerBundleInfo object. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool GetInnerBundleInfo(const std::string &bundleName, const std::string &deviceId, InnerBundleInfo &info); + /** + * @brief Generate UID and GID for a bundle. + * @param info Indicates the InnerBundleInfo object. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool GenerateUidAndGid(InnerBundleInfo &info); + /** + * @brief Query the AbilityInfo by the given Want. + * @param want Indicates the information of the ability. + * @param abilityInfo Indicates the obtained AbilityInfo object. + * @return Returns true if the AbilityInfo is successfully obtained; returns false otherwise. + */ + bool QueryAbilityInfo(const Want &want, AbilityInfo &abilityInfo) const; + /** + * @brief Query the AbilityInfo by ability.uri in config.json. + * @param abilityUri Indicates the uri of the ability. + * @param abilityInfo Indicates the obtained AbilityInfo object. + * @return Returns true if the AbilityInfo is successfully obtained; returns false otherwise. + */ + bool QueryAbilityInfoByUri(const std::string &abilityUri, AbilityInfo &abilityInfo) const; + /** + * @brief Obtains the ApplicationInfo based on a given bundle name. + * @param appName 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 appInfo Indicates the obtained ApplicationInfo object. + * @return Returns true if the application is successfully obtained; returns false otherwise. + */ + bool GetApplicationInfo( + const std::string &appName, const ApplicationFlag flag, const int userId, ApplicationInfo &appInfo) const; + /** + * @brief Obtains information about all installed applications of a specified user. + * @param flag Indicates the flag used to specify information contained + * in the ApplicationInfo objects that will be returned. + * @param userId Indicates the user ID. + * @param appInfos Indicates all of the obtained ApplicationInfo objects. + * @return Returns true if the application is successfully obtained; returns false otherwise. + */ + bool GetApplicationInfos( + const ApplicationFlag flag, const int userId, std::vector &appInfos) const; + /** + * @brief Obtains BundleInfo of all bundles available in the system. + * @param flag Indicates the flag used to specify information contained in the BundleInfo that will be returned. + * @param bundleInfos Indicates all of the obtained BundleInfo objects. + * @return Returns true if the BundleInfos is successfully obtained; returns false otherwise. + */ + bool GetBundleInfos(const BundleFlag flag, std::vector &bundleInfos) const; + /** + * @brief Obtains the BundleInfo based on a given bundle name. + * @param bundleName Indicates the application bundle name to be queried. + * @param flag Indicates the information contained in the BundleInfo object to be returned. + * @param bundleInfo Indicates the obtained BundleInfo object. + * @return Returns true if the BundleInfo is successfully obtained; returns false otherwise. + */ + bool GetBundleInfo(const std::string &bundleName, const BundleFlag flag, BundleInfo &bundleInfo) const; + /** + * @brief Obtains the BundleInfo of application bundles based on the specified metaData. + * @param metaData Indicates the metadata to get in the bundle. + * @param bundleInfos Indicates all of the obtained BundleInfo objects. + * @return Returns true if the BundleInfos is successfully obtained; returns false otherwise. + */ + bool GetBundleInfosByMetaData(const std::string &metaData, std::vector &bundleInfos) const; + /** + * @brief Obtains the bundle name of a specified application based on the given UID. + * @param uid Indicates the uid. + * @param bundleName Indicates the obtained bundle name. + * @return Returns true if the bundle name is successfully obtained; returns false otherwise. + */ + bool GetBundleNameForUid(const int uid, std::string &bundleName) const; + /** + * @brief Obtains an array of all group IDs associated with a specified bundle. + * @param bundleName Indicates the bundle name. + * @param gids Indicates the group IDs associated with the specified bundle. + * @return Returns true if the gids is successfully obtained; returns false otherwise. + */ + bool GetBundleGids(const std::string &bundleName, std::vector &gids) const; + /** + * @brief Obtains the BundleInfo of all keep-alive applications in the system. + * @param bundleInfos Indicates all of the obtained BundleInfo objects. + * @return Returns true if the BundleInfos is successfully obtained; returns false otherwise. + */ + bool QueryKeepAliveBundleInfos(std::vector &bundleInfos) const; + /** + * @brief Obtains the label of a specified ability. + * @param bundleName Indicates the bundle name. + * @param className Indicates the ability class name. + * @return Returns the label of the ability if exist; returns empty string otherwise. + */ + std::string GetAbilityLabel(const std::string &bundleName, const std::string &className) const; + /** + * @brief Obtains the Want for starting the main ability of an application based on the given bundle name. + * @param bundleName Indicates the bundle name. + * @param want Indicates the obtained launch Want object. + * @return Returns true if the launch Want object is successfully obtained; returns false otherwise. + */ + bool GetLaunchWantForBundle(const std::string &bundleName, Want &want) const; + /** + * @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. + */ + bool GetHapModuleInfo(const AbilityInfo &abilityInfo, HapModuleInfo &hapModuleInfo) const; + /** + * @brief Check whether the app is system app by it's UID. + * @param uid Indicates the uid. + * @return Returns true if the bundle is a system application; returns false otherwise. + */ + bool CheckIsSystemAppByUid(const int uid) const; + /** + * @brief Obtains all bundle names installed. + * @param bundleNames Indicates the bundle Names. + * @return Returns true if have bundle installed; returns false otherwise. + */ + bool GetBundleList(std::vector &bundleNames) const; + /** + * @brief Set the bundle status disable. + * @param bundleName Indicates the bundle name. + * @return Returns true if the bundle status successfully set; returns false otherwise. + */ + bool DisableBundle(const std::string &bundleName); + /** + * @brief Set the bundle status enable. + * @param bundleName Indicates the bundle name. + * @return Returns true if the bundle status successfully set; returns false otherwise. + */ + bool EnableBundle(const std::string &bundleName); + /** + * @brief Get whether the application status is enabled. + * @param bundleName Indicates the bundle name. + * @return Returns true if the bundle status is enabled; returns false otherwise. + */ + bool IsApplicationEnabled(const std::string &bundleName) const; + /** + * @brief Set the application status. + * @param bundleName Indicates the bundle name. + * @param isEnable Indicates the status to set. + * @return Returns true if the bundle status successfully set; returns false otherwise. + */ + bool SetApplicationEnabled(const std::string &bundleName, bool isEnable); + /** + * @brief Register the bundle status callback function. + * @param bundleStatusCallback Indicates the callback object that using for notifing the bundle status. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool RegisterBundleStatusCallback(const sptr &bundleStatusCallback); + /** + * @brief Clear the specific bundle status callback. + * @param bundleStatusCallback Indicates the callback to be cleared. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool ClearBundleStatusCallback(const sptr &bundleStatusCallback); + /** + * @brief Unregister all the callbacks of status changed. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool UnregisterBundleStatusCallback(); + /** + * @brief Notify when the installation, update, or uninstall state of an application changes. + * @param bundleName Indicates the name of the bundle whose state has changed. + * @param modulePackage Indicates the modulePackage name of the bundle whose state has changed. + * @param resultCode Indicates the status code returned for the application installation, update, or uninstall + * result. + * @param type Indicates the NotifyType object. + * @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); + /** + * @brief Obtains the provision Id based on a given bundle name. + * @param bundleName Indicates the application bundle name to be queried. + * @param provisionId Indicates the provision Id to be returned. + * @return Returns true if the provision Id is successfully obtained; returns false otherwise. + */ + bool GetProvisionId(const std::string &bundleName, std::string &provisionId) const; + /** + * @brief Obtains the app feature based on a given bundle name. + * @param bundleName Indicates the application bundle name to be queried. + * @param provisionId Indicates the app feature to be returned. + * @return Returns true if the app feature is successfully obtained; returns false otherwise. + */ + bool GetAppFeature(const std::string &bundleName, std::string &appFeature) const; + + /** + * @brief Set the flag that indicates whether all applications are installed. + * @param flag Indicates the flag to be set. + * @return + */ + void SetAllInstallFlag(bool flag); + +private: + /** + * @brief Init transferStates. + * @return + */ + void InitStateTransferMap(); + /** + * @brief Determine whether to delete the data status. + * @param state Indicates the InstallState object. + * @return Returns true if state is INSTALL_FAIL,UNINSTALL_FAIL,UNINSTALL_SUCCESS,or UPDATING_FAIL; returns false + * otherwise. + */ + bool IsDeleteDataState(const InstallState state) const; + /** + * @brief Determine whether it is disable. + * @param state Indicates the InstallState object. + * @return Returns true if install state is UPDATING_START or UNINSTALL_START; returns false otherwise. + */ + bool IsDisableState(const InstallState state) const; + /** + * @brief Delete bundle info if InstallState is not INSTALL_FAIL. + * @param bundleName Indicates the bundle Names. + * @param state Indicates the InstallState object. + * @return Returns true if install state is UPDATING_START or UNINSTALL_START; returns false otherwise. + */ + void DeleteBundleInfo(const std::string &bundleName, const InstallState state); + /** + * @brief Determine whether app is installed. + * @param bundleName Indicates the bundle Names. + * @return Returns true if install state is INSTALL_SUCCESS; returns false otherwise. + */ + bool IsAppOrAbilityInstalled(const std::string &bundleName) const; + /** + * @brief Restore uid and gid . + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool RestoreUidAndGid(); + /** + * @brief Recycle uid and gid . + * @param info Indicates the InnerBundleInfo object. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool RecycleUidAndGid(const InnerBundleInfo &info); + +private: + mutable std::mutex bundleInfoMutex_; + mutable std::mutex stateMutex_; + mutable std::mutex uidMapMutex_; + mutable std::mutex callbackMutex_; + bool allInstallFlag_ = false; + // using for generating uid and gid + std::map sysUidMap_; + std::map sysVendorUidMap_; + std::map appUidMap_; + // use vector because these functions using for IPC, the bundleName may duplicate + std::vector> callbackList_; + // all installed bundles + // key:bundleName + // value:deviceId-innerbundleinfo pair + std::map> bundleInfos_; + // key:bundle name + std::map installStates_; + // current-status:previous-statue pair + std::multimap transferStates_; + std::shared_ptr dataStorage_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_DATA_MGR_H diff --git a/services/bundlemgr/include/bundle_data_storage.h b/services/bundlemgr/include/bundle_data_storage.h new file mode 100644 index 000000000..744d53e8d --- /dev/null +++ b/services/bundlemgr/include/bundle_data_storage.h @@ -0,0 +1,72 @@ +/* + * 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_DATA_STORAGE_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_DATA_STORAGE_H + +#include + +#include "inner_bundle_info.h" +#include "bundle_data_storage_interface.h" + +namespace OHOS { +namespace AppExecFwk { + +class BundleDataStorage : public IBundleDataStorage { +public: + /** + * @brief Load all installed bundles data from bmsdb.json to innerBundleInfos. + * @param infos Indicates the map to save all installed bundles. + * @return Returns true if the data is successfully loaded; returns false otherwise. + */ + virtual bool LoadAllData(std::map> &infos) const; + /** + * @brief Save the bundle data corresponding to the device Id of the bundle name to bmsdb.json. + * @param deviceId Indicates this device Id corresponding to the bundle name. + * @param innerBundleInfo Indicates the InnerBundleInfo object to be save. + * @return Returns true if the data is successfully saved; returns false otherwise. + */ + virtual bool SaveStorageBundleInfo(const std::string &deviceId, const InnerBundleInfo &innerBundleInfo) const; + /** + * @brief Modify the bundle data corresponding to the device Id of the bundle name to bmsdb.json. + * @param deviceId Indicates this device Id corresponding to the bundle name. + * @param innerBundleInfo Indicates the InnerBundleInfo object to be Modify. + * @return Returns true if the data is successfully modified; returns false otherwise. + */ + virtual bool ModifyStorageBundleInfo(const std::string &deviceId, const InnerBundleInfo &innerBundleInfo) const; + /** + * @brief Delete the bundle data corresponding to the device Id of the bundle name to bmsdb.json. + * @param deviceId Indicates this device Id corresponding to the bundle name. + * @param innerBundleInfo Indicates the InnerBundleInfo object to be Delete. + * @return Returns true if the data is successfully deleted; returns false otherwise. + */ + virtual bool DeleteStorageBundleInfo(const std::string &deviceId, const InnerBundleInfo &innerBundleInfo) const; + /** + * @brief Delete the module data corresponding to the device Id of the bundle name to bmsdb.json. + * @param deviceId Indicates this device Id corresponding to the bundle name. + * @param innerBundleInfo Indicates the InnerBundleInfo object to be Delete. + * @return Returns true if the data is successfully deleted; returns false otherwise. + */ + virtual bool DeleteStorageModuleInfo( + const std::string &deviceId, const InnerBundleInfo &innerBundleInfo, const std::string &moduleName) const; + +private: + bool KeyToDeviceAndName(const std::string &key, std::string &deviceId, std::string &bundleName) const; + void DeviceAndNameToKey(const std::string &deviceId, const std::string &bundleName, std::string &key) const; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_DATA_STORAGE_H diff --git a/services/bundlemgr/include/bundle_data_storage_interface.h b/services/bundlemgr/include/bundle_data_storage_interface.h new file mode 100644 index 000000000..999ef39ad --- /dev/null +++ b/services/bundlemgr/include/bundle_data_storage_interface.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_BUNDLEMGR_INCLUDE_IBUNDLE_DATA_STORAGE_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_IBUNDLE_DATA_STORAGE_H + +#include + +#include "inner_bundle_info.h" + +namespace OHOS { +namespace AppExecFwk { + +class IBundleDataStorage { +public: + IBundleDataStorage() = default; + virtual ~IBundleDataStorage() = default; + /** + * @brief Load all installed bundles data from bmsdb.json to innerBundleInfos. + * @param infos Indicates the map to save all installed bundles. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool LoadAllData(std::map> &infos) const = 0; + /** + * @brief Save the bundle data corresponding to the device Id of the bundle name to bmsdb.json. + * @param deviceId Indicates this device Id corresponding to the bundle name. + * @param innerBundleInfo Indicates the InnerBundleInfo object to be save. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool SaveStorageBundleInfo(const std::string &deviceId, const InnerBundleInfo &innerBundleInfo) const = 0; + /** + * @brief Modify the bundle data corresponding to the device Id of the bundle name to bmsdb.json. + * @param deviceId Indicates this device Id corresponding to the bundle name. + * @param innerBundleInfo Indicates the InnerBundleInfo object to be Modify. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool ModifyStorageBundleInfo(const std::string &deviceId, const InnerBundleInfo &innerBundleInfo) const = 0; + /** + * @brief Delete the bundle data corresponding to the device Id of the bundle name to bmsdb.json. + * @param deviceId Indicates this device Id corresponding to the bundle name. + * @param innerBundleInfo Indicates the InnerBundleInfo object to be Delete. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool DeleteStorageBundleInfo(const std::string &deviceId, const InnerBundleInfo &innerBundleInfo) const = 0; + /** + * @brief Delete the module data corresponding to the device Id of the bundle name to bmsdb.json. + * @param deviceId Indicates this device Id corresponding to the bundle name. + * @param innerBundleInfo Indicates the InnerBundleInfo object to be Delete. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool DeleteStorageModuleInfo( + const std::string &deviceId, const InnerBundleInfo &innerBundleInfo, const std::string &moduleName) const = 0; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_IBUNDLE_DATA_STORAGE_H diff --git a/services/bundlemgr/include/bundle_extractor.h b/services/bundlemgr/include/bundle_extractor.h new file mode 100644 index 000000000..96f2475ee --- /dev/null +++ b/services/bundlemgr/include/bundle_extractor.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_BUNDLE_EXTRACTOR_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_EXTRACTOR_H + +#include + +#include "base_extractor.h" + +namespace OHOS { +namespace AppExecFwk { + +class BundleExtractor : public BaseExtractor { +public: + explicit BundleExtractor(const std::string &source); + virtual ~BundleExtractor() override; + /** + * @brief Extract the config.json of a hap to dest stream. + * @param dest Indicates the obtained std::ostream object. + * @return Returns true if the Profile is successfully extracted; returns false otherwise. + */ + virtual bool ExtractProfile(std::ostream &dest) const override; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_EXTRACTOR_H diff --git a/services/bundlemgr/include/bundle_installer.h b/services/bundlemgr/include/bundle_installer.h new file mode 100644 index 000000000..17a099271 --- /dev/null +++ b/services/bundlemgr/include/bundle_installer.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_BUNDLEMGR_INCLUDE_BUNDLE_INSTALLER_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_INSTALLER_H + +#include +#include + +#include "nocopyable.h" + +#include "base_bundle_installer.h" +#include "event_handler.h" +#include "status_receiver_interface.h" + +namespace OHOS { +namespace AppExecFwk { + +class BundleInstaller : public BaseBundleInstaller { +public: + BundleInstaller(const int64_t installerId, const std::shared_ptr &handler, + const sptr &statusReceiver); + virtual ~BundleInstaller() override; + /** + * @brief Get the installer ID of an installer object. + * @return Returns the installer ID of this object. + */ + int64_t GetInstallerId() const + { + return installerId_; + } + /** + * @brief Install a bundle using this installer object. + * @param bundleFilePath Indicates the path for storing the HAP of the bundle to install or update. + * @param installParam Indicates the install parameters. + * @return + */ + void Install(const std::string &bundleFilePath, const InstallParam &installParam); + /** + * @brief Uninstall a bundle using this installer object. + * @param bundleName Indicates the bundle name of the application to uninstall. + * @param installParam Indicates the uninstall parameters. + * @return + */ + void Uninstall(const std::string &bundleName, const InstallParam &installParam); + /** + * @brief Uninstall a module using this installer object. + * @param bundleName Indicates the bundle name of the module to uninstall. + * @param modulePackage Indicates the module package of the module to uninstall. + * @param installParam Indicates the uninstall parameters. + * @return + */ + void Uninstall(const std::string &bundleName, const std::string &modulePackage, const InstallParam &installParam); + /** + * @brief Update the installer state and send status from the StatusReceiver object. + * @attention This function will send the install status to StatusReceiver. + * @param state Indicates the state to be updated to. + * @return + */ + virtual void UpdateInstallerState(const InstallerState state) override; + +private: + /** + * @brief Send an event for requesting to remove this bundle installer object. + * @return + */ + void SendRemoveEvent() const; + +private: + const int64_t installerId_ = 0; + const std::weak_ptr handler_; + const sptr statusReceiver_; + + DISALLOW_COPY_AND_MOVE(BundleInstaller); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_INSTALLER_H \ No newline at end of file diff --git a/services/bundlemgr/include/bundle_installer_host.h b/services/bundlemgr/include/bundle_installer_host.h new file mode 100644 index 000000000..58ca72e7d --- /dev/null +++ b/services/bundlemgr/include/bundle_installer_host.h @@ -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. + */ + +#ifndef FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_INSTALLER_HOST_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_INSTALLER_HOST_H + +#include +#include + +#include "iremote_stub.h" +#include "nocopyable.h" + +#include "bundle_installer_interface.h" +#include "bundle_installer_manager.h" + +namespace OHOS { +namespace AppExecFwk { + +class BundleInstallerHost : public IRemoteStub { +public: + BundleInstallerHost(); + virtual ~BundleInstallerHost() override; + + bool Init(); + virtual int OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + /** + * @brief Installs an application, the final result will be notified from the statusReceiver object. + * @attention Notice that the bundleFilePath should be an absolute path. + * @param bundleFilePath Indicates the path for storing the ohos Ability Package (HAP) of the application + * to install or update. + * @param installParam Indicates the install parameters. + * @param statusReceiver Indicates the callback object that using for notifing the install result. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool Install(const std::string &bundleFilePath, const InstallParam &installParam, + const sptr &statusReceiver) override; + /** + * @brief Uninstalls an application, the result will be notified from the statusReceiver object. + * @param bundleName Indicates the bundle name of the application to uninstall. + * @param installParam Indicates the uninstall parameters. + * @param statusReceiver Indicates the callback object that using for notifing the uninstall result. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool Uninstall(const std::string &bundleName, const InstallParam &installParam, + const sptr &statusReceiver) override; + /** + * @brief Uninstalls a module in an application, the result will be notified from the statusReceiver object. + * @param bundleName Indicates the bundle name of the module to uninstall. + * @param modulePackage Indicates the module package of the module to uninstall. + * @param installParam Indicates the uninstall parameters. + * @param statusReceiver Indicates the callback object that using for notifing the uninstall result. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool Uninstall(const std::string &bundleName, const std::string &modulePackage, + const InstallParam &installParam, const sptr &statusReceiver) override; + +private: + /** + * @brief Handles the Install function called from a IBundleInstaller proxy object. + * @param data Indicates the data to be read. + * @param reply Indicates the reply to be sent; + * @return + */ + void HandleInstallMessage(Parcel &data); + /** + * @brief Handles the Uninstall bundle function called from a IBundleInstaller proxy object. + * @param data Indicates the data to be read. + * @param reply Indicates the reply to be sent; + * @return + */ + void HandleUninstallMessage(Parcel &data); + /** + * @brief Handles the Uninstall module function called from a IBundleInstaller proxy object. + * @param data Indicates the data to be read. + * @param reply Indicates the reply to be sent; + * @return + */ + void HandleUninstallModuleMessage(Parcel &data); + /** + * @brief Check whether the statusReceiver object is valid. + * @param statusReceiver Indicates the IStatusReceiver object. + * @return Returns true if the object is valid; returns false otherwise. + */ + bool CheckBundleInstallerManager(const sptr &statusReceiver) const; + +private: + std::shared_ptr manager_; + + DISALLOW_COPY_AND_MOVE(BundleInstallerHost); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_INSTALLER_HOST_H \ No newline at end of file diff --git a/services/bundlemgr/include/bundle_installer_manager.h b/services/bundlemgr/include/bundle_installer_manager.h new file mode 100644 index 000000000..ec6b56a41 --- /dev/null +++ b/services/bundlemgr/include/bundle_installer_manager.h @@ -0,0 +1,104 @@ +/* + * 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_INSTALLER_MANAGER_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_INSTALLER_MANAGER_H + +#include +#include +#include +#include + +#include "nocopyable.h" +#include "thread_pool.h" + +#include "bundle_installer.h" +#include "event_handler.h" +#include "status_receiver_interface.h" + +namespace OHOS { +namespace AppExecFwk { + +class BundleInstallerManager : public EventHandler { +public: + explicit BundleInstallerManager(const std::shared_ptr &runner); + virtual ~BundleInstallerManager() override; + /** + * @brief Process the event of destroy bundle installer object. + * @param event Indicates the event to be processed. + * @return + */ + virtual void ProcessEvent(const InnerEvent::Pointer &event) override; + /** + * @brief Create a bundle installer object for installing a bundle. + * @param bundleFilePath Indicates the path for storing the HAP of the bundle to install or update. + * @param installParam Indicates the install parameters. + * @param statusReceiver Indicates the callback object that using for notifing the install result. + * @return + */ + void CreateInstallTask(const std::string &bundleFilePath, const InstallParam &installParam, + const sptr &statusReceiver); + /** + * @brief Create a bundle installer object for uninstalling an bundle. + * @param bundleName Indicates the bundle name of the application to uninstall. + * @param installParam Indicates the uninstall parameters. + * @param statusReceiver Indicates the callback object that using for notifing the uninstall result. + * @return + */ + void CreateUninstallTask( + const std::string &bundleName, const InstallParam &installParam, const sptr &statusReceiver); + /** + * @brief Create a bundle installer object for uninstalling a module. + * @param bundleName Indicates the bundle name of the module to uninstall. + * @param modulePackage Indicates the module package of the module to uninstall. + * @param installParam Indicates the uninstall parameters. + * @param statusReceiver Indicates the callback object that using for notifing the uninstall result. + * @return + */ + void CreateUninstallTask(const std::string &bundleName, const std::string &modulePackage, + const InstallParam &installParam, const sptr &statusReceiver); + enum { + REMOVE_BUNDLE_INSTALLER = 1, + }; + +private: + /** + * @brief Create a bundle installer object internal. + * @param statusReceiver Indicates the callback object for this installer. + * @return Returns a pointers to BundleInstaller object. + */ + std::shared_ptr CreateInstaller(const sptr &statusReceiver); + /** + * @brief Remove an installer object with the installer ID. + * @param installerId Indicates the installer ID. + * @return + */ + void RemoveInstaller(const int64_t installerId); + +private: + const int MAX_TASK_NUMBER = 10; + const int THREAD_NUMBER = 1; + // Thread pool used to start multipule installer in parallel. + ThreadPool installersPool_; + std::mutex mutex_; + // map key will use timestamp. + std::unordered_map> installers_; + + DISALLOW_COPY_AND_MOVE(BundleInstallerManager); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_INSTALLER_MANAGER_H diff --git a/services/bundlemgr/include/bundle_mgr_host_impl.h b/services/bundlemgr/include/bundle_mgr_host_impl.h new file mode 100644 index 000000000..892951945 --- /dev/null +++ b/services/bundlemgr/include/bundle_mgr_host_impl.h @@ -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. + */ + +#ifndef FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_MGR_HOST_IMPL_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_MGR_HOST_IMPL_H + +#include "bundle_mgr_host.h" +#include "bundle_data_mgr.h" + +namespace OHOS { +namespace AppExecFwk { + +class BundleMgrHostImpl : public BundleMgrHost { +public: + /** + * @brief Obtains the ApplicationInfo based on a given bundle name. + * @param appName 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 appInfo Indicates the obtained ApplicationInfo object. + * @return Returns true if the application is successfully obtained; returns false otherwise. + */ + virtual bool GetApplicationInfo( + const std::string &appName, const ApplicationFlag flag, const int userId, ApplicationInfo &appInfo) override; + /** + * @brief Obtains information about all installed applications of a specified user. + * @param flag Indicates the flag used to specify information contained + * in the ApplicationInfo objects that will be returned. + * @param userId Indicates the user ID. + * @param appInfos Indicates all of the obtained ApplicationInfo objects. + * @return Returns true if the applications is successfully obtained; returns false otherwise. + */ + virtual bool GetApplicationInfos( + const ApplicationFlag flag, const int userId, std::vector &appInfos) override; + /** + * @brief Obtains the BundleInfo based on a given bundle name. + * @param bundleName Indicates the application bundle name to be queried. + * @param flag Indicates the information contained in the BundleInfo object to be returned. + * @param bundleInfo Indicates the obtained BundleInfo object. + * @return Returns true if the BundleInfo is successfully obtained; returns false otherwise. + */ + virtual bool GetBundleInfo(const std::string &bundleName, const BundleFlag flag, BundleInfo &bundleInfo) override; + /** + * @brief Obtains BundleInfo of all bundles available in the system. + * @param flag Indicates the flag used to specify information contained in the BundleInfo that will be returned. + * @param bundleInfos Indicates all of the obtained BundleInfo objects. + * @return Returns true if the BundleInfos is successfully obtained; returns false otherwise. + */ + virtual bool GetBundleInfos(const BundleFlag flag, std::vector &bundleInfos) override; + /** + * @brief Obtains the application UID based on the given bundle name and user ID. + * @param bundleName Indicates the bundle name of the application. + * @param userId Indicates the user ID. + * @return Returns the uid if successfully obtained; returns -1 otherwise. + */ + virtual bool GetBundleNameForUid(const int uid, std::string &bundleName) override; + /** + * @brief Obtains an array of all group IDs associated with a specified bundle. + * @param bundleName Indicates the bundle name. + * @param gids Indicates the group IDs associated with the specified bundle. + * @return Returns true if the gids is successfully obtained; returns false otherwise. + */ + virtual bool GetBundleGids(const std::string &bundleName, std::vector &gids) override; + /** + * @brief Check whether the app is system app by it's UID. + * @param uid Indicates the uid. + * @return Returns true if the bundle is a system application; returns false otherwise. + */ + virtual bool CheckIsSystemAppByUid(const int uid) override; + /** + * @brief Obtains the BundleInfo of application bundles based on the specified metaData. + * @param metaData Indicates the metadata to get in the bundle. + * @param bundleInfos Indicates all of the obtained BundleInfo objects. + * @return Returns true if the BundleInfos is successfully obtained; returns false otherwise. + */ + virtual bool GetBundleInfosByMetaData(const std::string &metaData, std::vector &bundleInfos) override; + /** + * @brief Query the AbilityInfo by the given Want. + * @param want Indicates the information of the ability. + * @param abilityInfo Indicates the obtained AbilityInfo object. + * @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 by ability.uri in config.json. + * @param abilityUri Indicates the uri of the ability. + * @param abilityInfo Indicates the obtained AbilityInfo object. + * @return Returns true if the AbilityInfo is successfully obtained; returns false otherwise. + */ + virtual bool QueryAbilityInfoByUri(const std::string &abilityUri, AbilityInfo &abilityInfo) override; + /** + * @brief Obtains the BundleInfo of all keep-alive applications in the system. + * @param bundleInfos Indicates all of the obtained BundleInfo objects. + * @return Returns true if the BundleInfos is successfully obtained; returns false otherwise. + */ + virtual bool QueryKeepAliveBundleInfos(std::vector &bundleInfos) override; + /** + * @brief Obtains the label of a specified ability. + * @param bundleName Indicates the bundle name. + * @param className Indicates the ability class name. + * @return Returns the label of the ability if exist; returns empty string otherwise. + */ + virtual std::string GetAbilityLabel(const std::string &bundleName, const std::string &className) override; + /** + * @brief Obtains information about an application bundle contained in an ohos Ability Package (HAP). + * @param hapFilePath Indicates the absolute file path of the HAP. + * @param flag Indicates the information contained in the BundleInfo object to be returned. + * @param bundleInfo Indicates the obtained BundleInfo object. + * @return Returns true if the BundleInfo is successfully obtained; returns false otherwise. + */ + virtual bool GetBundleArchiveInfo( + const std::string &hapFilePath, const BundleFlag flag, BundleInfo &bundleInfo) override; + /** + * @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; + /** + * @brief Obtains the Want for starting the main ability of an application based on the given bundle name. + * @param bundleName Indicates the bundle name. + * @param want Indicates the obtained launch Want object. + * @return Returns true if the launch Want object is successfully obtained; returns false otherwise. + */ + virtual bool GetLaunchWantForBundle(const std::string &bundleName, Want &want) override; + /** + * @brief Checks whether the publickeys of two bundles are the same. + * @param firstBundleName Indicates the first bundle name. + * @param secondBundleName Indicates the second bundle name. + * @return Returns SIGNATURE_UNKNOWN_BUNDLE if at least one of the given bundles is not found; + * returns SIGNATURE_NOT_MATCHED if their publickeys are different; + * returns SIGNATURE_MATCHED if their publickeys are the same. + */ + virtual int CheckPublicKeys(const std::string &firstBundleName, const std::string &secondBundleName) override; + /** + * @brief Checks whether a specified bundle has been granted a specific permission. + * @param bundleName Indicates the name of the bundle to check. + * @param permission Indicates the permission to check. + * @return Returns 0 if the bundle has the permission; returns -1 otherwise. + */ + virtual int CheckPermission(const std::string &bundleName, const std::string &permission) override; + /** + * @brief Obtains detailed information about a specified permission. + * @param permissionName Indicates the name of the ohos permission. + * @param permissionDef Indicates the object containing detailed information about the given ohos permission. + * @return Returns true if the PermissionDef object is successfully obtained; returns false otherwise. + */ + virtual bool GetPermissionDef(const std::string &permissionName, PermissionDef &permissionDef) override; + /** + * @brief Obtains all known permission groups in the system. + * @param permissionDefs Indicates the list of objects containing the permission group information. + * @return Returns true if the PermissionDef objects is successfully obtained; returns false otherwise. + */ + virtual bool GetAllPermissionGroupDefs(std::vector &permissionDefs) override; + /** + * @brief Obtains all known permission groups in the system. + * @param permissions Indicates the permission array. + * @param appNames Indicates the list of application names that have the specified permissions. + * @return Returns true if the application names is successfully obtained; returns false otherwise. + */ + virtual bool GetAppsGrantedPermissions( + const std::vector &permissions, std::vector &appNames) override; + /** + * @brief Checks whether the system has a specified capability. + * @param capName Indicates the name of the system feature to check. + * @return Returns true if the given feature specified by name is available in the system; returns false otherwise. + */ + virtual bool HasSystemCapability(const std::string &capName) override; + /** + * @brief Obtains the capabilities that are available in the system. + * @param systemCaps Indicates the list of capabilities available in the system. + * @return Returns true if capabilities in the system are successfully obtained; returns false otherwise. + */ + virtual bool GetSystemAvailableCapabilities(std::vector &systemCaps) override; + /** + * @brief Checks whether the current device has been started in safe mode. + * @return Returns true if the device is in safe mode; returns false otherwise. + */ + virtual bool IsSafeMode() override; + /** + * @brief Clears cache data of a specified application. + * @param bundleName Indicates the bundle name of the application whose cache data is to be cleared. + * @param cleanCacheCallback Indicates the callback to be invoked for returning the operation result. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool CleanBundleCacheFiles( + const std::string &bundleName, const sptr &cleanCacheCallback) override; + /** + * @brief Clears application running data of a specified application. + * @param bundleName Indicates the bundle name of the application whose data is to be cleared. + * @return Returns true if the data cleared successfully; returns false otherwise. + */ + virtual bool CleanBundleDataFiles(const std::string &bundleName) override; + /** + * @brief Register the specific bundle status callback. + * @param bundleStatusCallback Indicates the callback to be invoked for returning the bundle status changed result. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool RegisterBundleStatusCallback(const sptr &bundleStatusCallback) override; + /** + * @brief Clear the specific bundle status callback. + * @param bundleStatusCallback Indicates the callback to be cleared. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool ClearBundleStatusCallback(const sptr &bundleStatusCallback) override; + /** + * @brief Unregister all the callbacks of status changed. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + virtual bool UnregisterBundleStatusCallback() override; + /** + * @brief Dump the bundle informations with specific flags. + * @param flag Indicates the information contained in the dump result. + * @param bundleName Indicates the bundle name if needed. + * @param result Indicates the dump information result. + * @return Returns true if the dump result is successfully obtained; returns false otherwise. + */ + virtual bool DumpInfos(const DumpFlag flag, const std::string &bundleName, std::string &result) override; + /** + * @brief Checks whether a specified application is enabled. + * @param bundleName Indicates the bundle name of the application. + * @return Returns true if the application is enabled; returns false otherwise. + */ + virtual bool IsApplicationEnabled(const std::string &bundleName) override; + /** + * @brief Sets whether to enable a specified application. + * @param bundleName Indicates the bundle name of the application. + * @param isEnable Specifies whether to enable the application. + * The value true means to enable it, and the value false means to disable it. + * @return Returns true if the application is enabled; returns false otherwise. + */ + virtual bool SetApplicationEnabled(const std::string &bundleName, bool isEnable) override; + /** + * @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() override; + /** + * @brief Confirms with the permission management module to check whether a request prompt is required for granting + * a certain permission. + * @param bundleName Indicates the name of the bundle to check. + * @param permission Indicates the permission to check. + * @param userId Indicates the user id. + * @return Returns true if the current application does not have the permission and the user does not turn off + * further requests; returns false if the current application already has the permission, the permission is rejected + * by the system, or the permission is denied by the user and the user has turned off further requests. + */ + virtual bool CanRequestPermission( + const std::string &bundleName, const std::string &permissionName, const int userId) override; + /** + * @brief Requests a certain permission from user. + * @param bundleName Indicates the name of the bundle to request permission. + * @param permission Indicates the permission to request permission. + * @param userId Indicates the user id. + * @return Returns true if the permission request successfully; returns false otherwise. + */ + virtual bool RequestPermissionFromUser( + const std::string &bundleName, const std::string &permissionName, const int userId) override; + +private: + const std::shared_ptr GetDataMgrFromService(); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_MGR_HOST_IMPL_H diff --git a/services/bundlemgr/include/bundle_mgr_service.h b/services/bundlemgr/include/bundle_mgr_service.h new file mode 100644 index 000000000..d2308c6c1 --- /dev/null +++ b/services/bundlemgr/include/bundle_mgr_service.h @@ -0,0 +1,90 @@ +/* + * 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_MGR_SERVICE_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_MGR_SERVICE_H + +#include + +#include "singleton.h" +#include "system_ability.h" + +#include "bundle_data_mgr.h" +#include "bundle_installer_host.h" +#include "bundle_mgr_host_impl.h" +#include "bundle_mgr_service_event_handler.h" + +namespace OHOS { +namespace AppExecFwk { + +class BundleMgrService : public SystemAbility { + DECLARE_DELAYED_SINGLETON(BundleMgrService); + DECLEAR_SYSTEM_ABILITY(BundleMgrService); + +public: + /** + * @brief Start the bundle manager service. + * @return + */ + virtual void OnStart() override; + /** + * @brief Stop the bundle manager service. + * @return + */ + virtual void OnStop() override; + /** + * @brief Check whether if the bundle manager service is ready. + * @return Returns true if the bundle manager service is ready; returns false otherwise. + */ + bool IsServiceReady() const; + /** + * @brief Get a shared pointer to the BundleDataMgr object. + * @return Returns the pointer of BundleDataMgr object. + */ + const std::shared_ptr GetDataMgr() const; + /** + * @brief Get a IBundleInstaller object for IPC + * @return Returns the pointer of IBundleInstaller object. + */ + sptr GetBundleInstaller() const; + +private: + /** + * @brief Initialize the bundle manager service context. + * @return Returns true if initialized successfully; returns false otherwise. + */ + bool Init(); + /** + * @brief Clean the context of this bundle manager service. + * @return + */ + void SelfClean(); + +private: + bool ready_ = false; + bool registerToService_ = false; + bool needToScan_ = false; + std::shared_ptr runner_; + std::shared_ptr handler_; + std::shared_ptr dataMgr_; + sptr host_; + sptr installer_; + + DISALLOW_COPY_AND_MOVE(BundleMgrService); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_MGR_SERVICE_H diff --git a/services/bundlemgr/include/bundle_mgr_service_event_handler.h b/services/bundlemgr/include/bundle_mgr_service_event_handler.h new file mode 100755 index 000000000..f0d07f1ab --- /dev/null +++ b/services/bundlemgr/include/bundle_mgr_service_event_handler.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_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_MGR_SERVICE_EVENT_HANDLER_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_MGR_SERVICE_EVENT_HANDLER_H + +#include "event_handler.h" +#include "bundle_constants.h" + +namespace OHOS { +namespace AppExecFwk { + +class BundleMgrService; + +class BMSEventHandler : public EventHandler { +public: + explicit BMSEventHandler(const std::shared_ptr &runner); + virtual ~BMSEventHandler() override; + /** + * @brief Process the event of install system bundles. + * @param event Indicates the event to be processed. + * @return + */ + virtual void ProcessEvent(const InnerEvent::Pointer &event) override; + + enum { + BUNDLE_SCAN_START = 1, + BUNDLE_SCAN_FINISHED, + BMS_START_FINISHED, + }; + +private: + /** + * @brief Install system and system vendor bundles. + * @param appType Indicates the bundle type. + * @return + */ + void ProcessSystemBundleInstall(Constants::AppType appType) const; + + /** + * @brief Set the flag indicates that all system and vendor applications installed. + * @return + */ + void SetAllInstallFlag() const; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_MGR_SERVICE_EVENT_HANDLER_H diff --git a/services/bundlemgr/include/bundle_parser.h b/services/bundlemgr/include/bundle_parser.h new file mode 100644 index 000000000..09be7831b --- /dev/null +++ b/services/bundlemgr/include/bundle_parser.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_BUNDLE_PARSER_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_PARSER_H + +#include + +#include "appexecfwk_errors.h" +#include "inner_bundle_info.h" + +namespace OHOS { +namespace AppExecFwk { + +class BundleParser { +public: + /** + * @brief Parse bundle by the path name, then save in innerBundleInfo info. + * @param pathName Indicates the path of Bundle. + * @param innerBundleInfo Indicates the obtained InnerBundleInfo object. + * @return Returns ERR_OK if the bundle successfully parsed; returns ErrCode otherwise. + */ + ErrCode Parse(const std::string &pathName, InnerBundleInfo &innerBundleInfo) const; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_PARSER_H diff --git a/services/bundlemgr/include/bundle_permission_mgr.h b/services/bundlemgr/include/bundle_permission_mgr.h new file mode 100644 index 000000000..5a3966898 --- /dev/null +++ b/services/bundlemgr/include/bundle_permission_mgr.h @@ -0,0 +1,161 @@ +/* + * 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_PERMISSION_MGR_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_PERMISSION_MGR_H + +#include "inner_bundle_info.h" +#include "permission_def.h" +#include "permission/permission_kit.h" + +namespace OHOS { +namespace AppExecFwk { + +class BundlePermissionMgr { +public: + /** + * @brief Initialize the system defined permissions on first start up. + * @return Returns true if the permissions initialized successfully; returns false otherwise. + */ + static bool InitPermissions(); + /** + * @brief Handle the permissions in installation progress. + * @param innerBundleInfo Indicates the current installing inner bundle information. + * @return Returns true if the permissions install successfully; returns false otherwise. + */ + static bool InstallPermissions(const InnerBundleInfo &innerBundleInfo); + /** + * @brief Handle the permissions in updating progress. + * @param innerBundleInfo Indicates the current installing inner bundle information. + * @return Returns true if the permissions updating successfully; returns false otherwise. + */ + static bool UpdatePermissions(const InnerBundleInfo &innerBundleInfo); + /** + * @brief Handle the permissions in uninstall progress. + * @param innerBundleInfo Indicates the current installing inner bundle information. + * @return Returns true if the permissions uninstall successfully; returns false otherwise. + */ + static bool UninstallPermissions(const InnerBundleInfo &innerBundleInfo); + /** + * @brief Check the permission whether granted for calling process. + * @param permissionName Indicates the permission name. + * @return Returns true if the permissions has been granted; returns false otherwise. + */ + static bool CheckCallingPermission(const std::string &permissionName); + /** + * @brief Verify whether a specified bundle has been granted a specific permission. + * @param bundleName Indicates the name of the bundle to check. + * @param permission Indicates the permission to check. + * @param userId Indicates the userId of the bundle. + * @return Returns 0 if the bundle has the permission; returns -1 otherwise. + */ + static int VerifyPermission(const std::string &bundleName, const std::string &permissionName, const int userId); + /** + * @brief Obtains detailed information about a specified permission. + * @param permissionName Indicates the name of the permission. + * @param permissionDef Indicates the object containing detailed information about the given permission. + * @return Returns true if the PermissionDef object is successfully obtained; returns false otherwise. + */ + static bool GetPermissionDef(const std::string &permissionName, PermissionDef &permissionDef); + /** + * @brief Confirms with the permission management module to check whether a request prompt is required for granting + * a certain permission. + * @param bundleName Indicates the name of the bundle. + * @param permission Indicates the permission to quest. + * @param userId Indicates the userId of the bundle. + * @return Returns true if the current application does not have the permission and the user does not turn off + * further requests; returns false if the current application already has the permission, the permission is rejected + * by the system, or the permission is denied by the user and the user has turned off further requests. + */ + static bool CanRequestPermission( + const std::string &bundleName, const std::string &permissionName, const int userId); + /** + * @brief Requests a certain permission from user. + * @param bundleName Indicates the name of the bundle. + * @param permission Indicates the permission to request. + * @param userId Indicates the userId of the bundle. + * @return Returns true if the permission request successfully; returns false otherwise. + */ + static bool RequestPermissionFromUser( + const std::string &bundleName, const std::string &permissionName, const int userId); + +private: + /** + * @brief Add the defPermissions to permission kit. + * @param innerBundleInfo Indicates the current installing inner bundle information. + * @return Returns 0 if the defPermissions add successfully; returns -1 otherwise. + */ + static int AddDefPermissions(const InnerBundleInfo &innerBundleInfo); + /** + * @brief Add and grant the reqPermissions to permission kit. + * @param innerBundleInfo Indicates the current installing inner bundle information. + * @return Returns 0 if the reqPermissions add and grant successfully; returns -1 otherwise. + */ + static int AddAndGrantedReqPermissions(const InnerBundleInfo &innerBundleInfo); + /** + * @brief Grant a reqPermission from permission kit. + * @param bundleName Indicates the name of the bundle. + * @param permissionName Indicates the permission. + * @return Returns 0 if the reqPermission grant successfully; returns -1 otherwise. + */ + static int GrantReqPermissions(const std::string &bundleName, const std::string &permissionName); + /** + * @brief Add user granted reqPermissions to permission kit. + * @param bundleName Indicates the name of the bundle to add. + * @param permList Indicates the list of reqPermission to add. + * @param userId Indicates the userId of the bundle. + * @return Returns 0 if the reqPermissions add successfully; returns -1 otherwise. + */ + static int AddUserGrantedReqPermissions( + const std::string &bundleName, const std::vector &permList, const int userId); + /** + * @brief Add system granted reqPermissions to permission kit. + * @param bundleName Indicates the name of the bundle to add. + * @param permList Indicates the list of reqPermission to add. + * @return Returns 0 if the reqPermissions add successfully; returns -1 otherwise. + */ + static int AddSystemGrantedReqPermissions(const std::string &bundleName, const std::vector &permList); + /** + * @brief Check whether a permission need to be granted. + * @param permissionDef Indicates the definition of a permission. + * @param innerBundleInfo Indicates the current installing inner bundle information. + * @return Returns true if the permission need to be granted; returns false otherwise. + */ + static bool CheckPermissionAuthorization( + const Security::Permission::PermissionDef &permissionDef, const InnerBundleInfo &innerBundleInfo); + /** + * @brief Remove the defPermissions from permission kit. + * @param innerBundleInfo Indicates the current uninstalling inner bundle information. + * @return Returns 0 if the defPermissions removed successfully; returns -1 otherwise. + */ + static int RemoveDefPermissions(const std::string &bundleName); + /** + * @brief Remove user granted reqPermissions from permission kit. + * @param bundleName Indicates the name of the bundle to remove. + * @param userId Indicates the userId of the bundle. + * @return Returns 0 if the reqPermissions removed successfully; returns -1 otherwise. + */ + static int RemoveUserGrantedReqPermissions(const std::string &bundleName, const int userId); + /** + * @brief Remove system granted reqPermissions from permission kit. + * @param bundleName Indicates the name of the bundle to remove. + * @return Returns 0 if the reqPermissions removed successfully; returns -1 otherwise. + */ + static int RemoveSystemGrantedReqPermissions(const std::string &bundleName); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_PERMISSION_MGR_H \ No newline at end of file diff --git a/services/bundlemgr/include/bundle_profile.h b/services/bundlemgr/include/bundle_profile.h new file mode 100644 index 000000000..1a9e76cbb --- /dev/null +++ b/services/bundlemgr/include/bundle_profile.h @@ -0,0 +1,38 @@ +/* + * 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_PROFILE_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_PROFILE_H + +#include "appexecfwk_errors.h" +#include "inner_bundle_info.h" + +namespace OHOS { +namespace AppExecFwk { + +class BundleProfile { +public: + /** + * @brief Transform the information of config.json to InnerBundleInfo object. + * @param source Indicates the std::ostringstream of config.json. + * @param innerBundleInfo Indicates the obtained InnerBundleInfo object. + * @return Returns ERR_OK if the information transformed successfully; returns error code otherwise. + */ + ErrCode TransformTo(const std::ostringstream &source, InnerBundleInfo &innerBundleInfo) const; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_PROFILE_H diff --git a/services/bundlemgr/include/bundle_scanner.h b/services/bundlemgr/include/bundle_scanner.h new file mode 100644 index 000000000..b96fe821d --- /dev/null +++ b/services/bundlemgr/include/bundle_scanner.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_BUNDLEMGR_INCLUDE_BUNDLE_SCANNER_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_SCANNER_H + +#include +#include +#include + +namespace OHOS { +namespace AppExecFwk { + +class BundleMgrService; + +class BundleScanner { +public: + BundleScanner(); + ~BundleScanner(); + /** + * @brief Scan the specific path. + * @param dirPath Indicates the path to scan. + * @return Returns entries if this function is successfully called; returns false otherwise. + */ + const std::list &Scan(const std::string &dirPath); + +private: + /** + * @brief Scan the specific path and save .hap files to entries_. + * @param dirPath Indicates the path to scan. + * @return Returns true if the specific path is successfully scanned; returns false otherwise. + */ + bool ScanImpl(const std::string &dirPath); + +private: + std::list entries_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_SCANNER_H diff --git a/services/bundlemgr/include/bundle_status_callback_death_recipient.h b/services/bundlemgr/include/bundle_status_callback_death_recipient.h new file mode 100644 index 000000000..631f4efc7 --- /dev/null +++ b/services/bundlemgr/include/bundle_status_callback_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_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_BUNDLE_STATUS_CALLBACK_DEATH_RECIPIENT_H +#define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_BUNDLE_STATUS_CALLBACK_DEATH_RECIPIENT_H + +#include "iremote_object.h" + +namespace OHOS { +namespace AppExecFwk { + +class BundleStatusCallbackDeathRecipient : public IRemoteObject::DeathRecipient { +public: + BundleStatusCallbackDeathRecipient(); + ~BundleStatusCallbackDeathRecipient(); + virtual void OnRemoteDied(const wptr &object) override; +}; + +} // namespace AppExecFwk +} // namespace OHOS + +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_CORE_INCLUDE_BUNDLE_STATUS_CALLBACK_DEATH_RECIPIENT_H diff --git a/services/bundlemgr/include/bundle_util.h b/services/bundlemgr/include/bundle_util.h new file mode 100644 index 000000000..6ae58bf54 --- /dev/null +++ b/services/bundlemgr/include/bundle_util.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_BUNDLEMGR_INCLUDE_BUNDLE_UTIL_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_UTIL_H + +#include + +#include "appexecfwk_errors.h" + +namespace OHOS { +namespace AppExecFwk { + +class BundleUtil { +public: + /** + * @brief Check whether a file is valid HAP file. + * @param bundlePath Indicates the HAP file path. + * @return Returns ERR_OK if the file checked successfully; returns error code otherwise. + */ + static ErrCode CheckFilePath(const std::string &bundlePath, std::string &realPath); + /** + * @brief Check whether a file is the specific type file. + * @param fileName Indicates the file path. + * @param extensionName Indicates the type to be checked. + * @return Returns true if the file type checked successfully; returns false otherwise. + */ + static bool CheckFileType(const std::string &fileName, const std::string &extensionName); + /** + * @brief Check whether a file name is valid. + * @param fileName Indicates the file path. + * @return Returns true if the file name checked successfully; returns false otherwise. + */ + static bool CheckFileName(const std::string &fileName); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_UTIL_H diff --git a/services/bundlemgr/include/bundle_verify_mgr.h b/services/bundlemgr/include/bundle_verify_mgr.h new file mode 100644 index 000000000..b31a5bd1d --- /dev/null +++ b/services/bundlemgr/include/bundle_verify_mgr.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_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_VERIFY_MGR_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_VERIFY_MGR_H + +#include "interfaces/hap_verify.h" + +namespace OHOS { +namespace AppExecFwk { + +class BundleVerifyMgr { +public: + static bool HapVerify(const std::string &filePath, Security::Verify::HapVerifyResult &hapVerifyResult); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_VERIFY_MGR_H \ No newline at end of file diff --git a/services/bundlemgr/include/common_profile.h b/services/bundlemgr/include/common_profile.h new file mode 100644 index 000000000..6c2c89451 --- /dev/null +++ b/services/bundlemgr/include/common_profile.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_BUNDLEMGR_INCLUDE_COMMON_PROFILE_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_COMMON_PROFILE_H + +#include + +#include "nlohmann/json.hpp" + +namespace OHOS { +namespace AppExecFwk { +namespace ProfileReader { + +// commen tag +const std::string PROFILE_KEY_NAME = "name"; +const std::string PROFILE_KEY_LABEL = "label"; +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"; + +// bundle profile tag +const std::string BUNDLE_PROFILE_KEY_APP = "app"; +const std::string BUNDLE_PROFILE_KEY_DEVICE_CONFIG = "deviceConfig"; +const std::string BUNDLE_PROFILE_KEY_MODULE = "module"; +// sub BUNDLE_PROFILE_KEY_APP +const std::string BUNDLE_APP_PROFILE_KEY_BUNDLE_NAME = "bundleName"; +const std::string BUNDLE_APP_PROFILE_KEY_VENDOR = "vendor"; +const std::string BUNDLE_APP_PROFILE_KEY_VERSION = "version"; +const std::string BUNDLE_APP_PROFILE_KEY_API_VERSION = "apiVersion"; +// sub BUNDLE_APP_PROFILE_KEY_VERSION +const std::string BUNDLE_APP_PROFILE_KEY_CODE = "code"; +// sub BUNDLE_APP_PROFILE_KEY_API_VERSION +const std::string BUNDLE_APP_PROFILE_KEY_COMPATIBLE = "compatible"; +const std::string BUNDLE_APP_PROFILE_KEY_TARGET = "target"; +const std::string BUNDLE_APP_PROFILE_KEY_RELEASE_TYPE = "releaseType"; +const std::string APP_RELEASE_TYPE_VALUE_RELEASE = "Release"; +// sub BUNDLE_PROFILE_KEY_DEVICE_CONFIG +const std::string BUNDLE_DEVICE_CONFIG_PROFILE_KEY_DEFAULT = "default"; +const std::string BUNDLE_DEVICE_CONFIG_PROFILE_KEY_PHONE = "phone"; +const std::string BUNDLE_DEVICE_CONFIG_PROFILE_KEY_TABLET = "tablet"; +const std::string BUNDLE_DEVICE_CONFIG_PROFILE_KEY_TV = "tv"; +const std::string BUNDLE_DEVICE_CONFIG_PROFILE_KEY_CAR = "car"; +const std::string BUNDLE_DEVICE_CONFIG_PROFILE_KEY_WEARABLE = "wearable"; +const std::string BUNDLE_DEVICE_CONFIG_PROFILE_KEY_LITE_WEARABLE = "liteWearable"; +const std::string BUNDLE_DEVICE_CONFIG_PROFILE_KEY_SMART_VISION = "smartVision"; +// sub BUNDLE_DEVICE_CONFIG_PROFILE_KEY_DEFAULT +const std::string BUNDLE_DEVICE_CONFIG_PROFILE_KEY_JOINT_USER_ID = "jointUserId"; +const std::string BUNDLE_DEVICE_CONFIG_PROFILE_KEY_PROCESS = "process"; +const std::string BUNDLE_DEVICE_CONFIG_PROFILE_KEY_KEEP_ALIVE = "keepAlive"; +const std::string BUNDLE_DEVICE_CONFIG_PROFILE_KEY_ARK = "ark"; +const std::string BUNDLE_DEVICE_CONFIG_PROFILE_KEY_DIRECT_LAUNCH = "directLaunch"; +const std::string BUNDLE_DEVICE_CONFIG_PROFILE_KEY_SUPPORT_BACKUP = "supportBackup"; +const std::string BUNDLE_DEVICE_CONFIG_PROFILE_KEY_COMPRESS_NATIVE_LIBS = "compressNativeLibs"; +const std::string BUNDLE_DEVICE_CONFIG_PROFILE_KEY_NETWORK = "network"; +const std::string BUNDLE_DEVICE_CONFIG_PROFILE_KEY_REQ_VERSION = "reqVersion"; +const std::string BUNDLE_DEVICE_CONFIG_PROFILE_KEY_FLAG = "flag"; +const std::string BUNDLE_DEVICE_CONFIG_PROFILE_KEY_COMPATIBLE = "compatible"; +const std::string BUNDLE_DEVICE_CONFIG_PROFILE_KEY_TARGET = "target"; +// sub BUNDLE_DEVICE_CONFIG_PROFILE_KEY_NETWORK +const std::string BUNDLE_DEVICE_CONFIG_PROFILE_KEY_USES_CLEAR_TEXT = "usesCleartext"; +const std::string BUNDLE_DEVICE_CONFIG_PROFILE_KEY_SECURITY_CONFIG = "securityConfig"; +// sub BUNDLE_DEVICE_CONFIG_PROFILE_KEY_SECURITY_CONFIG +const std::string BUNDLE_DEVICE_CONFIG_PROFILE_KEY_DOMAIN_SETTINGS = "domainSettings"; +// sub BUNDLE_DEVICE_CONFIG_PROFILE_KEY_DOMAIN_SETTINGS +const std::string BUNDLE_DEVICE_CONFIG_PROFILE_KEY_CLEAR_TEXT_PERMITTED = "cleartextPermitted"; +const std::string BUNDLE_DEVICE_CONFIG_PROFILE_KEY_DOMAINS = "domains"; +// sub BUNDLE_DEVICE_CONFIG_PROFILE_KEY_DOMAINS +const std::string BUNDLE_DEVICE_CONFIG_PROFILE_KEY_SUB_DOMAINS = "subDomains"; +// sub BUNDLE_PROFILE_KEY_MODULE +const std::string BUNDLE_MODULE_PROFILE_KEY_PACKAGE = "package"; +const std::string BUNDLE_MODULE_PROFILE_KEY_SUPPORTED_MODES = "supportedModes"; +const std::string BUNDLE_MODULE_PROFILE_KEY_REQ_CAPABILITIES = "reqCapabilities"; +const std::string BUNDLE_MODULE_PROFILE_KEY_SUPPORTED_REQ_CAPABILITIES = "reqCapabilities"; +const std::string MODULE_SUPPORTED_MODES_VALUE_DRIVE = "drive"; +const std::string BUNDLE_MODULE_PROFILE_KEY_DEVICE_TYPE = "deviceType"; +const std::string BUNDLE_MODULE_PROFILE_KEY_DISTRO = "distro"; +const std::string BUNDLE_MODULE_PROFILE_KEY_META_DATA = "metaData"; +const std::string BUNDLE_MODULE_PROFILE_KEY_ABILITIES = "abilities"; +const std::string BUNDLE_MODULE_PROFILE_KEY_JS = "js"; +const std::string BUNDLE_MODULE_PROFILE_KEY_COMMON_EVENTS = "commonEvents"; +const std::string BUNDLE_MODULE_PROFILE_KEY_SHORTCUTS = "shortcuts"; +const std::string BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS = "defPermissions"; +const std::string BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_NAME = "name"; +const std::string BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_GRANTMODE = "grantMode"; +const std::string BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_GRANTMODE_USER_GRANT = "user_grant"; +const std::string BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_GRANTMODE_SYSTEM_GRANT = "system_grant"; +const std::string BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_AVAILABLESCOPE = "availableScope"; +const std::string BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_AVAILABLESCOPE_SIGNATURE = "signature"; +const std::string BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_AVAILABLESCOPE_PRIVILEGED = "privileged"; +const std::string BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_AVAILABLESCOPE_RESTRICTED = "restricted"; +const std::string BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_LABEL = "label"; +const std::string BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_LABEL_ID = "labelId"; +const std::string BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_DESCRIPTION = "description"; +const std::string BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_DESCRIPTION_ID = "descriptionId"; +const std::string BUNDLE_MODULE_PROFILE_KEY_REQ_PERMISSIONS = "reqPermissions"; +const std::string BUNDLE_MODULE_PROFILE_KEY_REQ_PERMISSIONS_NAME = "name"; +const std::string BUNDLE_MODULE_PROFILE_KEY_REQ_PERMISSIONS_REASON = "reason"; +const std::string BUNDLE_MODULE_PROFILE_KEY_REQ_PERMISSIONS_USEDSCENE = "usedScene"; +const std::string BUNDLE_MODULE_PROFILE_KEY_REQ_PERMISSIONS_ABILITY = "ability"; +const std::string BUNDLE_MODULE_PROFILE_KEY_REQ_PERMISSIONS_WHEN = "when"; +const std::string BUNDLE_MODULE_PROFILE_KEY_REQ_PERMISSIONS_WHEN_INUSE = "inuse"; +const std::string BUNDLE_MODULE_PROFILE_KEY_REQ_PERMISSIONS_WHEN_ALWAYS = "always"; +const std::string BUNDLE_MODULE_PROFILE_KEY_CUSTOMIZE_DATA = "customizeData"; +// sub BUNDLE_MODULE_PROFILE_KEY_DISTRO +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"; +// sub BUNDLE_MODULE_PROFILE_KEY_SKILLS +const std::string BUNDLE_MODULE_PROFILE_KEY_ACTIONS = "actions"; +const std::string BUNDLE_MODULE_PROFILE_KEY_ENTITIES = "entities"; +const std::string BUNDLE_MODULE_PROFILE_KEY_URIS = "uris"; +// sub BUNDLE_MODULE_PROFILE_KEY_URIS +const std::string BUNDLE_MODULE_PROFILE_KEY_SCHEME = "scheme"; +const std::string BUNDLE_MODULE_PROFILE_KEY_HOST = "host"; +const std::string BUNDLE_MODULE_PROFILE_KEY_PORT = "port"; +const std::string BUNDLE_MODULE_PROFILE_KEY_PATH = "path"; +const std::string BUNDLE_MODULE_PROFILE_KEY_TYPE = "type"; +// sub BUNDLE_MODULE_PROFILE_KEY_META_DATA +const std::string BUNDLE_MODULE_META_KEY_NAME = "name"; +const std::string BUNDLE_MODULE_META_KEY_DESCRIPTION = "description"; +const std::string BUNDLE_MODULE_META_KEY_PARAMETERS = "parameters"; +const std::string BUNDLE_MODULE_META_KEY_RESULTS = "results"; +const std::string BUNDLE_MODULE_META_KEY_CUSTOMIZE_DATA = "customizeData"; +const std::string BUNDLE_MODULE_META_KEY_VALUE = "value"; +const std::string BUNDLE_MODULE_META_KEY_EXTRA = "extra"; +// sub BUNDLE_MODULE_PROFILE_KEY_DISTRO_TYPE +const std::string MODULE_DISTRO_MODULE_TYPE_VALUE_ENTRY = "entry"; +const std::string MODULE_DISTRO_MODULE_TYPE_VALUE_FEATURE = "feature"; +// sub BUNDLE_MODULE_PROFILE_KEY_ABILITIES +const std::string BUNDLE_MODULE_PROFILE_KEY_ICON = "icon"; +const std::string BUNDLE_MODULE_PROFILE_KEY_ICON_ID = "iconId"; +const std::string BUNDLE_MODULE_PROFILE_KEY_URI = "uri"; +const std::string BUNDLE_MODULE_PROFILE_KEY_LAUNCH_TYPE = "launchType"; +const std::string BUNDLE_MODULE_PROFILE_KEY_LAUNCH_THEME = "theme"; +const std::string BUNDLE_MODULE_PROFILE_KEY_VISIBLE = "visible"; +const std::string BUNDLE_MODULE_PROFILE_KEY_PERMISSIONS = "permissions"; +const std::string BUNDLE_MODULE_PROFILE_KEY_SKILLS = "skills"; +const std::string BUNDLE_MODULE_PROFILE_KEY_PROCESS = "process"; +const std::string BUNDLE_MODULE_PROFILE_KEY_DEVICE_CAP_ABILITY = "deviceCapability"; +const std::string BUNDLE_MODULE_PROFILE_KEY_FORM_ENABLED = "formEnabled"; +const std::string BUNDLE_MODULE_PROFILE_KEY_FORM = "form"; +const std::string BUNDLE_MODULE_PROFILE_KEY_ORIENTATION = "orientation"; +const std::string BUNDLE_MODULE_PROFILE_KEY_BACKGROUND_MODES = "backgroundModes"; +const std::string BUNDLE_MODULE_PROFILE_KEY_GRANT_PERMISSION = "grantPermission"; +const std::string BUNDLE_MODULE_PROFILE_KEY_URI_PERMISSION = "uriPermission"; +const std::string BUNDLE_MODULE_PROFILE_KEY_READ_PERMISSION = "readPermission"; +const std::string BUNDLE_MODULE_PROFILE_KEY_WRITE_PERMISSION = "writePermission"; +const std::string BUNDLE_MODULE_PROFILE_KEY_DIRECT_LAUNCH = "directLaunch"; +const std::string BUNDLE_MODULE_PROFILE_KEY_CONFIG_CHANGES = "configChanges"; +const std::string BUNDLE_MODULE_PROFILE_KEY_MISSION = "mission"; +const std::string BUNDLE_MODULE_PROFILE_KEY_TARGET_ABILITY = "targetAbility"; +const std::string BUNDLE_MODULE_PROFILE_KEY_MULTIUSER_SHARED = "multiUserShared"; +const std::string BUNDLE_MODULE_PROFILE_KEY_SUPPORT_PIP_MODE = "supportPipMode"; +const std::string BUNDLE_MODULE_PROFILE_KEY_FORMS_ENABLED = "formsEnabled"; +const std::string BUNDLE_MODULE_PROFILE_KEY_FORMS = "forms"; +// sub BUNDLE_MODULE_PROFILE_KEY_FORM +const std::string BUNDLE_MODULE_PROFILE_KEY_MODE = "mode"; +// sub BUNDLE_MODULE_PROFILE_KEY_FORM +const std::string BUNDLE_MODULE_PROFILE_FORM_ENTITY = "formEntity"; +const std::string BUNDLE_MODULE_PROFILE_FORM_MIN_HEIGHT = "minHeight"; +const std::string BUNDLE_MODULE_PROFILE_FORM_DEFAULT_HEIGHT = "defaultHeight"; +const std::string BUNDLE_MODULE_PROFILE_FORM_MIN_WIDTH = "minWidth"; +const std::string BUNDLE_MODULE_PROFILE_FORM_DEFAULT_WIDTH = "defaultWidth"; +// sub BUNDLE_MODULE_PROFILE_KEY_FORMS +const std::string BUNDLE_MODULE_PROFILE_FORMS_IS_DEFAULT = "isDefault"; +const std::string BUNDLE_MODULE_PROFILE_FORMS_COLOR_MODE = "colorMode"; +const std::string BUNDLE_MODULE_PROFILE_FORMS_SUPPORT_DIMENSIONS = "supportDimensions"; +const std::string BUNDLE_MODULE_PROFILE_FORMS_DEFAULT_DIMENSION = "defaultDimension"; +const std::string BUNDLE_MODULE_PROFILE_FORMS_LANDSCAPE_LAYOUTS = "landscapeLayouts"; +const std::string BUNDLE_MODULE_PROFILE_FORMS_PORTRAIT_LAYOUTS = "portraitLayouts"; +const std::string BUNDLE_MODULE_PROFILE_FORMS_UPDATEENABLED = "updateEnabled"; +const std::string BUNDLE_MODULE_PROFILE_FORMS_SCHEDULED_UPDATE_TIME = "scheduledUpateTime"; +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"; +// sub BUNDLE_MODULE_PROFILE_KEY_JS +const std::string BUNDLE_MODULE_PROFILE_KEY_PAGES = "pages"; +const std::string BUNDLE_MODULE_PROFILE_KEY_WINDOW = "window"; +// sub BUNDLE_MODULE_PROFILE_KEY_COMMON_EVENTS +const std::string BUNDLE_MODULE_PROFILE_KEY_PERMISSION = "permission"; +const std::string BUNDLE_MODULE_PROFILE_KEY_DATA = "data"; +const std::string BUNDLE_MODULE_PROFILE_KEY_EVENTS = "events"; +const std::string MODULE_ABILITY_JS_TYPE_VALUE_NORMAL = "normal"; +const std::string MODULE_ABILITY_JS_TYPE_VALUE_FORM = "form"; +// sub BUNDLE_MODULE_PROFILE_KEY_WINDOW +const std::string BUNDLE_MODULE_PROFILE_KEY_DESIGN_WIDTH = "designWidth"; +const std::string BUNDLE_MODULE_PROFILE_KEY_AUTO_DESIGN_WIDTH = "autoDesignWidth"; +// sub BUNDLE_MODULE_PROFILE_KEY_SHORTCUTS +const std::string BUNDLE_MODULE_PROFILE_KEY_SHORTCUT_ID = "shortcutId"; +const std::string BUNDLE_MODULE_PROFILE_KEY_SHORTCUT_INTENTS = "intents"; +// sub BUNDLE_MODULE_PROFILE_KEY_SHORTCUT_INTENTS +const std::string BUNDLE_MODULE_PROFILE_KEY_TARGET_CLASS = "targetClass"; +const std::string BUNDLE_MODULE_PROFILE_KEY_TARGET_BUNDLE = "targetBundle"; + +} // namespace ProfileReader +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_COMMON_PROFILE_H diff --git a/services/bundlemgr/include/inner_bundle_info.h b/services/bundlemgr/include/inner_bundle_info.h new file mode 100644 index 000000000..2479c297c --- /dev/null +++ b/services/bundlemgr/include/inner_bundle_info.h @@ -0,0 +1,825 @@ +/* + * 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_INNER_BUNDLE_INFO_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_INNER_BUNDLE_INFO_H + +#include "nocopyable.h" +#include "permission/permission_kit.h" + +#include "ability_info.h" +#include "bundle_info.h" +#include "hap_module_info.h" +#include "bundle_constants.h" +#include "json_serializer.h" +#include "common_profile.h" + +namespace OHOS { +namespace AppExecFwk { + +struct Parameters { + std::string description; + std::string name; + std::string type; +}; + +struct Results { + std::string description; + std::string name; + std::string type; +}; + +struct CustomizeData { + std::string name; + std::string value; + std::string extra; +}; + +struct MetaData { + std::vector parameters; + std::vector results; + std::vector customizeData; +}; + +struct Distro { + bool deliveryWithInstall; + std::string moduleName; + std::string moduleType; +}; + +struct DefPermission { + std::string name; + std::string grantMode; + std::vector availableScope; + std::string label; + int32_t labelId; + std::string description; + int32_t descriptionId; +}; + +struct UsedScene { + std::vector ability; + std::string when; +}; + +struct ReqPermission { + std::string name; + std::string reason; + UsedScene usedScene; +}; + +struct InnerModuleInfo { + std::string modulePackage; + std::string moduleName; + std::string modulePath; + std::string moduleDataDir; + std::string moduleResPath; + std::string description; + bool isEntry; + MetaData metaData; + Distro distro; + std::vector reqCapabilities; + std::vector reqPermissions; + std::vector defPermissions; + std::vector abilityKeys; + std::vector skillKeys; +}; + +struct SkillUri { + std::string scheme; + std::string host; + std::string port; + std::string path; + std::string type; +}; + +struct Skill { + std::vector actions; + std::vector entities; + std::vector uris; +}; + +class InnerBundleInfo { +public: + enum class BundleStatus { + ENABLED = 1, + DISABLED, + }; + + InnerBundleInfo(); + ~InnerBundleInfo(); + /** + * @brief Transform the InnerBundleInfo object to json. + * @param jsonObject Indicates the obtained json object. + * @return + */ + void ToJson(nlohmann::json &jsonObject) const; + /** + * @brief Transform the json object to InnerBundleInfo object. + * @param jsonObject Indicates the obtained json object. + * @return + */ + bool FromJson(const nlohmann::json &jsonObject); + /** + * @brief Add module info to old InnerBundleInfo object. + * @param newInfo Indicates the new InnerBundleInfo object. + * @return Returns true if the module successfully added; returns false otherwise. + */ + bool AddModuleInfo(const InnerBundleInfo &newInfo); + /** + * @brief Update module info to old InnerBundleInfo object. + * @param newInfo Indicates the new InnerBundleInfo object. + * @return + */ + void UpdateModuleInfo(const InnerBundleInfo &newInfo); + /** + * @brief Update version info to old InnerBundleInfo object. + * @param newInfo Indicates the new InnerBundleInfo object. + * @return + */ + void UpdateVersionInfo(const InnerBundleInfo &newInfo); + /** + * @brief Remove module info from InnerBundleInfo object. + * @param modulePackage Indicates the module package to be remove. + * @return + */ + void RemoveModuleInfo(const std::string &modulePackage); + /** + * @brief Find hap module info by module package. + * @param modulePackage Indicates the module package. + * @return Returns the HapModuleInfo object if find it; returns null otherwise. + */ + std::optional FindHapModuleInfo(const std::string &modulePackage) const; + /** + * @brief Find skills by keyName. + * @param keyName Indicates the keyName. + * @return Returns the skills object if find it; returns null otherwise. + */ + std::optional> FindSkills(const std::string &keyName) const; + /** + * @brief Find abilityInfo by bundle name and ability name. + * @param bundleName Indicates the bundle name. + * @param abilityName Indicates the ability name + * @return Returns the AbilityInfo object if find it; returns null otherwise. + */ + std::optional FindAbilityInfo(const std::string &bundleName, const std::string &abilityName) const; + /** + * @brief Transform the InnerBundleInfo object to string. + * @return Returns the string object + */ + std::string ToString() const; + /** + * @brief Add ability infos to old InnerBundleInfo object. + * @param abilityInfos Indicates the AbilityInfo object to be add. + * @return + */ + void AddModuleAbilityInfo(const std::map &abilityInfos) + { + for (const auto &ability : abilityInfos) { + baseAbilityInfos_.try_emplace(ability.first, ability.second); + } + } + /** + * @brief Add skill infos to old InnerBundleInfo object. + * @param skillInfos Indicates the Skill object to be add. + * @return + */ + void AddModuleSkillInfo(const std::map> &skillInfos) + { + for (const auto &skills : skillInfos) { + skillInfos_.try_emplace(skills.first, skills.second); + } + } + /** + * @brief Add innerModuleInfos to old InnerBundleInfo object. + * @param innerModuleInfos Indicates the InnerModuleInfo object to be add. + * @return + */ + void AddInnerModuleInfo(const std::map &innerModuleInfos) + { + for (const auto &info : innerModuleInfos) { + innerModuleInfos_.try_emplace(info.first, info.second); + } + } + /** + * @brief Get application name. + * @return Return application name + */ + std::string GetApplicationName() const + { + return baseApplicationInfo_.name; + } + /** + * @brief Set bundle status. + * @param status Indicates the BundleStatus object to set. + * @return + */ + void SetBundleStatus(const BundleStatus &status) + { + bundleStatus_ = status; + } + /** + * @brief Get bundle status. + * @return Return the BundleStatus object + */ + BundleStatus GetBundleStatus() const + { + return bundleStatus_; + } + /** + * @brief Set bundle install time. + * @param time Indicates the install time to set. + * @return + */ + void SetBundleInstallTime(const int64_t time) + { + baseBundleInfo_.installTime = time; + baseBundleInfo_.updateTime = time; + } + /** + * @brief Get bundle install time. + * @return Return the bundle install time. + */ + int64_t GetBundleInstallTime() const + { + return baseBundleInfo_.installTime; + } + /** + * @brief Set bundle update time. + * @param time Indicates the update time to set. + * @return + */ + void SetBundleUpdateTime(const int64_t time) + { + baseBundleInfo_.updateTime = time; + } + /** + * @brief Get bundle update time. + * @return Return the bundle update time. + */ + int64_t GetBundleUpdateTime() const + { + return baseBundleInfo_.updateTime; + } + /** + * @brief Set whether the application supports backup. + * @param isSupportBackup Indicates the supports status to set. + */ + void SetIsSupportBackup(bool isSupportBackup) + { + isSupportBackup_ = isSupportBackup; + } + /** + * @brief Get whether the application supports backup. + * @return Return the supports status. + */ + bool GetIsSupportBackup() const + { + return isSupportBackup_; + } + /** + * @brief Get bundle name. + * @return Return bundle name + */ + std::string GetBundleName() const + { + return baseApplicationInfo_.bundleName; + } + /** + * @brief Set baseBundleInfo. + * @param bundleInfo Indicates the BundleInfo object. + */ + void SetBaseBundleInfo(const BundleInfo &bundleInfo) + { + baseBundleInfo_ = bundleInfo; + } + /** + * @brief Get baseBundleInfo. + * @return Return the BundleInfo object. + */ + BundleInfo GetBaseBundleInfo() const + { + return baseBundleInfo_; + } + /** + * @brief Set baseApplicationInfo. + * @param applicationInfo Indicates the ApplicationInfo object. + */ + void SetBaseApplicationInfo(const ApplicationInfo &applicationInfo) + { + baseApplicationInfo_ = applicationInfo; + } + /** + * @brief Update baseApplicationInfo. + * @param applicationInfo Indicates the ApplicationInfo object. + */ + void UpdateBaseApplicationInfo(const ApplicationInfo &applicationInfo) + { + baseApplicationInfo_.label = applicationInfo.label; + baseApplicationInfo_.labelId = applicationInfo.labelId; + baseApplicationInfo_.iconPath = applicationInfo.iconPath; + baseApplicationInfo_.iconId = applicationInfo.iconId; + baseApplicationInfo_.description = applicationInfo.description; + baseApplicationInfo_.descriptionId = applicationInfo.descriptionId; + if (!baseApplicationInfo_.isLauncherApp) { + baseApplicationInfo_.isLauncherApp = applicationInfo.isLauncherApp; + } + } + /** + * @brief Get baseApplicationInfo. + * @return Return the ApplicationInfo object. + */ + ApplicationInfo GetBaseApplicationInfo() const + { + return baseApplicationInfo_; + } + /** + * @brief Get application code path. + * @return Return the string object. + */ + std::string GetAppCodePath() const + { + return baseApplicationInfo_.codePath; + } + /** + * @brief Set application code path. + * @param codePath Indicates the code path to be set. + */ + void SetAppCodePath(std::string codePath) + { + baseApplicationInfo_.codePath = codePath; + } + /** + * @brief Insert innerModuleInfos. + * @param modulePackage Indicates the modulePackage object as key. + * @param innerModuleInfo Indicates the InnerModuleInfo object as value. + */ + void InsertInnerModuleInfo(const std::string &modulePackage, const InnerModuleInfo &innerModuleInfo) + { + innerModuleInfos_.try_emplace(modulePackage, innerModuleInfo); + } + /** + * @brief Insert baseAbilityInfos. + * @param keyName Indicates the key. + * @param abilityInfo Indicates the AbilityInfo object as value. + */ + void InsertAbilitiesInfo(const std::string &keyName, const AbilityInfo &abilityInfo) + { + baseAbilityInfos_.emplace(keyName, abilityInfo); + } + /** + * @brief Insert skillInfos. + * @param keyName Indicates the abilityName as key. + * @param abilityInfo Indicates the Skills object as value. + */ + void InsertSkillInfo(const std::string &abilityName, const std::vector &skills) + { + skillInfos_.emplace(abilityName, skills); + } + /** + * @brief Find AbilityInfo object by Uri. + * @param abilityUri Indicates the ability uri. + * @return Returns the AbilityInfo object if find it; returns null otherwise. + */ + std::optional FindAbilityInfoByUri(const std::string &abilityUri) const + { + for (const auto &ability : baseAbilityInfos_) { + if (ability.second.uri == abilityUri) { + return ability.second; + } + } + return std::nullopt; + } + /** + * @brief Get all ability names in application. + * @return Returns ability names. + */ + auto GetAbilityNames() const + { + std::vector abilityNames; + for (auto &ability : baseAbilityInfos_) { + abilityNames.emplace_back(ability.second.name); + } + return abilityNames; + } + /** + * @brief Get all skill keys in application. + * @return Returns skill keys. + */ + auto GetSkillKeys() const + { + std::vector skillKeys; + for (auto &skill : skillInfos_) { + skillKeys.emplace_back(skill.first); + } + return skillKeys; + } + /** + * @brief Get version code in application. + * @return Returns version code. + */ + uint32_t GetVersionCode() const + { + return baseBundleInfo_.versionCode; + } + /** + * @brief Get signature key in application. + * @return Returns signature key. + */ + std::string GetSignatureKey() const + { + return baseApplicationInfo_.signatureKey; + } + /** + * @brief Set application base data dir. + * @param baseDataDir Indicates the dir to be set. + */ + void SetBaseDataDir(std::string baseDataDir) + { + baseDataDir_ = baseDataDir; + } + /** + * @brief Get application base data dir. + * @return Return the string object. + */ + std::string GetBaseDataDir() const + { + return baseDataDir_; + } + /** + * @brief Get application data dir. + * @return Return the string object. + */ + std::string GetAppDataDir() const + { + return baseApplicationInfo_.dataDir; + } + /** + * @brief Set application data dir. + * @param dataDir Indicates the data Dir to be set. + */ + void SetAppDataDir(std::string dataDir) + { + baseApplicationInfo_.dataDir = dataDir; + } + /** + * @brief Set application data base dir. + * @param dataBaseDir Indicates the data base Dir to be set. + */ + void SetAppDataBaseDir(std::string dataBaseDir) + { + baseApplicationInfo_.dataBaseDir = dataBaseDir; + } + /** + * @brief Set application cache dir. + * @param cacheDir Indicates the cache Dir to be set. + */ + void SetAppCacheDir(std::string cacheDir) + { + baseApplicationInfo_.cacheDir = cacheDir; + } + /** + * @brief Set application uid. + * @param uid Indicates the uid to be set. + */ + void SetUid(int uid) + { + uid_ = uid; + baseBundleInfo_.uid = uid; + } + /** + * @brief Get application uid. + * @return Returns the uid. + */ + int GetUid() const + { + return uid_; + } + /** + * @brief Get application gid. + * @return Returns the gid. + */ + int GetGid() const + { + return gid_; + } + /** + * @brief Set application gid. + * @param gid Indicates the gid to be set. + */ + void SetGid(int gid) + { + gid_ = gid; + baseBundleInfo_.gid = gid; + } + /** + * @brief Get application AppType. + * @return Returns the AppType. + */ + Constants::AppType GetAppType() const + { + return appType_; + } + /** + * @brief Set application AppType. + * @param gid Indicates the AppType to be set. + */ + void SetAppType(Constants::AppType appType) + { + appType_ = appType; + } + /** + * @brief Get application user id. + * @return Returns the user id. + */ + int GetUserId() const + { + return userId_; + } + /** + * @brief Set application user id. + * @param gid Indicates the user id to be set. + */ + void SetUserId(int userId) + { + userId_ = userId; + } + + // only used in install progress with newInfo + std::string GetCurrentModulePackage() const + { + return currentPackage_; + } + void SetCurrentModulePackage(const std::string &modulePackage) + { + currentPackage_ = modulePackage; + } + void AddModuleSrcDir(const std::string &moduleSrcDir) + { + if (innerModuleInfos_.count(currentPackage_) == 1) { + innerModuleInfos_.at(currentPackage_).modulePath = moduleSrcDir; + } + } + void AddModuleDataDir(const std::string &moduleDataDir) + { + if (innerModuleInfos_.count(currentPackage_) == 1) { + innerModuleInfos_.at(currentPackage_).moduleDataDir = moduleDataDir; + } + } + void AddModuleResPath(const std::string &moduleSrcDir) + { + if (innerModuleInfos_.count(currentPackage_) == 1) { + std::string moduleResPath = moduleSrcDir + Constants::PATH_SEPARATOR + Constants::ASSETS_DIR + + Constants::PATH_SEPARATOR + + innerModuleInfos_.at(currentPackage_).distro.moduleName + + Constants::PATH_SEPARATOR + Constants::RESOURCES_INDEX; + innerModuleInfos_.at(currentPackage_).moduleResPath = moduleResPath; + for (auto &abilityInfo : baseAbilityInfos_) { + abilityInfo.second.resourcePath = moduleResPath; + } + } + } + std::vector GetDefPermissions() const + { + std::vector defPermissions; + if (innerModuleInfos_.count(currentPackage_) == 1) { + defPermissions = innerModuleInfos_.at(currentPackage_).defPermissions; + } + return defPermissions; + } + + std::vector GetReqPermissions() const + { + std::vector reqPermissions; + if (innerModuleInfos_.count(currentPackage_) == 1) { + reqPermissions = innerModuleInfos_.at(currentPackage_).reqPermissions; + } + return reqPermissions; + } + + bool FindModule(std::string modulePackage) const + { + return (innerModuleInfos_.find(modulePackage) != innerModuleInfos_.end()); + } + + void SetIsKeepData(bool isKeepData) + { + isKeepData_ = isKeepData; + } + + bool GetIsKeepData() const + { + return isKeepData_; + } + + void SetIsKeepAlive(bool isKeepAlive) + { + baseBundleInfo_.isKeepAlive = isKeepAlive; + } + + bool GetIsKeepAlive() const + { + return baseBundleInfo_.isKeepAlive; + } + + void SetIsNativeApp(bool isNativeApp) + { + baseBundleInfo_.isNativeApp = isNativeApp; + } + + bool GetIsNativeApp() const + { + return baseBundleInfo_.isNativeApp; + } + + void SetIsLauncherApp(bool isLauncher) + { + baseApplicationInfo_.isLauncherApp = isLauncher; + } + + bool GetIsLauncherApp() const + { + return baseApplicationInfo_.isLauncherApp; + } + + void SetMainAbility(const std::string &mainAbility) + { + mainAbility_ = mainAbility; + } + + std::string GetMainAbility() const + { + return mainAbility_; + } + + void SetMainAbilityName(const std::string &mainAbilityName) + { + mainAbilityName_ = mainAbilityName; + } + + std::string GetMainAbilityName() const + { + return mainAbilityName_; + } + + void GetMainAbilityInfo(AbilityInfo &abilityInfo) const + { + if (!mainAbility_.empty()) { + abilityInfo = baseAbilityInfos_.at(mainAbility_); + } + } + + std::string GetModuleDir(std::string modulePackage) const + { + if (innerModuleInfos_.find(modulePackage) != innerModuleInfos_.end()) { + return innerModuleInfos_.at(modulePackage).modulePath; + } + return Constants::EMPTY_STRING; + } + + std::string GetModuleDataDir(std::string modulePackage) const + { + if (innerModuleInfos_.find(modulePackage) != innerModuleInfos_.end()) { + return innerModuleInfos_.at(modulePackage).moduleDataDir; + } + return Constants::EMPTY_STRING; + } + + bool IsDisabled() const + { + return (bundleStatus_ == BundleStatus::DISABLED); + } + + void SetSeInfo(const std::string &seInfo) + { + baseBundleInfo_.seInfo = seInfo; + } + + std::string GetSeInfo() const + { + return baseBundleInfo_.seInfo; + } + + bool IsOnlyModule(const std::string &modulePackage) + { + if ((innerModuleInfos_.size() == 1) && (innerModuleInfos_.count(modulePackage) == 1)) { + return true; + } + return false; + } + + void SetProvisionId(const std::string &provisionId) + { + provisionId_ = provisionId; + } + + std::string GetProvisionId() const + { + return provisionId_; + } + + void SetAppFeature(const std::string &appFeature) + { + appFeature_ = appFeature; + } + + std::string GetAppFeature() const + { + return appFeature_; + } + + void SetHasEntry(bool hasEntry) + { + hasEntry_ = hasEntry; + } + + bool HasEntry() const + { + return hasEntry_; + } + + // use for new Info in updating progress + void RestoreFromOldInfo(const InnerBundleInfo &oldInfo) + { + SetAppCodePath(oldInfo.GetAppCodePath()); + SetBaseDataDir(oldInfo.GetBaseDataDir()); + SetUid(oldInfo.GetUid()); + SetGid(oldInfo.GetGid()); + } + void RestoreModuleInfo(const InnerBundleInfo &oldInfo) + { + if (oldInfo.FindModule(currentPackage_)) { + innerModuleInfos_.at(currentPackage_).moduleDataDir = oldInfo.GetModuleDataDir(currentPackage_); + } + } + /** + * @brief Obtains configuration information about an application. + * @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 appInfo Indicates the obtained ApplicationInfo object. + */ + void GetApplicationInfo(const ApplicationFlag flag, const int userId, ApplicationInfo &appInfo) const; + /** + * @brief Obtains configuration information about an bundle. + * @param flag Indicates the flag used to specify information contained in the BundleInfo that will be returned. + * @param bundleInfos Indicates all of the obtained BundleInfo objects. + */ + void GetBundleInfo(const BundleFlag flag, BundleInfo &bundleInfo) const; + /** + * @brief Check if special metadata is in the application. + * @param metaData Indicates the special metaData. + * @param bundleInfos Returns true if the metadata in application; returns false otherwise. + */ + bool CheckSpecialMetaData(const std::string &metaData) const; + +private: + // using for get + bool isSupportBackup_ = false; + bool isKeepData_ = false; + Constants::AppType appType_ = Constants::AppType::THIRD_PARTY_APP; + int uid_ = Constants::INVALID_UID; + int gid_ = Constants::INVALID_GID; + int userId_ = Constants::DEFAULT_USERID; + std::string baseDataDir_; + BundleStatus bundleStatus_ = BundleStatus::ENABLED; + ApplicationInfo baseApplicationInfo_; + BundleInfo baseBundleInfo_; // applicationInfo and abilityInfo empty + std::string mainAbility_; + std::string provisionId_; + std::string appFeature_; + bool hasEntry_ = false; + // only using for install or update progress, doesn't need to save to database + std::string currentPackage_; + std::string mainAbilityName_; + + std::map baseAbilityInfos_; + std::map innerModuleInfos_; + std::map> skillInfos_; +}; + +void from_json(const nlohmann::json &jsonObject, InnerModuleInfo &info); +void from_json(const nlohmann::json &jsonObject, SkillUri &uri); +void from_json(const nlohmann::json &jsonObject, Skill &skill); +void from_json(const nlohmann::json &jsonObject, CustomizeData &customizeData); +void from_json(const nlohmann::json &jsonObject, Parameters ¶meters); +void from_json(const nlohmann::json &jsonObject, Results &results); +void from_json(const nlohmann::json &jsonObject, MetaData &metaData); +void from_json(const nlohmann::json &jsonObject, Distro &distro); +void from_json(const nlohmann::json &jsonObject, ReqPermission &ReqPermission); +void from_json(const nlohmann::json &jsonObject, DefPermission &DefPermission); +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_INNER_BUNDLE_INFO_H diff --git a/services/bundlemgr/include/installd/installd_host_impl.h b/services/bundlemgr/include/installd/installd_host_impl.h new file mode 100644 index 000000000..985830394 --- /dev/null +++ b/services/bundlemgr/include/installd/installd_host_impl.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_BUNDLEMGR_INCLUDE_INSTALLD_HOST_IMPL_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_INSTALLD_HOST_IMPL_H + +#include "ipc/installd_host.h" +#include "installd/installd_operator.h" + +namespace OHOS { +namespace AppExecFwk { + +class InstalldHostImpl : public InstalldHost { +public: + InstalldHostImpl(); + virtual ~InstalldHostImpl(); + /** + * @brief Create a bundle code directory. + * @param bundleDir Indicates the bundle code directory path that to be created. + * @return Returns ERR_OK if the bundle directory created successfully; returns error code otherwise. + */ + virtual ErrCode CreateBundleDir(const std::string &bundleDir) override; + /** + * @brief Remove a bundle code directory. + * @param bundleDir Indicates the bundle code directory path that to be removed. + * @return Returns ERR_OK if the bundle directory removed successfully; returns error code otherwise. + */ + virtual ErrCode RemoveBundleDir(const std::string &bundleDir) override; + /** + * @brief Extract the files of a HAP module to the code directory. + * @param srcModulePath Indicates the HAP file path. + * @param targetPath Indicates the code directory path that the HAP to be extracted to. + * @return Returns ERR_OK if the HAP file extracted successfully; returns error code otherwise. + */ + virtual ErrCode ExtractModuleFiles(const std::string &srcModulePath, const std::string &targetPath) override; + /** + * @brief Rename the module directory from temporaily path to the real path. + * @param oldPath Indicates the old path name. + * @param newPath Indicates the new path name. + * @return Returns ERR_OK if the module directory renamed successfully; returns error code otherwise. + */ + virtual ErrCode RenameModuleDir(const std::string &oldPath, const std::string &newPath) override; + /** + * @brief Remove the module directory. + * @param moduleDir Indicates the module directory to be removed. + * @return Returns ERR_OK if the module directory removed successfully; returns error code otherwise. + */ + virtual ErrCode RemoveModuleDir(const std::string &moduleDir) override; + /** + * @brief Create a bundle data directory. + * @param bundleDir Indicates the bundle data directory path that to be created. + * @param uid Indicates uid to be set to the directory. + * @param gid Indicates gid to be set to the directory. + * @return Returns ERR_OK if the bundle data directory created successfully; returns error code otherwise. + */ + virtual ErrCode CreateBundleDataDir(const std::string &bundleDir, const int uid, const int gid) override; + /** + * @brief Remove a bundle data directory. + * @param bundleDir Indicates the bundle data directory path that to be removed. + * @return Returns ERR_OK if the bundle data directory removed successfully; returns error code otherwise. + */ + virtual ErrCode RemoveBundleDataDir(const std::string &bundleDataDir) override; + /** + * @brief Create a module and it's abilities data directory. + * @param bundleDir Indicates the module data directory path that to be created. + * @param abilityDirs Indicates the abilities data directory name that to be created. + * @param uid Indicates uid to be set to the directory. + * @param gid Indicates gid to be set to the directory. + * @return Returns ERR_OK if the data directories created successfully; returns error code otherwise. + */ + virtual ErrCode CreateModuleDataDir(const std::string &ModuleDir, const std::vector &abilityDirs, + const int uid, const int gid) override; + /** + * @brief Remove a module data directory. + * @param bundleDir Indicates the module data directory path that to be removed. + * @return Returns ERR_OK if the module data directory removed successfully; returns error code otherwise. + */ + virtual ErrCode RemoveModuleDataDir(const std::string &moduleDataDir) override; + /** + * @brief Clean all files in a bundle data directory. + * @param bundleDir Indicates the data directory path that to be cleaned. + * @return Returns ERR_OK if the data directory cleaned successfully; returns error code otherwise. + */ + virtual ErrCode CleanBundleDataDir(const std::string &bundleDir) override; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_INSTALLD_HOST_IMPL_H \ No newline at end of file diff --git a/services/bundlemgr/include/installd/installd_operator.h b/services/bundlemgr/include/installd/installd_operator.h new file mode 100644 index 000000000..5dc3595f9 --- /dev/null +++ b/services/bundlemgr/include/installd/installd_operator.h @@ -0,0 +1,123 @@ +/* + * 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_INSTALLD_OPERATOR_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_INSTALLD_OPERATOR_H + +#include +#include +#include + +#include "nocopyable.h" +#include "appexecfwk_errors.h" + +namespace OHOS { +namespace AppExecFwk { + +class InstalldOperator { +public: + /** + * @brief Check whether a file exist. + * @param path Indicates the file path to be checked. + * @return Returns true if the file exist; returns false otherwise. + */ + static bool IsExistFile(const std::string &path); + /** + * @brief Check whether a directory exist. + * @param path Indicates the directory path to be checked. + * @return Returns true if the directory exist; returns false otherwise. + */ + static bool IsExistDir(const std::string &path); + /** + * @brief Make a new directory including the parent path if not exist. + * @param path Indicates the directory path to be checked. + * @param isReadByOthers Indicates the directory whether read by other users. + * @return Returns true if the directory make successfully; returns false otherwise. + */ + static bool MkRecursiveDir(const std::string &path, bool isReadByOthers); + /** + * @brief Delete a directory. + * @param path Indicates the directory path to be deleted. + * @return Returns true if the directory deleted successfully; returns false otherwise. + */ + static bool DeleteDir(const std::string &path); + /** + * @brief Extract the files of a compressed package to a specific directory. + * @param srcModulePath Indicates the package file path. + * @param targetPath Indicates the destination directory path that to be extracted to. + * @return Returns true if the package extracted successfully; returns false otherwise. + */ + static bool ExtractFiles(const std::string &sourcePath, const std::string &targetPath); + /** + * @brief Rename a directory from old path to new path. + * @param oldPath Indicates the old path name. + * @param newPath Indicates the new path name. + * @return Returns true if the directory renamed successfully; returns false otherwise. + */ + static bool RenameDir(const std::string &oldPath, const std::string &newPath); + /** + * @brief Change the owner and group ID of a file or directory. + * @param filePath Indicates the file or directory path. + * @param uid Indicates the uid. + * @param uid Indicates the gid. + * @return Returns true if changed successfully; returns false otherwise. + */ + static bool ChangeFileAttr(const std::string &filePath, const int uid, const int gid); + /** + * @brief Rename a file from old path to new path. + * @param oldPath Indicates the old path name. + * @param newPath Indicates the new path name. + * @return Returns true if the file renamed successfully; returns false otherwise. + */ + static bool RenameFile(const std::string &oldPath, const std::string &newPath); + /** + * @brief Check whether a path is valid under a root path. + * @param rootDir Indicates the root path name. + * @param path Indicates the path to be checked. + * @return Returns true if the path is valid successfully; returns false otherwise. + */ + static bool IsValidPath(const std::string &rootDir, const std::string &path); + /** + * @brief Check whether a path is valid code path. + * @param codePath Indicates the path to be checked. + * @return Returns true if the file renamed successfully; returns false otherwise. + */ + static bool IsValideCodePath(const std::string &codePath); + /** + * @brief Get the parent directory path of a file. + * @param codePath Indicates the file path. + * @return Returns the parent directory if get successfully; returns empty string otherwise. + */ + static std::string GetPathDir(const std::string &path); + /** + * @brief Delete files in a directory. + * @param path Indicates the directory path of the files to be deleted. + * @return Returns true if the files deleted successfully; returns false otherwise. + */ + static bool DeleteFiles(const std::string &dataPath); + /** + * @brief Make a directory and change the owner and group ID of it. + * @param path Indicates the directory path to be made. + * @param isReadByOthers Indicates the directory whether read by other users. + * @param uid Indicates the uid. + * @param uid Indicates the gid. + * @return Returns true if directory made successfully; returns false otherwise. + */ + static bool MkOwnerDir(const std::string &path, bool isReadByOthers, const int uid, const int gid); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_INSTALLD_OPERATOR_H \ No newline at end of file diff --git a/services/bundlemgr/include/installd/installd_service.h b/services/bundlemgr/include/installd/installd_service.h new file mode 100644 index 000000000..1320514ab --- /dev/null +++ b/services/bundlemgr/include/installd/installd_service.h @@ -0,0 +1,72 @@ +/* + * 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_INSTALLD_SERVICE_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_INSTALLD_SERVICE_H + +#include + +#include "installd/installd_host_impl.h" +#include "ipc/installd_host.h" + +namespace OHOS { +namespace AppExecFwk { + +class InstalldService { +public: + InstalldService(); + virtual ~InstalldService(); + /** + * @brief Start the installd service. + * @return + */ + void Start(); + /** + * @brief Stop the installd service. + * @return + */ + void Stop(); + /** + * @brief Check whether if the installd service is ready. + * @return Returns true if the installd service is ready; returns false otherwise. + */ + bool IsServiceReady() const + { + return isReady_; + } + +private: + /** + * @brief Initialize the installd service context. + * @return Returns true if initialized successfully; returns false otherwise. + */ + bool Init(); + /** + * @brief Initialize to create a directory. + * @param path Indicates the directory path to create. + * @return Returns true if directory created successfully; returns false otherwise. + */ + bool InitDir(const std::string &path); + +private: + bool isReady_ = false; + sptr hostImpl_; + + DISALLOW_COPY_AND_MOVE(InstalldService); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_INSTALLD_SERVICE_H \ No newline at end of file diff --git a/services/bundlemgr/include/installd_client.h b/services/bundlemgr/include/installd_client.h new file mode 100644 index 000000000..71daf6558 --- /dev/null +++ b/services/bundlemgr/include/installd_client.h @@ -0,0 +1,123 @@ +/* + * 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_INSTALLD_CLIENT_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_INSTALLD_CLIENT_H + +#include +#include +#include + +#include "nocopyable.h" +#include "singleton.h" + +#include "appexecfwk_errors.h" +#include "ipc/installd_interface.h" + +namespace OHOS { +namespace AppExecFwk { + +class InstalldClient : public DelayedSingleton { +public: + /** + * @brief Create a bundle code directory through an installd proxy object. + * @param bundleDir Indicates the bundle code directory path that to be created. + * @return Returns ERR_OK if the bundle directory created successfully; returns error code otherwise. + */ + ErrCode CreateBundleDir(const std::string &bundleDir); + /** + * @brief Remove a bundle code directory. + * @param bundleDir Indicates the bundle code directory path that to be removed. + * @return Returns ERR_OK if the bundle directory removed successfully; returns error code otherwise. + */ + ErrCode RemoveBundleDir(const std::string &bundleDir); + /** + * @brief Remove a bundle data directory. + * @param bundleDir Indicates the bundle data directory path that to be removed. + * @return Returns ERR_OK if the bundle data directory removed successfully; returns error code otherwise. + */ + ErrCode RemoveBundleDataDir(const std::string &bundleDataDir); + /** + * @brief Extract the files of a HAP module to the code directory. + * @param srcModulePath Indicates the HAP file path. + * @param targetPath Indicates the code directory path that the HAP to be extracted to. + * @return Returns ERR_OK if the HAP file extracted successfully; returns error code otherwise. + */ + ErrCode ExtractModuleFiles(const std::string &srcModulePath, const std::string &targetPath); + /** + * @brief Remove a module directory. + * @param moduleDir Indicates the module directory to be removed. + * @return Returns ERR_OK if the module directory removed successfully; returns error code otherwise. + */ + ErrCode RemoveModuleDir(const std::string &moduleDir); + /** + * @brief Rename the module directory from temporaily path to the real path. + * @param oldPath Indicates the old path name. + * @param newPath Indicates the new path name. + * @return Returns ERR_OK if the module directory renamed successfully; returns error code otherwise. + */ + ErrCode RenameModuleDir(const std::string &oldPath, const std::string &newPath); + /** + * @brief Create a bundle data directory. + * @param bundleDir Indicates the bundle data directory path that to be created. + * @param uid Indicates uid to be set to the directory. + * @param gid Indicates gid to be set to the directory. + * @return Returns ERR_OK if the bundle data directory created successfully; returns error code otherwise. + */ + ErrCode CreateBundleDataDir(const std::string &bundleDir, const int uid, const int gid); + /** + * @brief Create a module and it's abilities data directory. + * @param bundleDir Indicates the module data directory path that to be created. + * @param abilityDirs Indicates the abilities data directory name that to be created. + * @param uid Indicates uid to be set to the directory. + * @param gid Indicates gid to be set to the directory. + * @return Returns ERR_OK if the data directories created successfully; returns error code otherwise. + */ + ErrCode CreateModuleDataDir( + const std::string &ModuleDir, const std::vector &abilityDirs, const int uid, const int gid); + /** + * @brief Remove a module data directory. + * @param bundleDir Indicates the module data directory path that to be removed. + * @return Returns ERR_OK if the module data directory removed successfully; returns error code otherwise. + */ + ErrCode RemoveModuleDataDir(const std::string &moduleDataDir); + /** + * @brief Clean all files in a bundle data directory. + * @param bundleDir Indicates the data directory path that to be cleaned. + * @return Returns ERR_OK if the data directory cleaned successfully; returns error code otherwise. + */ + ErrCode CleanBundleDataDir(const std::string &bundleDir); + /** + * @brief Reset the installd proxy object when installd service died. + * @return + */ + void ResetInstalldProxy(); + +private: + /** + * @brief Get the installd proxy object. + * @return Returns true if the installd proxy object got successfully; returns false otherwise. + */ + bool GetInstalldProxy(); + +private: + std::mutex mutex_; + sptr installdProxy_; + sptr recipient_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_INSTALLD_CLIENT_H \ No newline at end of file diff --git a/services/bundlemgr/include/installd_death_recipient.h b/services/bundlemgr/include/installd_death_recipient.h new file mode 100644 index 000000000..f081ea537 --- /dev/null +++ b/services/bundlemgr/include/installd_death_recipient.h @@ -0,0 +1,37 @@ +/* + * 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_INSTALLD_DEATH_RECIPIENT_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_INSTALLD_DEATH_RECIPIENT_H + +#include + +#include "iremote_object.h" + +namespace OHOS { +namespace AppExecFwk { + +class InstalldDeathRecipient : public IRemoteObject::DeathRecipient { +public: + /** + * @brief Called when installd process died. + * @return + */ + virtual void OnRemoteDied([[maybe_unused]] const wptr &remote) override; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_INSTALLD_DEATH_RECIPIENT_H \ No newline at end of file diff --git a/services/bundlemgr/include/ipc/installd_host.h b/services/bundlemgr/include/ipc/installd_host.h new file mode 100644 index 000000000..419771f9d --- /dev/null +++ b/services/bundlemgr/include/ipc/installd_host.h @@ -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. + */ + +#ifndef FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_IPC_INSTALLD_HOST_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_IPC_INSTALLD_HOST_H + +#include + +#include "iremote_stub.h" + +#include "ipc/installd_interface.h" + +namespace OHOS { +namespace AppExecFwk { + +class InstalldHost : public IRemoteStub { +public: + InstalldHost(); + virtual ~InstalldHost() override; + + virtual int OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + +private: + /** + * @brief Handles the CreateBundleDir function called from a IInstalld proxy object. + * @param data Indicates the data to be read. + * @param reply Indicates the reply to be sent; + * @return Returns true if called successfully; returns false otherwise. + */ + bool HandleCreateBundleDir(MessageParcel &data, MessageParcel &reply); + /** + * @brief Handles the RemoveBundleDir function called from a IInstalld proxy object. + * @param data Indicates the data to be read. + * @param reply Indicates the reply to be sent; + * @return Returns true if called successfully; returns false otherwise. + */ + bool HandleRemoveBundleDir(MessageParcel &data, MessageParcel &reply); + /** + * @brief Handles the ExtractModuleFiles function called from a IInstalld proxy object. + * @param data Indicates the data to be read. + * @param reply Indicates the reply to be sent; + * @return Returns true if called successfully; returns false otherwise. + */ + bool HandleExtractModuleFiles(MessageParcel &data, MessageParcel &reply); + /** + * @brief Handles the RenameModuleDir function called from a IInstalld proxy object. + * @param data Indicates the data to be read. + * @param reply Indicates the reply to be sent; + * @return Returns true if called successfully; returns false otherwise. + */ + bool HandleRenameModuleDir(MessageParcel &data, MessageParcel &reply); + /** + * @brief Handles the RemoveModuleDir function called from a IInstalld proxy object. + * @param data Indicates the data to be read. + * @param reply Indicates the reply to be sent; + * @return Returns true if called successfully; returns false otherwise. + */ + bool HandleRemoveModuleDir(MessageParcel &data, MessageParcel &reply); + /** + * @brief Handles the CreateBundleDataDir function called from a IInstalld proxy object. + * @param data Indicates the data to be read. + * @param reply Indicates the reply to be sent; + * @return Returns true if called successfully; returns false otherwise. + */ + bool HandleCreateBundleDataDir(MessageParcel &data, MessageParcel &reply); + /** + * @brief Handles the RemoveBundleDataDir function called from a IInstalld proxy object. + * @param data Indicates the data to be read. + * @param reply Indicates the reply to be sent; + * @return Returns true if called successfully; returns false otherwise. + */ + bool HandleRemoveBundleDataDir(MessageParcel &data, MessageParcel &reply); + /** + * @brief Handles the CreateModuleDataDir function called from a IInstalld proxy object. + * @param data Indicates the data to be read. + * @param reply Indicates the reply to be sent; + * @return Returns true if called successfully; returns false otherwise. + */ + bool HandleCreateModuleDataDir(MessageParcel &data, MessageParcel &reply); + /** + * @brief Handles the RemoveModuleDataDir function called from a IInstalld proxy object. + * @param data Indicates the data to be read. + * @param reply Indicates the reply to be sent; + * @return Returns true if called successfully; returns false otherwise. + */ + bool HandleRemoveModuleDataDir(MessageParcel &data, MessageParcel &reply); + /** + * @brief Handles the CleanBundleDataDir function called from a IInstalld proxy object. + * @param data Indicates the data to be read. + * @param reply Indicates the reply to be sent; + * @return Returns true if called successfully; returns false otherwise. + */ + bool HandleCleanBundleDataDir(MessageParcel &data, MessageParcel &reply); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_IPC_INSTALLD_HOST_H \ No newline at end of file diff --git a/services/bundlemgr/include/ipc/installd_interface.h b/services/bundlemgr/include/ipc/installd_interface.h new file mode 100644 index 000000000..328678fdf --- /dev/null +++ b/services/bundlemgr/include/ipc/installd_interface.h @@ -0,0 +1,117 @@ +/* + * 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_IPC_INSTALLD_INTERFACE_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_IPC_INSTALLD_INTERFACE_H + +#include +#include + +#include "iremote_broker.h" + +#include "appexecfwk_errors.h" + +namespace OHOS { +namespace AppExecFwk { + +class IInstalld : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.appexecfwk.Installd"); + /** + * @brief Create a bundle code directory. + * @param bundleDir Indicates the bundle code directory path that to be created. + * @return Returns ERR_OK if the bundle directory created successfully; returns error code otherwise. + */ + virtual ErrCode CreateBundleDir(const std::string &bundleDir) = 0; + /** + * @brief Remove a bundle code directory. + * @param bundleDir Indicates the bundle code directory path that to be removed. + * @return Returns ERR_OK if the bundle directory removed successfully; returns error code otherwise. + */ + virtual ErrCode RemoveBundleDir(const std::string &bundleDir) = 0; + /** + * @brief Extract the files of a HAP module to the code directory. + * @param srcModulePath Indicates the HAP file path. + * @param targetPath Indicates the code directory path that the HAP to be extracted to. + * @return Returns ERR_OK if the HAP file extracted successfully; returns error code otherwise. + */ + virtual ErrCode ExtractModuleFiles(const std::string &srcModulePath, const std::string &destPath) = 0; + /** + * @brief Remove the module directory. + * @param moduleDir Indicates the module directory to be removed. + * @return Returns ERR_OK if the module directory removed successfully; returns error code otherwise. + */ + virtual ErrCode RemoveModuleDir(const std::string &moduleDir) = 0; + /** + * @brief Rename the module directory from temporaily path to the real path. + * @param oldPath Indicates the old path name. + * @param newPath Indicates the new path name. + * @return Returns ERR_OK if the module directory renamed successfully; returns error code otherwise. + */ + virtual ErrCode RenameModuleDir(const std::string &oldDir, const std::string &newDir) = 0; + /** + * @brief Create a bundle data directory. + * @param bundleDir Indicates the bundle data directory path that to be created. + * @param uid Indicates uid to be set to the directory. + * @param gid Indicates gid to be set to the directory. + * @return Returns ERR_OK if the bundle data directory created successfully; returns error code otherwise. + */ + virtual ErrCode CreateBundleDataDir(const std::string &bundleDir, const int uid, const int gid) = 0; + /** + * @brief Remove a bundle data directory. + * @param bundleDir Indicates the bundle data directory path that to be removed. + * @return Returns ERR_OK if the bundle data directory removed successfully; returns error code otherwise. + */ + virtual ErrCode RemoveBundleDataDir(const std::string &bundleDataDir) = 0; + /** + * @brief Create a module and it's abilities data directory. + * @param bundleDir Indicates the module data directory path that to be created. + * @param abilityDirs Indicates the abilities data directory name that to be created. + * @param uid Indicates uid to be set to the directory. + * @param gid Indicates gid to be set to the directory. + * @return Returns ERR_OK if the data directories created successfully; returns error code otherwise. + */ + virtual ErrCode CreateModuleDataDir( + const std::string &ModuleDir, const std::vector &abilityDirs, const int uid, const int gid) = 0; + /** + * @brief Remove a module data directory. + * @param bundleDir Indicates the module data directory path that to be removed. + * @return Returns ERR_OK if the module data directory removed successfully; returns error code otherwise. + */ + virtual ErrCode RemoveModuleDataDir(const std::string &moduleDataDir) = 0; + /** + * @brief Clean all files in a bundle data directory. + * @param bundleDir Indicates the data directory path that to be cleaned. + * @return Returns ERR_OK if the data directory cleaned successfully; returns error code otherwise. + */ + virtual ErrCode CleanBundleDataDir(const std::string &bundleDir) = 0; + + enum class Message { + CREATE_BUNDLE_DIR = 1, + REMOVE_BUNDLE_DIR, + EXTRACT_MODULE_FILES, + REMOVE_MODULE_DIR, + RENAME_MODULE_DIR, + CREATE_BUNDLE_DATA_DIR, + REMOVE_BUNDLE_DATA_DIR, + CREATE_MODULE_DATA_DIR, + REMOVE_MODULE_DATA_DIR, + CLEAN_BUNDLE_DATA_DIR, + }; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_IPC_INSTALLD_INTERFACE_H \ No newline at end of file diff --git a/services/bundlemgr/include/ipc/installd_proxy.h b/services/bundlemgr/include/ipc/installd_proxy.h new file mode 100644 index 000000000..bc8a106fb --- /dev/null +++ b/services/bundlemgr/include/ipc/installd_proxy.h @@ -0,0 +1,108 @@ +/* + * 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_IPC_INSTALLD_PROXY_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_IPC_INSTALLD_PROXY_H + +#include + +#include "iremote_proxy.h" +#include "appexecfwk_errors.h" +#include "ipc/installd_interface.h" + +namespace OHOS { +namespace AppExecFwk { + +class InstalldProxy : public IRemoteProxy { +public: + explicit InstalldProxy(const sptr &object); + virtual ~InstalldProxy() override; + /** + * @brief Create a bundle code directory through a proxy object. + * @param bundleDir Indicates the bundle code directory path that to be created. + * @return Returns ERR_OK if the bundle directory created successfully; returns error code otherwise. + */ + virtual ErrCode CreateBundleDir(const std::string &bundlePath) override; + /** + * @brief Remove a bundle code directory through a proxy object. + * @param bundleDir Indicates the bundle code directory path that to be removed. + * @return Returns ERR_OK if the bundle directory removed successfully; returns error code otherwise. + */ + virtual ErrCode RemoveBundleDir(const std::string &bundlePath) override; + /** + * @brief Extract the files of a HAP module to the code directory through a proxy object. + * @param srcModulePath Indicates the HAP file path. + * @param targetPath Indicates the code directory path that the HAP to be extracted to. + * @return Returns ERR_OK if the HAP file extracted successfully; returns error code otherwise. + */ + virtual ErrCode ExtractModuleFiles(const std::string &srcModulePath, const std::string &targetPath) override; + /** + * @brief Remove the module directory through a proxy object. + * @param moduleDir Indicates the module directory to be removed. + * @return Returns ERR_OK if the module directory removed successfully; returns error code otherwise. + */ + virtual ErrCode RemoveModuleDir(const std::string &moduleDir) override; + /** + * @brief Rename the module directory from temporaily path to the real path through a proxy object. + * @param oldPath Indicates the old path name. + * @param newPath Indicates the new path name. + * @return Returns ERR_OK if the module directory renamed successfully; returns error code otherwise. + */ + virtual ErrCode RenameModuleDir(const std::string &oldPath, const std::string &newPath) override; + /** + * @brief Create a bundle data directory through a proxy object. + * @param bundleDir Indicates the bundle data directory path that to be created. + * @param uid Indicates uid to be set to the directory. + * @param gid Indicates gid to be set to the directory. + * @return Returns ERR_OK if the bundle data directory created successfully; returns error code otherwise. + */ + virtual ErrCode CreateBundleDataDir(const std::string &bundleDir, const int uid, const int gid) override; + /** + * @brief Remove a bundle data directory through a proxy object. + * @param bundleDir Indicates the bundle data directory path that to be removed. + * @return Returns ERR_OK if the bundle data directory removed successfully; returns error code otherwise. + */ + virtual ErrCode RemoveBundleDataDir(const std::string &bundleDataDir) override; + /** + * @brief Create a module and it's abilities data directory through a proxy object. + * @param bundleDir Indicates the module data directory path that to be created. + * @param abilityDirs Indicates the abilities data directory name that to be created. + * @param uid Indicates uid to be set to the directory. + * @param gid Indicates gid to be set to the directory. + * @return Returns ERR_OK if the data directories created successfully; returns error code otherwise. + */ + virtual ErrCode CreateModuleDataDir(const std::string &ModuleDir, const std::vector &abilityDirs, + const int uid, const int gid) override; + /** + * @brief Remove a module data directory through a proxy object. + * @param bundleDir Indicates the module data directory path that to be removed. + * @return Returns ERR_OK if the module data directory removed successfully; returns error code otherwise. + */ + virtual ErrCode RemoveModuleDataDir(const std::string &moduleDataDir) override; + /** + * @brief Clean all files in a bundle data directory through a proxy object. + * @param bundleDir Indicates the data directory path that to be cleaned. + * @return Returns ERR_OK if the data directory cleaned successfully; returns error code otherwise. + */ + virtual ErrCode CleanBundleDataDir(const std::string &bundlePath) override; + +private: + bool TransactInstalldCmd(IInstalld::Message code, MessageParcel &data, MessageParcel &reply); + static inline BrokerDelegator delegator_; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_IPC_INSTALLD_PROXY_H \ No newline at end of file diff --git a/services/bundlemgr/include/system_ability_helper.h b/services/bundlemgr/include/system_ability_helper.h new file mode 100644 index 000000000..b1b15dcae --- /dev/null +++ b/services/bundlemgr/include/system_ability_helper.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_BUNDLEMGR_INCLUDE_SYSTEM_ABILITY_HELPER_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_SYSTEM_ABILITY_HELPER_H + +#include + +#include "iremote_object.h" + +namespace OHOS { +namespace AppExecFwk { + +class SystemAbilityHelper { +public: + /** + * @brief Get a pointer to a IRemoteObject object from system ability service. + * @param systemAbilityId Indicates the system ability ID to be got. + * @return Returns a pointer to the IRemoteObject object. + */ + static sptr GetSystemAbility(const int32_t systemAbilityId); + /** + * @brief Register a service to the system ability service. + * @param systemAbilityId Indicates the system ability ID to be registered. + * @param systemAbility Indicates the IRemoteObject pointer to be registered. + * @return Returns true if the pointer registered successfully; returns false otherwise. + */ + static bool AddSystemAbility(const int32_t systemAbilityId, const sptr &systemAbility); + /** + * @brief Unregister a service from the system ability service. + * @param systemAbilityId Indicates the system ability ID to be unregistered. + * @return Returns true if the service unregistered successfully; returns false otherwise. + */ + static bool RemoveSystemAbility(const int32_t systemAbilityId); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_SYSTEM_ABILITY_HELPER_H \ No newline at end of file diff --git a/services/bundlemgr/include/system_bundle_installer.h b/services/bundlemgr/include/system_bundle_installer.h new file mode 100644 index 000000000..fd53d17d1 --- /dev/null +++ b/services/bundlemgr/include/system_bundle_installer.h @@ -0,0 +1,43 @@ +/* + * 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_SYSTEM_BUNDLE_INSTALLER_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_SYSTEM_BUNDLE_INSTALLER_H + +#include "base_bundle_installer.h" + +namespace OHOS { +namespace AppExecFwk { + +class SystemBundleInstaller : public BaseBundleInstaller { +public: + SystemBundleInstaller(const std::string &filePath); + virtual ~SystemBundleInstaller() override; + /** + * @brief Install system and system vendor bundles. + * @param appType Indicates the bundle type. + * @return Returns true if this function called successfully; returns false otherwise. + */ + bool InstallSystemBundle(Constants::AppType appType); + +private: + const std::string filePath_; + + DISALLOW_COPY_AND_MOVE(SystemBundleInstaller); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_SYSTEM_BUNDLE_INSTALLER_H \ No newline at end of file diff --git a/services/bundlemgr/include/zip_file.h b/services/bundlemgr/include/zip_file.h new file mode 100644 index 000000000..9f9d6f858 --- /dev/null +++ b/services/bundlemgr/include/zip_file.h @@ -0,0 +1,304 @@ +/* + * 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_ZIP_FILE_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_ZIP_FILE_H + +#include +#include +#include + +#include "unzip.h" + +namespace OHOS { +namespace AppExecFwk { + +using ZipPos = ZPOS64_T; +using CentralDirEntry = struct CentralDirEntry; +using LocalHeader = struct LocalHeader; +using EndDir = struct EndDir; +using DataDesc = struct DataDesc; +using ZipEntry = struct ZipEntry; +using ZipEntryMap = std::map; +using BytePtr = Byte *; + +// Local file header: descript in APPNOTE-6.3.4 +// local file header signature 4 bytes (0x04034b50) +// version needed to extract 2 bytes +// general purpose bit flag 2 bytes +// compression method 2 bytes 10 +// last mod file time 2 bytes +// last mod file date 2 bytes +// crc-32 4 bytes +// compressed size 4 bytes 22 +// uncompressed size 4 bytes +// file name length 2 bytes +// extra field length 2 bytes 30 +struct __attribute__((packed)) LocalHeader { + uint32_t signature = 0; + uint16_t versionNeeded = 0; + uint16_t flags = 0; + uint16_t compressionMethod = 0; + uint16_t modifiedTime = 0; + uint16_t modifiedDate = 0; + uint32_t crc = 0; + uint32_t compressedSize = 0; + uint32_t uncompressedSize = 0; + uint16_t nameSize = 0; + uint16_t extraSize = 0; +}; + +// central file header +// Central File header: +// central file header signature 4 bytes (0x02014b50) +// version made by 2 bytes +// version needed to extract 2 bytes +// general purpose bit flag 2 bytes 10 +// compression method 2 bytes +// last mod file time 2 bytes +// last mod file date 2 bytes +// crc-32 4 bytes 20 +// compressed size 4 bytes +// uncompressed size 4 bytes +// file name length 2 bytes 30 +// extra field length 2 bytes +// file comment length 2 bytes +// disk number start 2 bytes +// internal file attributes 2 bytes +// external file attributes 4 bytes +// relative offset of local header 4 bytes 46byte +struct __attribute__((packed)) CentralDirEntry { + uint32_t signature = 0; + uint16_t versionMade = 0; + uint16_t versionNeeded = 0; + uint16_t flags = 0; // general purpose bit flag + uint16_t compressionMethod = 0; + uint16_t modifiedTime = 0; + uint16_t modifiedDate = 0; + uint32_t crc = 0; + uint32_t compressedSize = 0; + uint32_t uncompressedSize = 0; + uint16_t nameSize = 0; + uint16_t extraSize = 0; + uint16_t commentSize = 0; + uint16_t diskNumStart = 0; + uint16_t internalAttr = 0; + uint32_t externalAttr = 0; + uint32_t localHeaderOffset = 0; +}; + +// end of central directory packed structure +// end of central dir signature 4 bytes (0x06054b50) +// number of this disk 2 bytes +// number of the disk with the +// start of the central directory 2 bytes +// total number of entries in the +// central directory on this disk 2 bytes +// total number of entries in +// the central directory 2 bytes +// size of the central directory 4 bytes +// offset of start of central +// directory with respect to +// the starting disk number 4 bytes +// .ZIP file comment length 2 bytes +struct __attribute__((packed)) EndDir { + uint32_t signature = 0; + uint16_t numDisk = 0; + uint16_t startDiskOfCentralDir = 0; + uint16_t totalEntriesInThisDisk = 0; + uint16_t totalEntries = 0; + uint32_t sizeOfCentralDir = 0; + uint32_t offset = 0; + uint16_t commentLen = 0; +}; + +// Data descriptor: +// data descriptor signature 4 bytes (0x06054b50) +// crc-32 4 bytes +// compressed size 4 bytes +// uncompressed size 4 bytes +// This descriptor MUST exist if bit 3 of the general purpose bit flag is set (see below). +// It is byte aligned and immediately follows the last byte of compressed data. +struct __attribute__((packed)) DataDesc { + uint32_t signature = 0; + uint32_t crc = 0; + uint32_t compressedSize = 0; + uint32_t uncompressedSize = 0; +}; + +struct ZipEntry { + ZipEntry() = default; + explicit ZipEntry(const CentralDirEntry ¢ralEntry); + ~ZipEntry() = default; // for CodeDEX warning + + uint16_t compressionMethod = 0; + uint32_t uncompressedSize = 0; + uint32_t compressedSize = 0; + uint32_t localHeaderOffset = 0; + uint32_t crc = 0; + uint16_t flags = 0; + std::string fileName; +}; + +// zip file extract class for bundle format. +class ZipFile { +public: + explicit ZipFile(const std::string &pathName); + ~ZipFile(); + /** + * @brief Open zip file. + * @return Returns true if the zip file is successfully opened; returns false otherwise. + */ + bool Open(); + /** + * @brief Close zip file. + */ + void Close(); + /** + * @brief Set this zip content start offset and length in the zip file form pathName. + * @param start Indicates the zip content location start position. + * @param length Indicates the zip content length. + */ + void SetContentLocation(ZipPos start, size_t length); + /** + * @brief Get all entries in the zip file. + * @param start Indicates the zip content location start position. + * @param length Indicates the zip content length. + * @return Returns the ZipEntryMap object cotain all entries. + */ + const ZipEntryMap &GetAllEntries() const; + /** + * @brief Get entry by name. + * @param entryName Indicates the entry name. + * @param resultEntry Indicates the obtained ZipEntry object. + * @return Returns true if the ZipEntry is successfully finded; returns false otherwise. + */ + bool GetEntry(const std::string &entryName, ZipEntry &resultEntry) const; + /** + * @brief Get data relative offset for file. + * @param file Indicates the entry name. + * @param offset Indicates the obtained offset. + * @param length Indicates the length. + * @return Returns true if this function is successfully called; returns false otherwise. + */ + bool GetDataOffsetRelative(const std::string &file, ZipPos &offset, uint32_t &length) const; + /** + * @brief Get data relative offset for file. + * @param file Indicates the entry name. + * @param dest Indicates the obtained ostream object. + * @return Returns true if file is successfully extracted; returns false otherwise. + */ + bool ExtractFile(const std::string &file, std::ostream &dest) const; + +private: + /** + * @brief Check the EndDir object. + * @param endDir Indicates the EndDir object to check. + * @return Returns true if successfully checked; returns false otherwise. + */ + bool CheckEndDir(const EndDir &endDir) const; + /** + * @brief Parse the EndDir. + * @return Returns true if successfully Parsed; returns false otherwise. + */ + bool ParseEndDirectory(); + /** + * @brief Parse all Entries. + * @return Returns true if successfully parsed; returns false otherwise. + */ + bool ParseAllEntries(); + /** + * @brief Get LocalHeader object size. + * @param nameSize Indicates the nameSize. + * @param extraSize Indicates the extraSize. + * @return Returns size of LocalHeader. + */ + size_t GetLocalHeaderSize(const uint16_t nameSize = 0, const uint16_t extraSize = 0) const; + /** + * @brief Get entry data offset. + * @param zipEntry Indicates the ZipEntry object. + * @param extraSize Indicates the extraSize. + * @return Returns position. + */ + ZipPos GetEntryDataOffset(const ZipEntry &zipEntry, const uint16_t extraSize) const; + /** + * @brief Check data description. + * @param zipEntry Indicates the ZipEntry object. + * @param localHeader Indicates the localHeader object. + * @return Returns true if successfully checked; returns false otherwise. + */ + bool CheckDataDesc(const ZipEntry &zipEntry, const LocalHeader &localHeader) const; + /** + * @brief Check coherency LocalHeader object. + * @param zipEntry Indicates the ZipEntry object. + * @param extraSize Indicates the obtained size. + * @return Returns true if successfully checked; returns false otherwise. + */ + bool CheckCoherencyLocalHeader(const ZipEntry &zipEntry, uint16_t &extraSize) const; + /** + * @brief Unzip ZipEntry object to ostream. + * @param zipEntry Indicates the ZipEntry object. + * @param extraSize Indicates the size. + * @param dest Indicates the obtained ostream object. + * @return Returns true if successfully Unzip; returns false otherwise. + */ + bool UnzipWithStore(const ZipEntry &zipEntry, const uint16_t extraSize, std::ostream &dest) const; + /** + * @brief Unzip ZipEntry object to ostream. + * @param zipEntry Indicates the ZipEntry object. + * @param extraSize Indicates the size. + * @param dest Indicates the obtained ostream object. + * @return Returns true if successfully Unzip; returns false otherwise. + */ + bool UnzipWithInflated(const ZipEntry &zipEntry, const uint16_t extraSize, std::ostream &dest) const; + /** + * @brief Seek to Entry start. + * @param zipEntry Indicates the ZipEntry object. + * @param extraSize Indicates the extra size. + * @return Returns true if successfully Seeked; returns false otherwise. + */ + bool SeekToEntryStart(const ZipEntry &zipEntry, const uint16_t extraSize) const; + /** + * @brief Init zlib stream. + * @param zstream Indicates the obtained z_stream object. + * @return Returns true if successfully init; returns false otherwise. + */ + bool InitZStream(z_stream &zstream) const; + /** + * @brief Read zlib stream. + * @param buffer Indicates the buffer to read. + * @param zstream Indicates the obtained z_stream object. + * @param remainCompressedSize Indicates the obtained size. + * @return Returns true if successfully read; returns false otherwise. + */ + bool ReadZStream(const BytePtr &buffer, z_stream &zstream, uint32_t &remainCompressedSize) const; + +private: + std::string pathName_; + FILE *file_ = nullptr; + EndDir endDir_; + ZipEntryMap entriesMap_; + // offset of central directory relative to zip file. + ZipPos centralDirPos_ = 0; + // this zip content start offset relative to zip file. + ZipPos fileStartPos_ = 0; + // this zip content length in the zip file. + ZipPos fileLength_ = 0; + bool isOpen_ = false; +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_ZIP_FILE_H diff --git a/services/bundlemgr/installs.rc b/services/bundlemgr/installs.rc new file mode 100755 index 000000000..fc5fa649e --- /dev/null +++ b/services/bundlemgr/installs.rc @@ -0,0 +1,22 @@ +# 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. + +on late-fs + start installs + +service installs /system/bin/installs + class installs + priority -20 + user root + group root + seclabel u:r:installs:s0 diff --git a/services/bundlemgr/src/base_bundle_installer.cpp b/services/bundlemgr/src/base_bundle_installer.cpp new file mode 100755 index 000000000..ee8d2226a --- /dev/null +++ b/services/bundlemgr/src/base_bundle_installer.cpp @@ -0,0 +1,690 @@ +/* + * 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 "base_bundle_installer.h" + +#include +#include + +#include "datetime_ex.h" +#include "string_ex.h" +#include "system_ability_definition.h" +#include "app_log_wrapper.h" +#include "installd_client.h" +#include "perf_profile.h" +#include "system_ability_helper.h" +#include "ability_manager_interface.h" +#include "bundle_constants.h" +#include "bundle_extractor.h" +#include "bundle_mgr_service.h" +#include "bundle_parser.h" +#include "bundle_util.h" +#include "bundle_permission_mgr.h" +#include "bundle_verify_mgr.h" + +namespace OHOS { +namespace AppExecFwk { +namespace { + +bool KillApplicationProcesses(const std::string &bundleName) +{ + APP_LOGI("kill running processes, app name is %{public}s", bundleName.c_str()); + sptr abilityMgrProxy = + iface_cast(SystemAbilityHelper::GetSystemAbility(ABILITY_MGR_SERVICE_ID)); + if (!abilityMgrProxy) { + APP_LOGE("fail to find the app mgr service to kill application"); + return false; + } + if (abilityMgrProxy->KillProcess(bundleName) != 0) { + APP_LOGE("kill application process failed"); + return false; + } + return true; +} + +bool UninstallApplicationProcesses(const std::string &bundleName) +{ + APP_LOGI("uninstall kill running processes, app name is %{public}s", bundleName.c_str()); + sptr abilityMgrProxy = + iface_cast(SystemAbilityHelper::GetSystemAbility(ABILITY_MGR_SERVICE_ID)); + if (!abilityMgrProxy) { + APP_LOGE("fail to find the app mgr service to kill application"); + return false; + } + if (abilityMgrProxy->UninstallApp(bundleName) != 0) { + APP_LOGE("kill application process failed"); + return false; + } + return true; +} + +class ScopeGuard final { +public: + using Function = std::function; + explicit ScopeGuard(Function fn) : fn_(fn), dismissed_(false) + {} + + ~ScopeGuard() + { + if (!dismissed_) { + fn_(); + } + } + + void Dismiss() + { + dismissed_ = true; + } + +private: + Function fn_; + bool dismissed_; +}; + +} // namespace + +BaseBundleInstaller::BaseBundleInstaller() +{ + APP_LOGI("base bundle installer instance is created"); +} + +BaseBundleInstaller::~BaseBundleInstaller() +{ + APP_LOGI("base bundle installer instance is destroyed"); +} + +ErrCode BaseBundleInstaller::InstallBundle( + const std::string &bundlePath, const InstallParam &installParam, const Constants::AppType appType) +{ + APP_LOGI("begin to process %{public}s bundle install", bundlePath.c_str()); + PerfProfile::GetInstance().SetBundleInstallStartTime(GetTickCount()); + + ErrCode result = ProcessBundleInstall(bundlePath, installParam, appType); + if (dataMgr_ && !bundleName_.empty() && !modulePackage_.empty()) { + dataMgr_->NotifyBundleStatus( + bundleName_, modulePackage_, mainAbility_, result, isAppExist_ ? NotifyType::UPDATE : NotifyType::INSTALL); + } + + PerfProfile::GetInstance().SetBundleInstallEndTime(GetTickCount()); + APP_LOGI("finish to process %{public}s bundle install", bundlePath.c_str()); + return result; +} + +ErrCode BaseBundleInstaller::UninstallBundle(const std::string &bundleName, const InstallParam &installParam) +{ + APP_LOGD("begin to process %{public}s bundle uninstall", bundleName.c_str()); + PerfProfile::GetInstance().SetBundleUninstallStartTime(GetTickCount()); + + ErrCode result = ProcessBundleUninstall(bundleName, installParam); + if (dataMgr_) { + dataMgr_->NotifyBundleStatus( + bundleName, Constants::EMPTY_STRING, Constants::EMPTY_STRING, result, NotifyType::UNINSTALL_BUNDLE); + } + + PerfProfile::GetInstance().SetBundleUninstallEndTime(GetTickCount()); + APP_LOGD("finish to process %{public}s bundle uninstall", bundleName.c_str()); + return result; +} + +ErrCode BaseBundleInstaller::UninstallBundle( + const std::string &bundleName, const std::string &modulePackage, const InstallParam &installParam) +{ + 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); + if (dataMgr_) { + dataMgr_->NotifyBundleStatus( + bundleName, modulePackage, Constants::EMPTY_STRING, result, NotifyType::UNINSTALL_MODULE); + } + + PerfProfile::GetInstance().SetBundleUninstallEndTime(GetTickCount()); + APP_LOGD("finish to process %{public}s module in %{public}s uninstall", modulePackage.c_str(), bundleName.c_str()); + return result; +} + +void BaseBundleInstaller::UpdateInstallerState(const InstallerState state) +{ + APP_LOGI("UpdateInstallerState in BaseBundleInstaller state %{public}d", state); + SetInstallerState(state); +} + +ErrCode BaseBundleInstaller::ProcessBundleInstall( + const std::string &inBundlePath, const InstallParam &installParam, const Constants::AppType appType) +{ + APP_LOGI("ProcessBundleInstall bundlePath %{public}s", inBundlePath.c_str()); + if (installParam.userId == Constants::INVALID_USERID) { + APP_LOGE("invalid userId"); + return ERR_APPEXECFWK_INSTALL_PARAM_ERROR; + } + + std::string bundlePath; + ErrCode result = BundleUtil::CheckFilePath(inBundlePath, bundlePath); + if (result != ERR_OK) { + APP_LOGE("hap file check failed %{public}d", result); + return result; + } + 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; + } + + // parse the single bundle info to get the bundle name. + InnerBundleInfo newInfo; + modulePath_ = bundlePath; + newInfo.SetAppType(appType); + newInfo.SetUserId(installParam.userId); + newInfo.SetIsKeepData(installParam.isKeepData); + auto provisionInfo = hapVerifyResult.GetProvisionInfo(); + newInfo.SetProvisionId(provisionInfo.appId); + newInfo.SetAppFeature(provisionInfo.bundleInfo.appFeature); + + if (!ModifyInstallDirByHapType(newInfo)) { + APP_LOGE("modify bundle install dir failed %{public}d", result); + return ERR_APPEXECFWK_INSTALL_PARAM_ERROR; + } + result = ParseBundleInfo(bundlePath, newInfo); + if (result != ERR_OK) { + APP_LOGE("bundle parse failed %{public}d", result); + return result; + } + UpdateInstallerState(InstallerState::INSTALL_PARSED); + + bundleName_ = newInfo.GetBundleName(); + modulePackage_ = newInfo.GetCurrentModulePackage(); + mainAbility_ = newInfo.GetMainAbilityName(); + if (modulePackage_.empty()) { + APP_LOGE("get current package failed %{public}d", result); + return ERR_APPEXECFWK_INSTALL_PARAM_ERROR; + } + + // try to get the bundle info to decide use install or update. + InnerBundleInfo oldInfo; + dataMgr_ = DelayedSingleton::GetInstance()->GetDataMgr(); + if (!dataMgr_) { + APP_LOGE("Get dataMgr shared_ptr nullptr"); + return ERR_APPEXECFWK_INSTALL_BUNDLE_MGR_SERVICE_ERROR; + } + isAppExist_ = dataMgr_->GetInnerBundleInfo(bundleName_, Constants::CURRENT_DEVICE_ID, oldInfo); + if (isAppExist_) { + APP_LOGI("app is exist"); + bool isReplace = (installParam.installFlag == InstallFlag::REPLACE_EXISTING); + return ProcessBundleUpdateStatus(oldInfo, newInfo, isReplace); // app exist, but module may not + } + return ProcessBundleInstallStatus(newInfo); +} + +ErrCode BaseBundleInstaller::ProcessBundleUninstall(const std::string &bundleName, const InstallParam &installParam) +{ + if (bundleName.empty()) { + APP_LOGE("uninstall bundle name empty"); + return ERR_APPEXECFWK_UNINSTALL_INVALID_NAME; + } + if (installParam.userId == Constants::INVALID_USERID) { + APP_LOGE("invalid userId"); + return ERR_APPEXECFWK_UNINSTALL_PARAM_ERROR; + } + + dataMgr_ = DelayedSingleton::GetInstance()->GetDataMgr(); + if (!dataMgr_) { + APP_LOGE("Get dataMgr shared_ptr nullptr"); + return ERR_APPEXECFWK_UNINSTALL_BUNDLE_MGR_SERVICE_ERROR; + } + + InnerBundleInfo oldInfo; + if (!dataMgr_->GetInnerBundleInfo(bundleName, Constants::CURRENT_DEVICE_ID, oldInfo)) { + APP_LOGE("uninstall bundle info missing"); + return ERR_APPEXECFWK_UNINSTALL_MISSING_INSTALLED_BUNDLE; + } + ScopeGuard enableGuard([&] { dataMgr_->EnableBundle(bundleName); }); + if (oldInfo.GetAppType() == Constants::AppType::SYSTEM_APP) { + APP_LOGE("uninstall system app"); + return ERR_APPEXECFWK_UNINSTALL_SYSTEM_APP_ERROR; + } + + if (!dataMgr_->UpdateBundleInstallState(bundleName, InstallState::UNINSTALL_START)) { + APP_LOGE("uninstall already start"); + return ERR_APPEXECFWK_INSTALL_BUNDLE_MGR_SERVICE_ERROR; + } + + // kill the bundle process during uninstall. + if (!UninstallApplicationProcesses(oldInfo.GetApplicationName())) { + APP_LOGE("can not kill process"); + dataMgr_->UpdateBundleInstallState(bundleName, InstallState::INSTALL_SUCCESS); + return ERR_APPEXECFWK_UNINSTALL_KILLING_APP_ERROR; + } + enableGuard.Dismiss(); + ErrCode result = RemoveBundle(oldInfo); + if (result != ERR_OK) { + APP_LOGE("remove whole bundle failed"); + return result; + } + APP_LOGD("finish to process %{public}s bundle uninstall", bundleName.c_str()); + return ERR_OK; +} + +ErrCode BaseBundleInstaller::ProcessBundleUninstall( + const std::string &bundleName, const std::string &modulePackage, const InstallParam &installParam) +{ + if (bundleName.empty() || modulePackage.empty()) { + APP_LOGE("uninstall bundle name or module name empty"); + return ERR_APPEXECFWK_UNINSTALL_INVALID_NAME; + } + if (installParam.userId == Constants::INVALID_USERID) { + APP_LOGE("invalid userId"); + return ERR_APPEXECFWK_UNINSTALL_PARAM_ERROR; + } + + dataMgr_ = DelayedSingleton::GetInstance()->GetDataMgr(); + if (!dataMgr_) { + APP_LOGE("Get dataMgr shared_ptr nullptr"); + return ERR_APPEXECFWK_UNINSTALL_BUNDLE_MGR_SERVICE_ERROR; + } + InnerBundleInfo oldInfo; + if (!dataMgr_->GetInnerBundleInfo(bundleName, Constants::CURRENT_DEVICE_ID, oldInfo)) { + APP_LOGE("uninstall bundle info missing"); + return ERR_APPEXECFWK_UNINSTALL_MISSING_INSTALLED_BUNDLE; + } + ScopeGuard enableGuard([&] { dataMgr_->EnableBundle(bundleName); }); + + if (oldInfo.GetAppType() == Constants::AppType::SYSTEM_APP) { + APP_LOGE("uninstall system app"); + return ERR_APPEXECFWK_UNINSTALL_SYSTEM_APP_ERROR; + } + + bool isModuleExist = oldInfo.FindModule(modulePackage); + if (!isModuleExist) { + APP_LOGE("uninstall bundle info missing"); + return ERR_APPEXECFWK_UNINSTALL_MISSING_INSTALLED_MODULE; + } + + if (!dataMgr_->UpdateBundleInstallState(bundleName, InstallState::UNINSTALL_START)) { + APP_LOGE("uninstall already start"); + return ERR_APPEXECFWK_INSTALL_BUNDLE_MGR_SERVICE_ERROR; + } + ScopeGuard stateGuard([&] { dataMgr_->UpdateBundleInstallState(bundleName, InstallState::INSTALL_SUCCESS); }); + // kill the bundle process during uninstall. + if (!UninstallApplicationProcesses(oldInfo.GetApplicationName())) { + APP_LOGE("can not kill process"); + return ERR_APPEXECFWK_UNINSTALL_KILLING_APP_ERROR; + } + + // if it is the only module in the bundle + if (oldInfo.IsOnlyModule(modulePackage)) { + APP_LOGI("%{public}s is only module", modulePackage.c_str()); + enableGuard.Dismiss(); + stateGuard.Dismiss(); + return RemoveBundle(oldInfo); + } + + ErrCode result = RemoveModuleAndDataDir(oldInfo, modulePackage); + if (result != ERR_OK) { + APP_LOGE("remove module dir failed"); + return result; + } + + if (!dataMgr_->RemoveModuleInfo(bundleName, modulePackage, oldInfo)) { + APP_LOGE("RemoveModuleInfo failed"); + return ERR_APPEXECFWK_INSTALL_BUNDLE_MGR_SERVICE_ERROR; + } + APP_LOGI("finish to process %{public}s in %{public}s uninstall", bundleName.c_str(), modulePackage.c_str()); + return ERR_OK; +} + +ErrCode BaseBundleInstaller::RemoveBundle(InnerBundleInfo &info) +{ + ErrCode result = RemoveBundleAndDataDir(info, true); + if (result != ERR_OK) { + APP_LOGE("remove bundle dir failed"); + dataMgr_->UpdateBundleInstallState(info.GetBundleName(), InstallState::UNINSTALL_FAIL); + return result; + } + + if (!dataMgr_->UpdateBundleInstallState(info.GetBundleName(), InstallState::UNINSTALL_SUCCESS)) { + APP_LOGE("delete inner info failed"); + return ERR_APPEXECFWK_INSTALL_BUNDLE_MGR_SERVICE_ERROR; + } + BundlePermissionMgr::UninstallPermissions(info); + return ERR_OK; +} + +ErrCode BaseBundleInstaller::ProcessBundleInstallStatus(InnerBundleInfo &info) +{ + APP_LOGI("ProcessBundleInstallStatus %{public}s", info.GetBundleName().c_str()); + if (!dataMgr_->UpdateBundleInstallState(bundleName_, InstallState::INSTALL_START)) { + APP_LOGE("install already start"); + return ERR_APPEXECFWK_INSTALL_STATE_ERROR; + } + ScopeGuard stateGuard([&] { dataMgr_->UpdateBundleInstallState(bundleName_, InstallState::INSTALL_FAIL); }); + ErrCode result = CreateBundleAndDataDir(info); + if (result != ERR_OK) { + APP_LOGE("create bundle and data dir failed"); + return result; + } + UpdateInstallerState(InstallerState::INSTALL_CREATDIR); + ScopeGuard bundleGuard([&] { RemoveBundleAndDataDir(info, false); }); + + result = ExtractModuleAndRename(info); + if (result != ERR_OK) { + APP_LOGE("create bundle and data dir failed"); + return result; + } + + result = CreateModuleDataDir(info); + if (result != ERR_OK) { + APP_LOGE("create module data dir failed"); + return result; + } + + if (!dataMgr_->UpdateBundleInstallState(bundleName_, InstallState::INSTALL_SUCCESS)) { + APP_LOGE("update bundle %{public}s failed", bundleName_.c_str()); + return ERR_APPEXECFWK_INSTALL_BUNDLE_MGR_SERVICE_ERROR; + } + + if (!dataMgr_->AddInnerBundleInfo(bundleName_, info)) { + APP_LOGE("add bundle %{public}s info failed", bundleName_.c_str()); + dataMgr_->UpdateBundleInstallState(bundleName_, InstallState::UNINSTALL_START); + dataMgr_->UpdateBundleInstallState(bundleName_, InstallState::UNINSTALL_SUCCESS); + return ERR_APPEXECFWK_INSTALL_BUNDLE_MGR_SERVICE_ERROR; + } + UpdateInstallerState(InstallerState::INSTALL_INFO_SAVED); + stateGuard.Dismiss(); + bundleGuard.Dismiss(); + + BundlePermissionMgr::InstallPermissions(info); + UpdateInstallerState(InstallerState::INSTALL_SUCCESS); + return ERR_OK; +} + +ErrCode BaseBundleInstaller::ProcessBundleUpdateStatus( + InnerBundleInfo &oldInfo, InnerBundleInfo &newInfo, bool isReplace) +{ + // this state should always be set when return + ScopeGuard enableGuard([&] { dataMgr_->EnableBundle(bundleName_); }); + if (oldInfo.GetVersionCode() > newInfo.GetVersionCode()) { + APP_LOGE("fail to update lower version bundle"); + return ERR_APPEXECFWK_INSTALL_VERSION_DOWNGRADE; + } + + if (oldInfo.GetProvisionId() != newInfo.GetProvisionId()) { + APP_LOGE("the signature of the new bundle is not the same as old one"); + return ERR_APPEXECFWK_INSTALL_UPDATE_INCOMPATIBLE; + } + // now there are two cases for updating: + // 1. bundle exist, hap exist, update hap + // 2. bundle exist, install new hap + bool isModuleExist = oldInfo.FindModule(modulePackage_); + if (isModuleExist && !isReplace) { + APP_LOGE("fail to install already existing bundle using normal flag"); + return ERR_APPEXECFWK_INSTALL_ALREADY_EXIST; + } + if (!dataMgr_->UpdateBundleInstallState(bundleName_, InstallState::UPDATING_START)) { + APP_LOGE("update already start"); + return ERR_APPEXECFWK_INSTALL_STATE_ERROR; + } + // this state should always be set when return + ScopeGuard stateGuard([&] { dataMgr_->UpdateBundleInstallState(bundleName_, InstallState::INSTALL_SUCCESS); }); + newInfo.RestoreFromOldInfo(oldInfo); + ErrCode result = isModuleExist ? ProcessModuleUpdate(newInfo, oldInfo) : ProcessNewModuleInstall(newInfo, oldInfo); + if (result != ERR_OK) { + APP_LOGE("install module failed %{public}d", result); + return result; + } + + BundlePermissionMgr::UpdatePermissions(newInfo); + UpdateInstallerState(InstallerState::INSTALL_SUCCESS); + return ERR_OK; +} + +ErrCode BaseBundleInstaller::ProcessNewModuleInstall(InnerBundleInfo &newInfo, InnerBundleInfo &oldInfo) +{ + APP_LOGI("ProcessNewModuleInstall %{public}s", newInfo.GetBundleName().c_str()); + if (newInfo.HasEntry() && oldInfo.HasEntry()) { + APP_LOGE("install more than one entry module"); + return ERR_APPEXECFWK_INSTALL_ENTRY_ALREADY_EXIST; + } + ErrCode result = ExtractModuleAndRename(newInfo); + if (result != ERR_OK) { + APP_LOGE("extract module and rename failed"); + return result; + } + ScopeGuard moduleGuard([&] { RemoveModuleDir(newInfo); }); + result = CreateModuleDataDir(newInfo); + if (result != ERR_OK) { + APP_LOGE("create module data dir failed"); + return result; + } + ScopeGuard moduleDataGuard([&] { RemoveModuleDataDir(newInfo); }); + if (!dataMgr_->UpdateBundleInstallState(bundleName_, InstallState::UPDATING_SUCCESS)) { + APP_LOGE("new moduleupdate state failed"); + return ERR_APPEXECFWK_INSTALL_BUNDLE_MGR_SERVICE_ERROR; + } + if (!dataMgr_->AddNewModuleInfo(bundleName_, newInfo, oldInfo)) { + APP_LOGE( + "add module %{public}s to innerBundleInfo %{public}s failed", modulePackage_.c_str(), bundleName_.c_str()); + return ERR_APPEXECFWK_INSTALL_BUNDLE_MGR_SERVICE_ERROR; + } + moduleGuard.Dismiss(); + moduleDataGuard.Dismiss(); + return ERR_OK; +} + +ErrCode BaseBundleInstaller::ProcessModuleUpdate(InnerBundleInfo &newInfo, InnerBundleInfo &oldInfo) +{ + APP_LOGI("ProcessModuleUpdate %{public}s", newInfo.GetBundleName().c_str()); + // kill the bundle process during updating + if (!KillApplicationProcesses(oldInfo.GetApplicationName())) { + APP_LOGE("fail to kill running application"); + return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR; + } + ErrCode result = ExtractModuleAndRename(newInfo); + if (result != ERR_OK) { + APP_LOGE("extract module and rename failed"); + return result; + } + if (!dataMgr_->UpdateBundleInstallState(bundleName_, InstallState::UPDATING_SUCCESS)) { + APP_LOGE("old module update state failed"); + return ERR_APPEXECFWK_INSTALL_BUNDLE_MGR_SERVICE_ERROR; + } + newInfo.RestoreModuleInfo(oldInfo); + if (!dataMgr_->UpdateInnerBundleInfo(bundleName_, newInfo, oldInfo)) { + APP_LOGE("update innerBundleInfo %{public}s failed", bundleName_.c_str()); + return ERR_APPEXECFWK_INSTALL_BUNDLE_MGR_SERVICE_ERROR; + } + return ERR_OK; +} + +ErrCode BaseBundleInstaller::CreateBundleAndDataDir(InnerBundleInfo &info) const +{ + auto appCodePath = baseCodePath_ + Constants::PATH_SEPARATOR + bundleName_; + auto appDataPath = baseDataPath_ + Constants::PATH_SEPARATOR + bundleName_; + APP_LOGI("create bundle dir %{public}s", appCodePath.c_str()); + ErrCode result = InstalldClient::GetInstance()->CreateBundleDir(appCodePath); + if (result != ERR_OK) { + APP_LOGE("fail to create bundle dir, error is %{public}d", result); + return result; + } + info.SetAppCodePath(appCodePath); + + if (!dataMgr_->GenerateUidAndGid(info)) { + APP_LOGE("fail to gererate uid and gid"); + InstalldClient::GetInstance()->RemoveBundleDir(appCodePath); + return ERR_APPEXECFWK_INSTALL_GENERATE_UID_ERROR; + } + result = InstalldClient::GetInstance()->CreateBundleDataDir(appDataPath, info.GetUid(), info.GetGid()); + if (result != ERR_OK) { + APP_LOGE("fail to create bundle data dir, error is %{public}d", result); + InstalldClient::GetInstance()->RemoveBundleDir(appCodePath); + return result; + } + UpdateBundlePaths(info, appDataPath); + return ERR_OK; +} + +ErrCode BaseBundleInstaller::ExtractModuleAndRename(InnerBundleInfo &info) +{ + auto result = ExtractModuleFiles(info); + if (result != ERR_OK) { + APP_LOGE("fail to extrace module dir, error is %{public}d", result); + return result; + } + UpdateInstallerState(InstallerState::INSTALL_EXTRACTED); + result = RenameModuleDir(info); + if (result != ERR_OK) { + APP_LOGE("fail to rename module dir, error is %{public}d", result); + RemoveModuleDir(info); + return result; + } + UpdateInstallerState(InstallerState::INSTALL_RENAMED); + return ERR_OK; +} + +ErrCode BaseBundleInstaller::RemoveBundleAndDataDir(InnerBundleInfo &info, bool isUninstall) const +{ + auto result = InstalldClient::GetInstance()->RemoveBundleDir(info.GetAppCodePath()); + if (result != ERR_OK) { + APP_LOGE("fail to remove bundle dir, error is %{public}d", result); + return result; + } + if (!info.GetIsKeepData() || !isUninstall) { + result = InstalldClient::GetInstance()->RemoveBundleDataDir(info.GetBaseDataDir()); + if (result != ERR_OK) { + APP_LOGE("fail to remove bundle data dir, error is %{public}d", result); + return result; + } + } + return ERR_OK; +} + +ErrCode BaseBundleInstaller::RemoveModuleAndDataDir(InnerBundleInfo &info, const std::string &modulePackage) const +{ + auto moduleDir = info.GetModuleDir(modulePackage); + auto result = InstalldClient::GetInstance()->RemoveModuleDir(moduleDir); + if (result != ERR_OK) { + APP_LOGE("fail to remove module dir, error is %{public}d", result); + return result; + } + + if (!info.GetIsKeepData()) { + auto moduleDataDir = info.GetModuleDataDir(modulePackage); + result = InstalldClient::GetInstance()->RemoveModuleDataDir(moduleDataDir); + if (result != ERR_OK) { + APP_LOGE("fail to remove bundle data dir, error is %{public}d", result); + return result; + } + } + return ERR_OK; +} + +ErrCode BaseBundleInstaller::RemoveModuleDir(InnerBundleInfo &info) const +{ + std::string moduleDir = info.GetAppCodePath() + Constants::PATH_SEPARATOR + modulePackage_; + APP_LOGI("module dir %{public}s to be removed", moduleDir.c_str()); + return InstalldClient::GetInstance()->RemoveModuleDir(moduleDir); +} + +ErrCode BaseBundleInstaller::RemoveModuleDataDir(InnerBundleInfo &info) const +{ + return InstalldClient::GetInstance()->RemoveModuleDataDir(info.GetModuleDataDir(modulePackage_)); +} + +ErrCode BaseBundleInstaller::ParseBundleInfo(const std::string &bundleFilePath, InnerBundleInfo &info) const +{ + BundleParser bundleParser; + ErrCode result = bundleParser.Parse(bundleFilePath, info); + if (result != ERR_OK) { + APP_LOGE("parse bundle info failed, error: %{public}d", result); + return result; + } + return ERR_OK; +} + +ErrCode BaseBundleInstaller::ExtractModuleFiles(InnerBundleInfo &info) +{ + moduleTmpDir_ = info.GetAppCodePath() + Constants::PATH_SEPARATOR + modulePackage_ + Constants::TMP_SUFFIX; + APP_LOGI("extract module to %{public}s", moduleTmpDir_.c_str()); + auto result = InstalldClient::GetInstance()->ExtractModuleFiles(modulePath_, moduleTmpDir_); + if (result != ERR_OK) { + APP_LOGE("extract module files failed, error is %{public}d", result); + return result; + } + return ERR_OK; +} + +ErrCode BaseBundleInstaller::RenameModuleDir(InnerBundleInfo &info) const +{ + auto moduleDir = info.GetAppCodePath() + Constants::PATH_SEPARATOR + modulePackage_; + APP_LOGI("rename module to %{public}s", moduleDir.c_str()); + auto result = InstalldClient::GetInstance()->RenameModuleDir(moduleTmpDir_, moduleDir); + if (result != ERR_OK) { + APP_LOGE("rename module dir failed, error is %{public}d", result); + return result; + } + info.AddModuleSrcDir(moduleDir); + info.AddModuleResPath(moduleDir); + return ERR_OK; +} + +ErrCode BaseBundleInstaller::CreateModuleDataDir(InnerBundleInfo &info) const +{ + auto moduleDataDir = info.GetBaseDataDir() + Constants::PATH_SEPARATOR + modulePackage_; + auto result = InstalldClient::GetInstance()->CreateModuleDataDir( + moduleDataDir, info.GetAbilityNames(), info.GetUid(), info.GetGid()); + if (result != ERR_OK) { + APP_LOGE("create module data dir failed, error is %{public}d", result); + return result; + } + info.AddModuleDataDir(moduleDataDir); + return ERR_OK; +} + +bool BaseBundleInstaller::ModifyInstallDirByHapType(InnerBundleInfo &info) +{ + auto internalPath = Constants::PATH_SEPARATOR + Constants::USER_ACCOUNT_DIR + Constants::FILE_UNDERLINE + + std::to_string(info.GetUserId()) + Constants::PATH_SEPARATOR; + switch (info.GetAppType()) { + case Constants::AppType::SYSTEM_APP: + baseCodePath_ = Constants::SYSTEM_APP_INSTALL_PATH + internalPath + Constants::APP_CODE_DIR; + baseDataPath_ = Constants::SYSTEM_APP_INSTALL_PATH + internalPath + Constants::APP_DATA_DIR; + break; + case Constants::AppType::THIRD_SYSTEM_APP: + baseCodePath_ = Constants::THIRD_SYSTEM_APP_INSTALL_PATH + internalPath + Constants::APP_CODE_DIR; + baseDataPath_ = Constants::THIRD_SYSTEM_APP_INSTALL_PATH + internalPath + Constants::APP_DATA_DIR; + break; + case Constants::AppType::THIRD_PARTY_APP: + baseCodePath_ = Constants::THIRD_PARTY_APP_INSTALL_PATH + internalPath + Constants::APP_CODE_DIR; + baseDataPath_ = Constants::THIRD_PARTY_APP_INSTALL_PATH + internalPath + Constants::APP_DATA_DIR; + break; + default: + APP_LOGE("App type error"); + return false; + } + return true; +} + +bool BaseBundleInstaller::UpdateBundlePaths(InnerBundleInfo &info, const std::string baseDataPath) const +{ + info.SetBaseDataDir(baseDataPath); + info.SetAppDataDir(baseDataPath + Constants::PATH_SEPARATOR + Constants::DATA_DIR); + info.SetAppDataBaseDir(baseDataPath + Constants::PATH_SEPARATOR + Constants::DATA_BASE_DIR); + info.SetAppCacheDir(baseDataPath + Constants::PATH_SEPARATOR + Constants::CACHE_DIR); + return true; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/bundlemgr/src/base_extractor.cpp b/services/bundlemgr/src/base_extractor.cpp new file mode 100644 index 000000000..be1e5bb83 --- /dev/null +++ b/services/bundlemgr/src/base_extractor.cpp @@ -0,0 +1,95 @@ +/* + * 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 "base_extractor.h" + +#include +#include + +#include "string_ex.h" +#include "app_log_wrapper.h" +#include "bundle_constants.h" + +namespace OHOS { +namespace AppExecFwk { + +BaseExtractor::BaseExtractor(const std::string &source) : sourceFile_(source), zipFile_(source) +{ + APP_LOGI("BaseExtractor instance is created"); +} + +BaseExtractor::~BaseExtractor() +{ + APP_LOGI("BaseExtractor instance is destroyed"); +} + +bool BaseExtractor::Init() +{ + if (!zipFile_.Open()) { + APP_LOGE("open zip file failed"); + return false; + } + initial_ = true; + APP_LOGI("success"); + return true; +} + +bool BaseExtractor::ExtractByName(const std::string &fileName, std::ostream &dest) const +{ + if (!initial_) { + APP_LOGE("extractor is not initial"); + return false; + } + if (!zipFile_.ExtractFile(fileName, dest)) { + APP_LOGE("extractor is not ExtractFile"); + return false; + } + return true; +} + +bool BaseExtractor::ExtractFile(const std::string &fileName, const std::string &targetPath) const +{ + APP_LOGD("begin to extract %{public}s file into %{public}s targetPath", fileName.c_str(), targetPath.c_str()); + std::ofstream fileStream; + fileStream.open(targetPath, std::ios_base::out | std::ios_base::binary); + if (!fileStream.is_open()) { + APP_LOGE("fail to open %{public}s file to write", targetPath.c_str()); + return false; + } + if ((!ExtractByName(fileName, fileStream)) || (!fileStream.good())) { + APP_LOGE("fail to extract %{public}s zip file into stream", fileName.c_str()); + fileStream.clear(); + fileStream.close(); + if (remove(targetPath.c_str()) != 0) { + APP_LOGE("fail to remove %{private}s file which writes stream error", targetPath.c_str()); + } + return false; + } + fileStream.clear(); + fileStream.close(); + return true; +} + +bool BaseExtractor::GetZipFileNames(std::vector &fileNames) +{ + auto &entryMap = zipFile_.GetAllEntries(); + for (auto &entry : entryMap) { + fileNames.emplace_back(entry.first); + } + return true; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/bundlemgr/src/bundle_data_mgr.cpp b/services/bundlemgr/src/bundle_data_mgr.cpp new file mode 100755 index 000000000..e6460064d --- /dev/null +++ b/services/bundlemgr/src/bundle_data_mgr.cpp @@ -0,0 +1,1084 @@ +/* + * 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_data_mgr.h" + +#include + +#include "nlohmann/json.hpp" +#include "app_log_wrapper.h" +#include "permission/permission_kit.h" +#include "bundle_constants.h" +#include "bundle_data_storage.h" +#include "json_serializer.h" +#include "common_event_manager.h" +#include "common_event_support.h" +#include "bundle_status_callback_death_recipient.h" + +namespace OHOS { +namespace AppExecFwk { + +BundleDataMgr::BundleDataMgr() +{ + InitStateTransferMap(); + if (!dataStorage_) { + dataStorage_ = std::make_shared(); + } + APP_LOGI("BundleDataMgr instance is created"); +} + +BundleDataMgr::~BundleDataMgr() +{ + APP_LOGI("BundleDataMgr instance is destroyed"); + installStates_.clear(); + transferStates_.clear(); + bundleInfos_.clear(); +} + +bool BundleDataMgr::LoadDataFromPersistentStorage() +{ + std::lock_guard lock(bundleInfoMutex_); + bool ret = dataStorage_->LoadAllData(bundleInfos_); + if (ret) { + if (bundleInfos_.empty()) { + APP_LOGW("persistent data is empty"); + return false; + } + for (const auto &item : bundleInfos_) { + std::lock_guard lock(stateMutex_); + installStates_.emplace(item.first, InstallState::INSTALL_SUCCESS); + } + RestoreUidAndGid(); + allInstallFlag_ = true; + } + return ret; +} + +bool BundleDataMgr::UpdateBundleInstallState(const std::string &bundleName, const InstallState state) +{ + if (bundleName.empty()) { + APP_LOGW("update result:fail, reason:bundle name is empty"); + return false; + } + + std::lock_guard lock(stateMutex_); + auto item = installStates_.find(bundleName); + if (item == installStates_.end()) { + if (state == InstallState::INSTALL_START) { + installStates_.emplace(bundleName, state); + APP_LOGD("update result:success, state:INSTALL_START"); + return true; + } + APP_LOGW("update result:fail, reason:incorrect state"); + return false; + } + + auto stateRange = transferStates_.equal_range(state); + for (auto previousState = stateRange.first; previousState != stateRange.second; ++previousState) { + if (item->second == previousState->second) { + APP_LOGI("update result:success, current:%{public}d, state:%{public}d", previousState->second, state); + if (IsDeleteDataState(state)) { + installStates_.erase(item); + DeleteBundleInfo(bundleName, state); + return true; + } + item->second = state; + return true; + } + } + APP_LOGW("update result:fail, reason:incorrect current:%{public}d, state:%{public}d", item->second, state); + return false; +} + +bool BundleDataMgr::AddInnerBundleInfo(const std::string &bundleName, InnerBundleInfo &info) +{ + APP_LOGI("to save info:%{public}s", info.GetBundleName().c_str()); + if (bundleName.empty()) { + APP_LOGW("save info fail, empty bundle name"); + return false; + } + + std::lock_guard lock(bundleInfoMutex_); + auto infoItem = bundleInfos_.find(bundleName); + if (infoItem != bundleInfos_.end()) { + APP_LOGE("bundle info already exist"); + return false; + } + std::lock_guard stateLock(stateMutex_); + auto statusItem = installStates_.find(bundleName); + if (statusItem == installStates_.end()) { + APP_LOGE("save info fail, app:%{public}s is not installed", bundleName.c_str()); + return false; + } + if (statusItem->second == InstallState::INSTALL_SUCCESS) { + APP_LOGI("save bundle:%{public}s info", bundleName.c_str()); + int64_t time = + std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) + .count(); + #if __WORDSIZE == 64 + APP_LOGI("the bundle install time is %{public}ld", time); + #else + APP_LOGI("the bundle install time is %{public}lld", time); + #endif + info.SetBundleInstallTime(time); + if (dataStorage_->SaveStorageBundleInfo(Constants::CURRENT_DEVICE_ID, info)) { + APP_LOGI("write storage success bundle:%{public}s", bundleName.c_str()); + std::map infoWithId; + infoWithId.emplace(Constants::CURRENT_DEVICE_ID, info); + bundleInfos_.emplace(bundleName, infoWithId); + return true; + } + } + return false; +} + +bool BundleDataMgr::AddNewModuleInfo( + const std::string &bundleName, const InnerBundleInfo &newInfo, InnerBundleInfo &oldInfo) +{ + APP_LOGI("add new module info:%{public}s", bundleName.c_str()); + std::lock_guard lock(bundleInfoMutex_); + auto infoItem = bundleInfos_.find(bundleName); + if (infoItem == bundleInfos_.end()) { + APP_LOGE("bundle info not exist"); + return false; + } + std::lock_guard stateLock(stateMutex_); + auto statusItem = installStates_.find(bundleName); + if (statusItem == installStates_.end()) { + APP_LOGE("save info fail, app:%{public}s is not updated", bundleName.c_str()); + return false; + } + if (statusItem->second == InstallState::UPDATING_SUCCESS) { + APP_LOGI("save bundle:%{public}s info", bundleName.c_str()); + int64_t time = + std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) + .count(); + #if __WORDSIZE == 64 + APP_LOGI("the bundle update time is %{public}ld", time); + #else + APP_LOGI("the bundle update time is %{public}lld", time); + #endif + oldInfo.SetBundleUpdateTime(time); + oldInfo.UpdateVersionInfo(newInfo); + oldInfo.AddModuleInfo(newInfo); + oldInfo.SetBundleStatus(InnerBundleInfo::BundleStatus::ENABLED); + if (dataStorage_->DeleteStorageBundleInfo(Constants::CURRENT_DEVICE_ID, oldInfo)) { + if (dataStorage_->SaveStorageBundleInfo(Constants::CURRENT_DEVICE_ID, oldInfo)) { + APP_LOGI("update storage success bundle:%{public}s", bundleName.c_str()); + bundleInfos_.at(bundleName).at(Constants::CURRENT_DEVICE_ID) = oldInfo; + return true; + } + } + } + return false; +} + +bool BundleDataMgr::RemoveModuleInfo( + const std::string &bundleName, const std::string &modulePackage, InnerBundleInfo &oldInfo) +{ + APP_LOGI("remove module info:%{public}s/%{public}s", bundleName.c_str(), modulePackage.c_str()); + std::lock_guard lock(bundleInfoMutex_); + auto infoItem = bundleInfos_.find(bundleName); + if (infoItem == bundleInfos_.end()) { + APP_LOGE("bundle info not exist"); + return false; + } + std::lock_guard stateLock(stateMutex_); + auto statusItem = installStates_.find(bundleName); + if (statusItem == installStates_.end()) { + APP_LOGE("save info fail, app:%{public}s is not updated", bundleName.c_str()); + return false; + } + if (statusItem->second == InstallState::UNINSTALL_START) { + APP_LOGI("save bundle:%{public}s info", bundleName.c_str()); + oldInfo.RemoveModuleInfo(modulePackage); + oldInfo.SetBundleStatus(InnerBundleInfo::BundleStatus::ENABLED); + if (dataStorage_->DeleteStorageBundleInfo(Constants::CURRENT_DEVICE_ID, oldInfo)) { + if (dataStorage_->SaveStorageBundleInfo(Constants::CURRENT_DEVICE_ID, oldInfo)) { + APP_LOGI("update storage success bundle:%{public}s", bundleName.c_str()); + bundleInfos_.at(bundleName).at(Constants::CURRENT_DEVICE_ID) = oldInfo; + return true; + } + } + APP_LOGI("after delete modulePackage:%{public}s info", modulePackage.c_str()); + } + return true; +} + +bool BundleDataMgr::UpdateInnerBundleInfo( + const std::string &bundleName, const InnerBundleInfo &newInfo, InnerBundleInfo &oldInfo) +{ + APP_LOGI("update module info:%{public}s", bundleName.c_str()); + std::lock_guard lock(bundleInfoMutex_); + auto infoItem = bundleInfos_.find(bundleName); + if (infoItem == bundleInfos_.end()) { + APP_LOGE("bundle info not exist"); + return false; + } + std::lock_guard stateLock(stateMutex_); + auto statusItem = installStates_.find(bundleName); + if (statusItem == installStates_.end()) { + APP_LOGE("save info fail, app:%{public}s is not updated", bundleName.c_str()); + return false; + } + if (statusItem->second == InstallState::UPDATING_SUCCESS) { + APP_LOGI("save bundle:%{public}s info", bundleName.c_str()); + int64_t time = + std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) + .count(); + #if __WORDSIZE == 64 + APP_LOGI("the bundle update time is %{public}ld", time); + #else + APP_LOGI("the bundle update time is %{public}lld", time); + #endif + oldInfo.SetBundleUpdateTime(time); + oldInfo.UpdateVersionInfo(newInfo); + oldInfo.UpdateModuleInfo(newInfo); + oldInfo.SetBundleStatus(InnerBundleInfo::BundleStatus::ENABLED); + if (dataStorage_->DeleteStorageBundleInfo(Constants::CURRENT_DEVICE_ID, oldInfo)) { + if (dataStorage_->SaveStorageBundleInfo(Constants::CURRENT_DEVICE_ID, oldInfo)) { + APP_LOGI("update storage success bundle:%{public}s", bundleName.c_str()); + bundleInfos_.at(bundleName).at(Constants::CURRENT_DEVICE_ID) = oldInfo; + return true; + } + } + } + return false; +} + +bool BundleDataMgr::QueryAbilityInfo(const Want &want, AbilityInfo &abilityInfo) const +{ + // for launcher + if (want.HasEntity(Want::FLAG_HW_HOME_INTENT_FROM_SYSTEM)) { + std::lock_guard lock(bundleInfoMutex_); + for (const auto &item : bundleInfos_) { + for (const auto &info : item.second) { + if (allInstallFlag_ && info.second.GetIsLauncherApp()) { + APP_LOGI("find launcher app %{public}s", info.second.GetBundleName().c_str()); + info.second.GetMainAbilityInfo(abilityInfo); + info.second.GetApplicationInfo( + ApplicationFlag::GET_APPLICATION_INFO_WITH_PERMS, 0, abilityInfo.applicationInfo); + return true; + } + } + } + return false; + } + + 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()); + if (bundleName.empty() || abilityName.empty()) { + APP_LOGW("Want error, bundleName or abilityName empty"); + return false; + } + + 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.FindAbilityInfo(bundleName, abilityName); + if (!ability) { + APP_LOGE("ability:%{public}s not find", keyName.c_str()); + return false; + } + abilityInfo = (*ability); + infoWithIdItem->second.GetApplicationInfo( + ApplicationFlag::GET_APPLICATION_INFO_WITH_PERMS, 0, abilityInfo.applicationInfo); + return true; +} + +bool BundleDataMgr::QueryAbilityInfoByUri(const std::string &abilityUri, AbilityInfo &abilityInfo) const +{ + APP_LOGI("QueryAbilityInfoByUri"); + if (abilityUri.empty()) { + return false; + } + std::lock_guard lock(bundleInfoMutex_); + if (bundleInfos_.empty()) { + APP_LOGI("bundleInfos_ data is empty"); + return false; + } + 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; + } + } + return false; +} + +bool BundleDataMgr::GetApplicationInfo( + const std::string &appName, const ApplicationFlag flag, const int userId, ApplicationInfo &appInfo) const +{ + APP_LOGI("GetApplicationInfo %{public}s", appName.c_str()); + if (appName.empty()) { + return false; + } + std::lock_guard lock(bundleInfoMutex_); + if (bundleInfos_.empty()) { + APP_LOGI("bundleInfos_ data is empty"); + return false; + } + APP_LOGI("GetApplicationInfo %{public}s", appName.c_str()); + auto infoItem = bundleInfos_.find(appName); + if (infoItem == bundleInfos_.end()) { + return false; + } + APP_LOGI("GetApplicationInfo %{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; + } + bundleInfo->second.GetApplicationInfo(flag, userId, appInfo); + return true; +} + +bool BundleDataMgr::GetApplicationInfos( + const ApplicationFlag flag, const int userId, std::vector &appInfos) const +{ + std::lock_guard lock(bundleInfoMutex_); + if (bundleInfos_.empty()) { + APP_LOGI("bundleInfos_ data is empty"); + return false; + } + bool find = false; + 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; + } + ApplicationInfo appInfo; + info.second.GetApplicationInfo(flag, userId, appInfo); + appInfos.emplace_back(appInfo); + find = true; + } + } + APP_LOGI("get installed bundles success"); + return find; +} + +bool BundleDataMgr::GetBundleInfo(const std::string &bundleName, const BundleFlag flag, BundleInfo &bundleInfo) const +{ + if (bundleName.empty()) { + APP_LOGW("bundle name is empty"); + return false; + } + + std::lock_guard lock(bundleInfoMutex_); + if (bundleInfos_.empty()) { + APP_LOGI("bundleInfos_ data is empty"); + return false; + } + APP_LOGI("GetBundleInfo %{public}s", bundleName.c_str()); + auto infoItem = bundleInfos_.find(bundleName); + if (infoItem == bundleInfos_.end()) { + return false; + } + APP_LOGI("GetBundleInfo %{public}s", infoItem->first.c_str()); + auto innerBundleInfo = infoItem->second.find(Constants::CURRENT_DEVICE_ID); + if (innerBundleInfo == infoItem->second.end()) { + return false; + } + if (innerBundleInfo->second.IsDisabled()) { + APP_LOGI("app %{public}s is disabled", innerBundleInfo->second.GetBundleName().c_str()); + return false; + } + innerBundleInfo->second.GetBundleInfo(flag, bundleInfo); + APP_LOGI("bundle:%{public}s device id find success", bundleName.c_str()); + return true; +} + +bool BundleDataMgr::GetBundleInfosByMetaData(const std::string &metaData, std::vector &bundleInfos) const +{ + if (metaData.empty()) { + APP_LOGW("bundle name is empty"); + return false; + } + + std::lock_guard lock(bundleInfoMutex_); + if (bundleInfos_.empty()) { + APP_LOGI("bundleInfos_ data is empty"); + return false; + } + bool find = false; + 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; + } + if (info.second.CheckSpecialMetaData(metaData)) { + BundleInfo bundleInfo; + info.second.GetBundleInfo(BundleFlag::GET_BUNDLE_WITH_ABILITIES, bundleInfo); + bundleInfos.emplace_back(bundleInfo); + find = true; + } + } + } + return find; +} + +bool BundleDataMgr::GetBundleList(std::vector &bundleNames) const +{ + std::lock_guard lock(bundleInfoMutex_); + if (bundleInfos_.empty()) { + APP_LOGI("bundleInfos_ data is empty"); + return false; + } + bool find = false; + for (const auto &item : bundleInfos_) { + bundleNames.emplace_back(item.first); + find = true; + } + APP_LOGI("get installed bundles success"); + return find; +} + +bool BundleDataMgr::GetBundleInfos(const BundleFlag flag, std::vector &bundleInfos) const +{ + std::lock_guard lock(bundleInfoMutex_); + if (bundleInfos_.empty()) { + APP_LOGI("bundleInfos_ data is empty"); + return false; + } + bool find = false; + for (const auto &item : bundleInfos_) { + std::map infoWithId = item.second; + auto infoWithIdItem = infoWithId.find(Constants::CURRENT_DEVICE_ID); + if (infoWithIdItem == infoWithId.end()) { + APP_LOGI("current device id bundle not find"); + continue; + } + if (infoWithIdItem->second.IsDisabled()) { + APP_LOGI("app %{public}s is disabled", infoWithIdItem->second.GetBundleName().c_str()); + continue; + } + BundleInfo bundleInfo; + infoWithIdItem->second.GetBundleInfo(flag, bundleInfo); + bundleInfos.emplace_back(bundleInfo); + find = true; + } + APP_LOGI("get installed bundle infos success"); + return find; +} + +bool BundleDataMgr::GetBundleNameForUid(const int uid, std::string &bundleName) const +{ + std::lock_guard lock(bundleInfoMutex_); + if (bundleInfos_.empty()) { + APP_LOGI("bundleInfos_ data is empty"); + return false; + } + 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; + } + if (info.second.GetUid() == uid) { + bundleName = info.second.GetBundleName(); + return true; + } + } + } + return false; +} + +bool BundleDataMgr::GetBundleGids(const std::string &bundleName, std::vector &gids) const +{ + return true; +} + +bool BundleDataMgr::QueryKeepAliveBundleInfos(std::vector &bundleInfos) const +{ + std::lock_guard lock(bundleInfoMutex_); + if (bundleInfos_.empty()) { + APP_LOGI("bundleInfos_ data is empty"); + return false; + } + 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; + } + if (info.second.GetIsKeepAlive()) { + BundleInfo bundleInfo; + info.second.GetBundleInfo(BundleFlag::GET_BUNDLE_WITH_ABILITIES, bundleInfo); + bundleInfos.emplace_back(bundleInfo); + } + } + } + return !(bundleInfos.empty()); +} + +std::string BundleDataMgr::GetAbilityLabel(const std::string &bundleName, const std::string &className) const +{ + std::lock_guard lock(bundleInfoMutex_); + if (bundleInfos_.empty()) { + APP_LOGI("bundleInfos_ data is empty"); + return Constants::EMPTY_STRING; + } + APP_LOGI("GetAbilityLabel %{public}s", bundleName.c_str()); + auto infoItem = bundleInfos_.find(bundleName); + if (infoItem == bundleInfos_.end()) { + return Constants::EMPTY_STRING; + } + auto innerBundleInfo = infoItem->second.find(Constants::CURRENT_DEVICE_ID); + if (innerBundleInfo == infoItem->second.end()) { + return Constants::EMPTY_STRING; + } + if (innerBundleInfo->second.IsDisabled()) { + APP_LOGI("app %{public}s is disabled", innerBundleInfo->second.GetBundleName().c_str()); + return Constants::EMPTY_STRING; + } + auto ability = innerBundleInfo->second.FindAbilityInfo(bundleName, className); + if (!ability) { + return Constants::EMPTY_STRING; + } + return (*ability).label; +} + +bool BundleDataMgr::GetHapModuleInfo(const AbilityInfo &abilityInfo, HapModuleInfo &hapModuleInfo) const +{ + std::lock_guard lock(bundleInfoMutex_); + if (bundleInfos_.empty()) { + APP_LOGI("bundleInfos_ data is empty"); + return false; + } + APP_LOGI("GetHapModuleInfo %{public}s", abilityInfo.bundleName.c_str()); + auto infoItem = bundleInfos_.find(abilityInfo.bundleName); + if (infoItem == bundleInfos_.end()) { + return false; + } + auto innerBundleInfo = infoItem->second.find(Constants::CURRENT_DEVICE_ID); + if (innerBundleInfo == infoItem->second.end()) { + return false; + } + if (innerBundleInfo->second.IsDisabled()) { + APP_LOGI("app %{public}s is disabled", innerBundleInfo->second.GetBundleName().c_str()); + return false; + } + auto module = innerBundleInfo->second.FindHapModuleInfo(abilityInfo.package); + if (!module) { + APP_LOGE("can not find module %{public}s", abilityInfo.package.c_str()); + return false; + } + hapModuleInfo = *module; + return true; +} + +bool BundleDataMgr::GetLaunchWantForBundle(const std::string &bundleName, Want &want) const +{ + std::lock_guard lock(bundleInfoMutex_); + if (bundleInfos_.empty()) { + APP_LOGI("bundleInfos_ data is empty"); + return false; + } + APP_LOGI("GetLaunchWantForBundle %{public}s", bundleName.c_str()); + auto infoItem = bundleInfos_.find(bundleName); + if (infoItem == bundleInfos_.end()) { + return false; + } + auto innerBundleInfo = infoItem->second.find(Constants::CURRENT_DEVICE_ID); + if (innerBundleInfo == infoItem->second.end()) { + return false; + } + if (innerBundleInfo->second.IsDisabled()) { + APP_LOGI("app %{public}s is disabled", innerBundleInfo->second.GetBundleName().c_str()); + return false; + } + std::string mainAbility = innerBundleInfo->second.GetMainAbility(); + if (mainAbility.empty()) { + APP_LOGE("no main ability in the bundle %{public}s", bundleName.c_str()); + return false; + } + auto skills = innerBundleInfo->second.FindSkills(mainAbility); + if (!skills || (*skills).empty()) { + APP_LOGE("no skills of %{public}s", mainAbility.c_str()); + return false; + } + + want.SetElementName(Constants::CURRENT_DEVICE_ID, bundleName, mainAbility); + want.SetAction((*skills)[0].actions[0]); + for (auto &skill : (*skills)) { + for (auto &entity : skill.entities) { + want.AddEntity(entity); + } + } + return true; +} + +bool BundleDataMgr::CheckIsSystemAppByUid(const int uid) const +{ + int maxSysUid{Constants::MAX_SYS_UID}; + int baseSysUid{Constants::ROOT_UID}; + if (uid >= baseSysUid && uid <= maxSysUid) { + return true; + } + return false; +} + +void BundleDataMgr::InitStateTransferMap() +{ + transferStates_.emplace(InstallState::INSTALL_SUCCESS, InstallState::INSTALL_START); + transferStates_.emplace(InstallState::INSTALL_FAIL, InstallState::INSTALL_START); + transferStates_.emplace(InstallState::UNINSTALL_START, InstallState::INSTALL_SUCCESS); + transferStates_.emplace(InstallState::UNINSTALL_FAIL, InstallState::UNINSTALL_START); + transferStates_.emplace(InstallState::UNINSTALL_SUCCESS, InstallState::UNINSTALL_START); + transferStates_.emplace(InstallState::UPDATING_START, InstallState::INSTALL_SUCCESS); + transferStates_.emplace(InstallState::UPDATING_SUCCESS, InstallState::UPDATING_START); + transferStates_.emplace(InstallState::UPDATING_FAIL, InstallState::UPDATING_START); + transferStates_.emplace(InstallState::INSTALL_SUCCESS, InstallState::UPDATING_START); + transferStates_.emplace(InstallState::INSTALL_SUCCESS, InstallState::UPDATING_SUCCESS); + transferStates_.emplace(InstallState::INSTALL_SUCCESS, InstallState::UNINSTALL_START); +} + +bool BundleDataMgr::IsDeleteDataState(const InstallState state) const +{ + return (state == InstallState::INSTALL_FAIL || state == InstallState::UNINSTALL_FAIL || + state == InstallState::UNINSTALL_SUCCESS || state == InstallState::UPDATING_FAIL); +} + +bool BundleDataMgr::IsDisableState(const InstallState state) const +{ + if (state == InstallState::UPDATING_START || state == InstallState::UNINSTALL_START) { + return true; + } + return false; +} + +void BundleDataMgr::DeleteBundleInfo(const std::string &bundleName, const InstallState state) +{ + if (InstallState::INSTALL_FAIL == state) { + APP_LOGW("del fail, bundle:%{public}s has no installed info", bundleName.c_str()); + return; + } + + std::lock_guard lock(bundleInfoMutex_); + auto infoItem = bundleInfos_.find(bundleName); + if (infoItem != bundleInfos_.end()) { + APP_LOGI("del bundle name:%{public}s", bundleName.c_str()); + const InnerBundleInfo &innerBundleInfo = infoItem->second[Constants::CURRENT_DEVICE_ID]; + RecycleUidAndGid(innerBundleInfo); + bool ret = dataStorage_->DeleteStorageBundleInfo(Constants::CURRENT_DEVICE_ID, innerBundleInfo); + if (!ret) { + APP_LOGW("delete storage error name:%{public}s", bundleName.c_str()); + } + // only delete self-device bundle + infoItem->second.erase(Constants::CURRENT_DEVICE_ID); + if (infoItem->second.empty()) { + APP_LOGD("now only store current device installed info, delete all"); + bundleInfos_.erase(bundleName); + } + } +} + +bool BundleDataMgr::IsAppOrAbilityInstalled(const std::string &bundleName) const +{ + if (bundleName.empty()) { + APP_LOGW("name:%{public}s empty", bundleName.c_str()); + return false; + } + + std::lock_guard lock(stateMutex_); + auto statusItem = installStates_.find(bundleName); + if (statusItem == installStates_.end()) { + APP_LOGW("name:%{public}s not find", bundleName.c_str()); + return false; + } + + if (statusItem->second == InstallState::INSTALL_SUCCESS) { + return true; + } + + APP_LOGW("name:%{public}s not install success", bundleName.c_str()); + return false; +} + +bool BundleDataMgr::GetInnerBundleInfo( + const std::string &bundleName, const std::string &deviceId, InnerBundleInfo &info) +{ + APP_LOGI("GetInnerBundleInfo %{public}s", bundleName.c_str()); + if (bundleName.empty() || deviceId.empty()) { + APP_LOGE("bundleName or deviceId empty"); + return false; + } + + std::lock_guard lock(bundleInfoMutex_); + auto infoItem = bundleInfos_.find(bundleName); + if (infoItem == bundleInfos_.end()) { + APP_LOGE("can not find bundle %{public}s", bundleName.c_str()); + return false; + } + auto infoWithIdItem = infoItem->second.find(deviceId); + if (infoWithIdItem == infoItem->second.end()) { + APP_LOGE("bundle:%{public}s device id not find", bundleName.c_str()); + return false; + } + infoWithIdItem->second.SetBundleStatus(InnerBundleInfo::BundleStatus::DISABLED); + info = infoWithIdItem->second; + return true; +} + +bool BundleDataMgr::DisableBundle(const std::string &bundleName) +{ + APP_LOGI("DisableBundle %{public}s", bundleName.c_str()); + if (bundleName.empty()) { + APP_LOGE("bundleName empty"); + return false; + } + + std::lock_guard lock(bundleInfoMutex_); + auto infoItem = bundleInfos_.find(bundleName); + if (infoItem == bundleInfos_.end()) { + APP_LOGE("can not find bundle %{public}s", bundleName.c_str()); + return false; + } + auto infoWithIdItem = infoItem->second.find(Constants::CURRENT_DEVICE_ID); + if (infoWithIdItem == infoItem->second.end()) { + APP_LOGE("bundle:%{public}s device id not find", bundleName.c_str()); + return false; + } + infoWithIdItem->second.SetBundleStatus(InnerBundleInfo::BundleStatus::DISABLED); + return true; +} + +bool BundleDataMgr::EnableBundle(const std::string &bundleName) +{ + APP_LOGI("EnableBundle %{public}s", bundleName.c_str()); + if (bundleName.empty()) { + APP_LOGE("bundleName empty"); + return false; + } + + std::lock_guard lock(bundleInfoMutex_); + auto infoItem = bundleInfos_.find(bundleName); + if (infoItem == bundleInfos_.end()) { + APP_LOGE("can not find bundle %{public}s", bundleName.c_str()); + return false; + } + auto infoWithIdItem = infoItem->second.find(Constants::CURRENT_DEVICE_ID); + if (infoWithIdItem == infoItem->second.end()) { + APP_LOGE("bundle:%{public}s device id not find", bundleName.c_str()); + return false; + } + infoWithIdItem->second.SetBundleStatus(InnerBundleInfo::BundleStatus::ENABLED); + return true; +} + +bool BundleDataMgr::IsApplicationEnabled(const std::string &bundleName) const +{ + APP_LOGI("IsApplicationEnabled %{public}s", bundleName.c_str()); + if (bundleName.empty()) { + APP_LOGE("bundleName empty"); + return false; + } + + std::lock_guard lock(bundleInfoMutex_); + auto infoItem = bundleInfos_.find(bundleName); + if (infoItem == bundleInfos_.end()) { + APP_LOGE("can not find bundle %{public}s", bundleName.c_str()); + return false; + } + auto infoWithIdItem = infoItem->second.find(Constants::CURRENT_DEVICE_ID); + if (infoWithIdItem == infoItem->second.end()) { + APP_LOGE("bundle:%{public}s device id not find", bundleName.c_str()); + return false; + } + return (infoWithIdItem->second.GetBundleStatus() == InnerBundleInfo::BundleStatus::ENABLED) ? true : false; +} + +bool BundleDataMgr::SetApplicationEnabled(const std::string &bundleName, bool isEnable) +{ + APP_LOGI("SetApplicationEnabled %{public}s", bundleName.c_str()); + if (bundleName.empty()) { + APP_LOGE("bundleName empty"); + return false; + } + return isEnable ? EnableBundle(bundleName) : DisableBundle(bundleName); +} + +bool BundleDataMgr::RegisterBundleStatusCallback(const sptr &bundleStatusCallback) +{ + APP_LOGI("RegisterBundleStatusCallback %{public}s", bundleStatusCallback->GetBundleName().c_str()); + std::lock_guard lock(callbackMutex_); + callbackList_.emplace_back(bundleStatusCallback); + if (bundleStatusCallback->AsObject() != nullptr) { + sptr deathRecipient = new BundleStatusCallbackDeathRecipient(); + bundleStatusCallback->AsObject()->AddDeathRecipient(deathRecipient); + } + return true; +} + +bool BundleDataMgr::ClearBundleStatusCallback(const sptr &bundleStatusCallback) +{ + APP_LOGI("ClearBundleStatusCallback %{public}s", bundleStatusCallback->GetBundleName().c_str()); + std::lock_guard lock(callbackMutex_); + callbackList_.erase(std::remove_if(callbackList_.begin(), + callbackList_.end(), + [&](const sptr &callback) { + return callback->AsObject() == bundleStatusCallback->AsObject(); + }), + callbackList_.end()); + return true; +} + +bool BundleDataMgr::UnregisterBundleStatusCallback() +{ + std::lock_guard lock(callbackMutex_); + callbackList_.clear(); + return true; +} + +bool BundleDataMgr::GenerateUidAndGid(InnerBundleInfo &info) +{ + int baseUid; + std::map &innerMap = [&]() -> decltype(auto) { + switch (info.GetAppType()) { + case Constants::AppType::SYSTEM_APP: + baseUid = Constants::BASE_SYS_UID; + return (sysUidMap_); + case Constants::AppType::THIRD_SYSTEM_APP: + baseUid = Constants::BASE_SYS_VEN_UID; + return (sysVendorUidMap_); + case Constants::AppType::THIRD_PARTY_APP: + baseUid = Constants::BASE_APP_UID; + return (appUidMap_); + default: + APP_LOGE("app type error"); + baseUid = Constants::BASE_APP_UID; + return (appUidMap_); + } + }(); + std::lock_guard lock(uidMapMutex_); + if (innerMap.empty()) { + APP_LOGI("first app install"); + innerMap.emplace(0, info.GetBundleName()); + info.SetUid(baseUid); + info.SetGid(baseUid); + return true; + } + int uid = 0; + for (int i = 0; i < innerMap.rbegin()->first; ++i) { + if (innerMap.find(i) == innerMap.end()) { + APP_LOGI("the %{public}d app install", i); + innerMap.emplace(i, info.GetBundleName()); + uid = i + baseUid; + info.SetUid(baseUid); + info.SetGid(baseUid); + return true; + } + } + if ((info.GetAppType() == Constants::AppType::SYSTEM_APP) && (innerMap.rbegin()->first == Constants::MAX_SYS_UID)) { + return false; + } + if ((info.GetAppType() == Constants::AppType::THIRD_SYSTEM_APP) && + (innerMap.rbegin()->first == Constants::MAX_SYS_VEN_UID)) { + return false; + } + + innerMap.emplace((innerMap.rbegin()->first + 1), info.GetBundleName()); + uid = innerMap.rbegin()->first + baseUid; + APP_LOGI("the uid is %{public}d", uid); + info.SetUid(uid); + info.SetGid(uid); + return true; +} + +bool BundleDataMgr::RecycleUidAndGid(const InnerBundleInfo &info) +{ + std::map &innerMap = [&]() -> decltype(auto) { + switch (info.GetAppType()) { + case Constants::AppType::SYSTEM_APP: + return (sysUidMap_); + case Constants::AppType::THIRD_SYSTEM_APP: + return (sysVendorUidMap_); + case Constants::AppType::THIRD_PARTY_APP: + return (appUidMap_); + default: + APP_LOGE("app type error"); + return (appUidMap_); + } + }(); + for (auto &kv : innerMap) { + if (kv.second == info.GetBundleName()) { + innerMap.erase(kv.first); + return true; + } + } + return true; +} + +bool BundleDataMgr::RestoreUidAndGid() +{ + // this function should be called with bundleInfoMutex_ locked + for (const auto &item : bundleInfos_) { + for (const auto &info : item.second) { + uint32_t uid = info.second.GetUid(); + if ((uid < Constants::BASE_SYS_VEN_UID) && (uid >= Constants::BASE_SYS_UID)) { + sysUidMap_[uid - Constants::BASE_SYS_UID] = info.second.GetBundleName(); + } else if ((uid >= Constants::BASE_SYS_VEN_UID) && (uid <= Constants::MAX_SYS_VEN_UID)) { + sysVendorUidMap_[uid - Constants::BASE_SYS_VEN_UID] = info.second.GetBundleName(); + } else if (uid > Constants::MAX_SYS_VEN_UID) { + appUidMap_[uid - Constants::BASE_APP_UID] = info.second.GetBundleName(); + } + } + } + return true; +} + +bool BundleDataMgr::NotifyBundleStatus(const std::string &bundleName, const std::string &modulePackage, + const std::string &mainAbility, const ErrCode resultCode, const NotifyType type) +{ + APP_LOGI("notify type %{public}d with %{public}d for %{public}s-%{public}s in %{public}s", + type, + resultCode, + modulePackage.c_str(), + mainAbility.c_str(), + bundleName.c_str()); + uint8_t installType = [&]() -> uint8_t { + if ((type == NotifyType::UNINSTALL_BUNDLE) || (type == NotifyType::UNINSTALL_MODULE)) { + return static_cast(InstallType::UNINSTALL_CALLBACK); + } + return static_cast(InstallType::INSTALL_CALLBACK); + }(); + { + std::lock_guard lock(callbackMutex_); + for (const auto &callback : callbackList_) { + if (callback->GetBundleName() == bundleName) { + // if the msg needed, it could convert in the proxy node + callback->OnBundleStateChanged(installType, resultCode, Constants::EMPTY_STRING, bundleName); + } + } + } + + if (resultCode != ERR_OK) { + return true; + } + std::string eventData = [type]() -> std::string { + switch (type) { + case NotifyType::INSTALL: + return EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_ADDED; + case NotifyType::UNINSTALL_BUNDLE: + return EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_REMOVED; + case NotifyType::UNINSTALL_MODULE: + return EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_REMOVED; + case NotifyType::UPDATE: + return EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_CHANGED; + default: + APP_LOGE("event type error"); + return EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_CHANGED; + } + }(); + APP_LOGI("will send event data %{public}s", eventData.c_str()); + Want want; + want.SetAction(eventData); + ElementName element; + element.SetBundleName(bundleName); + element.SetAbilityName(mainAbility); + want.SetElement(element); + EventFwk::CommonEventData commonData{want}; + EventFwk::CommonEventManager::PublishCommonEvent(commonData); + return true; +} + +bool BundleDataMgr::GetProvisionId(const std::string &bundleName, std::string &provisionId) const +{ + APP_LOGI("GetProvisionId %{public}s", bundleName.c_str()); + if (bundleName.empty()) { + APP_LOGE("bundleName empty"); + return false; + } + std::lock_guard lock(bundleInfoMutex_); + auto infoItem = bundleInfos_.find(bundleName); + if (infoItem == bundleInfos_.end()) { + APP_LOGE("can not find bundle %{public}s", bundleName.c_str()); + return false; + } + auto infoWithIdItem = infoItem->second.find(Constants::CURRENT_DEVICE_ID); + if (infoWithIdItem == infoItem->second.end()) { + APP_LOGE("bundle:%{public}s device id not find", bundleName.c_str()); + return false; + } + provisionId = infoWithIdItem->second.GetProvisionId(); + return true; +} + +bool BundleDataMgr::GetAppFeature(const std::string &bundleName, std::string &appFeature) const +{ + APP_LOGI("GetAppFeature %{public}s", bundleName.c_str()); + if (bundleName.empty()) { + APP_LOGE("bundleName empty"); + return false; + } + std::lock_guard lock(bundleInfoMutex_); + auto infoItem = bundleInfos_.find(bundleName); + if (infoItem == bundleInfos_.end()) { + APP_LOGE("can not find bundle %{public}s", bundleName.c_str()); + return false; + } + auto infoWithIdItem = infoItem->second.find(Constants::CURRENT_DEVICE_ID); + if (infoWithIdItem == infoItem->second.end()) { + APP_LOGE("bundle:%{public}s device id not find", bundleName.c_str()); + return false; + } + appFeature = infoWithIdItem->second.GetAppFeature(); + return true; +} + +void BundleDataMgr::SetAllInstallFlag(bool flag) +{ + APP_LOGI("SetAllInstallFlag %{public}d", flag); + allInstallFlag_ = flag; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/bundlemgr/src/bundle_data_storage.cpp b/services/bundlemgr/src/bundle_data_storage.cpp new file mode 100644 index 000000000..91a8363a1 --- /dev/null +++ b/services/bundlemgr/src/bundle_data_storage.cpp @@ -0,0 +1,204 @@ +/* + * 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_data_storage.h" + +#include +#include + +#include "string_ex.h" +#include "app_log_wrapper.h" +#include "bundle_constants.h" +#include "bundle_profile.h" + +namespace OHOS { +namespace AppExecFwk { + +bool BundleDataStorage::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("bundleName = %{public}s", bundleName.c_str()); + return ret; +} + +void BundleDataStorage::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("bundleName = %{public}s", bundleName.c_str()); +} + +bool BundleDataStorage::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; +} + +bool BundleDataStorage::SaveStorageBundleInfo(const std::string &deviceId, const InnerBundleInfo &innerBundleInfo) const +{ + APP_LOGI("save bundle data"); + bool ret = true; + std::string appName = innerBundleInfo.GetApplicationName(); + std::fstream f(Constants::BUNDLE_DATA_BASE_FILE); + bool isExist = f.good(); + + if (isExist) { + nlohmann::json innerInfo; + innerBundleInfo.ToJson(innerInfo); + f.seekg(0, std::ios::end); + int len = static_cast(f.tellg()); + if (len == 0) { + nlohmann::json appRoot; + nlohmann::json app; + app[deviceId] = innerInfo; + appRoot[appName] = app; + f << std::setw(Constants::DUMP_INDENT) << appRoot << std::endl; + } else { + f.seekg(0, std::ios::beg); + nlohmann::json jsonFile; + f >> jsonFile; + if (jsonFile.find(appName) != jsonFile.end()) { + if (jsonFile[appName].find(deviceId) != jsonFile[appName].end()) { + // appName and device id is exist + APP_LOGE("appName = %{public}s is exist", appName.c_str()); + ret = false; + } else { + jsonFile[appName][deviceId] = innerInfo; + f.seekp(0, std::ios::beg); + f << std::setw(Constants::DUMP_INDENT) << jsonFile << std::endl; + } + } else { + nlohmann::json app; + app[deviceId] = innerInfo; + jsonFile[appName] = app; + f.seekp(0, std::ios::beg); + f << std::setw(Constants::DUMP_INDENT) << jsonFile << std::endl; + } + } + } else { + APP_LOGI("bundle database file not exist"); + ret = false; + } + f.close(); + return ret; +} + +bool BundleDataStorage::ModifyStorageBundleInfo( + const std::string &deviceId, const InnerBundleInfo &innerBundleInfo) const +{ + return true; +} + +bool BundleDataStorage::DeleteStorageBundleInfo( + const std::string &deviceId, const InnerBundleInfo &innerBundleInfo) const +{ + APP_LOGI("delete bundle data"); + bool ret = false; + bool isEmpty = false; + std::string appName = innerBundleInfo.GetApplicationName(); + std::ifstream i(Constants::BUNDLE_DATA_BASE_FILE); + nlohmann::json jParse; + if (!i.is_open()) { + APP_LOGE("failed to open bundle database file"); + return false; + } else { + i.seekg(0, std::ios::end); + int len = static_cast(i.tellg()); + if (len != 0) { + i.seekg(0, std::ios::beg); + i >> jParse; + if (jParse.find(appName) != jParse.end()) { + auto it = jParse[appName].find(deviceId); + if (it != jParse[appName].end()) { + jParse[appName].erase(it); + if (jParse[appName].size() == 0) { + jParse.erase(appName); + if (jParse.size() == 0) { + isEmpty = true; + } + } + ret = true; + } + } else { + APP_LOGE("not find appName = %{public}s", appName.c_str()); + } + } else { + APP_LOGE("file is empty appName = %{private}s", appName.c_str()); + } + } + i.close(); + + std::ofstream o(Constants::BUNDLE_DATA_BASE_FILE); + if (!o.is_open()) { + APP_LOGE("failed to open bundle database file"); + ret = false; + } else { + if (!isEmpty) { + o << std::setw(Constants::DUMP_INDENT) << jParse; + } + } + o.close(); + return ret; +} + +bool BundleDataStorage::DeleteStorageModuleInfo( + const std::string &deviceId, const InnerBundleInfo &innerBundleInfo, const std::string &moduleName) const +{ + return true; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/bundlemgr/src/bundle_extractor.cpp b/services/bundlemgr/src/bundle_extractor.cpp new file mode 100644 index 000000000..ba96f0d21 --- /dev/null +++ b/services/bundlemgr/src/bundle_extractor.cpp @@ -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. + */ + +#include "bundle_extractor.h" + +#include "app_log_wrapper.h" +#include "bundle_constants.h" + +namespace OHOS { +namespace AppExecFwk { + +BundleExtractor::BundleExtractor(const std::string &source) : BaseExtractor(source) +{ + APP_LOGI("BundleExtractor is created"); +} + +BundleExtractor::~BundleExtractor() +{ + APP_LOGI("BundleExtractoris destroyed"); +} + +bool BundleExtractor::ExtractProfile(std::ostream &dest) const +{ + return ExtractByName(Constants::BUNDLE_PROFILE_NAME, dest); +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/bundlemgr/src/bundle_installer.cpp b/services/bundlemgr/src/bundle_installer.cpp new file mode 100755 index 000000000..e7dc632ed --- /dev/null +++ b/services/bundlemgr/src/bundle_installer.cpp @@ -0,0 +1,80 @@ +/* + * 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_installer.h" + +#include + +#include "app_log_wrapper.h" +#include "bundle_installer_manager.h" + +namespace OHOS { +namespace AppExecFwk { + +BundleInstaller::BundleInstaller(const int64_t installerId, const std::shared_ptr &handler, + const sptr &statusReceiver) + : installerId_(installerId), handler_(handler), statusReceiver_(statusReceiver) +{ + APP_LOGI("create bundle installer instance, the installer id is %{public}" PRId64 "", installerId_); +} + +BundleInstaller::~BundleInstaller() +{ + APP_LOGI("destroy bundle installer instance, the installer id is %{public}" PRId64 "", installerId_); +} + +void BundleInstaller::Install(const std::string &bundleFilePath, const InstallParam &installParam) +{ + auto resultCode = InstallBundle(bundleFilePath, installParam, Constants::AppType::THIRD_PARTY_APP); + statusReceiver_->OnFinished(resultCode, ""); + SendRemoveEvent(); +} + +void BundleInstaller::Uninstall(const std::string &bundleName, const InstallParam &installParam) +{ + auto resultCode = UninstallBundle(bundleName, installParam); + statusReceiver_->OnFinished(resultCode, ""); + SendRemoveEvent(); +} + +void BundleInstaller::Uninstall( + const std::string &bundleName, const std::string &modulePackage, const InstallParam &installParam) +{ + auto resultCode = UninstallBundle(bundleName, modulePackage, installParam); + statusReceiver_->OnFinished(resultCode, ""); + SendRemoveEvent(); +} + +void BundleInstaller::UpdateInstallerState(const InstallerState state) +{ + APP_LOGI("UpdateInstallerState in bundleInstaller state %{public}d", state); + SetInstallerState(state); + if (statusReceiver_) { + statusReceiver_->OnStatusNotify(static_cast(state)); + } +} + +void BundleInstaller::SendRemoveEvent() const +{ + if (auto handler = handler_.lock()) { + uint32_t eventId = static_cast(BundleInstallerManager::REMOVE_BUNDLE_INSTALLER); + handler->SendEvent(InnerEvent::Get(eventId, installerId_)); + } else { + APP_LOGE("fail to remove %{public}" PRId64 " installer due to handler is expired", installerId_); + } +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/bundlemgr/src/bundle_installer_host.cpp b/services/bundlemgr/src/bundle_installer_host.cpp new file mode 100644 index 000000000..726150f83 --- /dev/null +++ b/services/bundlemgr/src/bundle_installer_host.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 "bundle_installer_host.h" + +#include "ipc_types.h" +#include "string_ex.h" + +#include "app_log_wrapper.h" +#include "appexecfwk_errors.h" +#include "bundle_constants.h" +#include "bundle_permission_mgr.h" + +namespace OHOS { +namespace AppExecFwk { +namespace { + +const std::string INSTALL_THREAD = "install_thread"; +const std::string GET_MANAGER_FAIL = "fail to get bundle installer manager"; + +} // namespace + +BundleInstallerHost::BundleInstallerHost() +{ + APP_LOGI("create bundle installer host instance"); +} + +BundleInstallerHost::~BundleInstallerHost() +{ + APP_LOGI("destroy bundle installer host instance"); +} + +bool BundleInstallerHost::Init() +{ + APP_LOGD("begin to init"); + auto installRunner = EventRunner::Create(INSTALL_THREAD); + if (!installRunner) { + APP_LOGE("create install runner fail"); + return false; + } + manager_ = std::make_shared(installRunner); + APP_LOGD("init successfully"); + return true; +} + +int BundleInstallerHost::OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + APP_LOGI("bundle installer host onReceived message, the message code is %{public}u", code); + std::u16string descripter = GetDescriptor(); + std::u16string remoteDescripter = data.ReadInterfaceToken(); + if (descripter != remoteDescripter) { + APP_LOGE("fail to write reply message in bundle mgr host due to the reply is nullptr"); + return OBJECT_NULL; + } + + switch (code) { + case static_cast(IBundleInstaller::Message::INSTALL): + HandleInstallMessage(data); + break; + case static_cast(IBundleInstaller::Message::UNINSTALL): + HandleUninstallMessage(data); + break; + case static_cast(IBundleInstaller::Message::UNINSTALL_MODULE): + HandleUninstallModuleMessage(data); + break; + default: + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); + } + return NO_ERROR; +} + +void BundleInstallerHost::HandleInstallMessage(Parcel &data) +{ + APP_LOGD("handle install message"); + std::string bundlePath = Str16ToStr8(data.ReadString16()); + std::unique_ptr installParam(data.ReadParcelable()); + if (!installParam) { + APP_LOGE("ReadParcelable failed"); + return; + } + sptr object = data.ReadParcelable(); + sptr statusReceiver = iface_cast(object); + + Install(bundlePath, *installParam, statusReceiver); + APP_LOGD("handle install message finished"); +} + +void BundleInstallerHost::HandleUninstallMessage(Parcel &data) +{ + APP_LOGD("handle uninstall message"); + std::string bundleName = Str16ToStr8(data.ReadString16()); + std::unique_ptr installParam(data.ReadParcelable()); + if (!installParam) { + APP_LOGE("ReadParcelable failed"); + return; + } + sptr object = data.ReadParcelable(); + sptr statusReceiver = iface_cast(object); + + Uninstall(bundleName, *installParam, statusReceiver); + APP_LOGD("handle uninstall message finished"); +} + +void BundleInstallerHost::HandleUninstallModuleMessage(Parcel &data) +{ + APP_LOGD("handle uninstall module message"); + std::string bundleName = Str16ToStr8(data.ReadString16()); + std::string modulePackage = Str16ToStr8(data.ReadString16()); + std::unique_ptr installParam(data.ReadParcelable()); + if (!installParam) { + APP_LOGE("ReadParcelable failed"); + return; + } + sptr object = data.ReadParcelable(); + sptr statusReceiver = iface_cast(object); + + Uninstall(bundleName, modulePackage, *installParam, statusReceiver); + APP_LOGD("handle uninstall message finished"); +} + +bool BundleInstallerHost::Install( + const std::string &bundleFilePath, const InstallParam &installParam, const sptr &statusReceiver) +{ + if (installParam.userId == Constants::INVALID_USERID) { + APP_LOGE("userId invalid"); + return false; + } + if (!CheckBundleInstallerManager(statusReceiver)) { + APP_LOGE("statusReceiver invalid"); + return false; + } + if (!BundlePermissionMgr::CheckCallingPermission(Constants::PERMISSION_INSTALL_BUNDLE)) { + APP_LOGE("install permission denied"); + statusReceiver->OnFinished(ERR_APPEXECFWK_INSTALL_PERMISSION_DENIED, ""); + return false; + } + manager_->CreateInstallTask(bundleFilePath, installParam, statusReceiver); + return true; +} + +bool BundleInstallerHost::Uninstall( + const std::string &bundleName, const InstallParam &installParam, const sptr &statusReceiver) +{ + if (installParam.userId == Constants::INVALID_USERID) { + APP_LOGE("userId invalid"); + return false; + } + if (!CheckBundleInstallerManager(statusReceiver)) { + APP_LOGE("statusReceiver invalid"); + return false; + } + if (!BundlePermissionMgr::CheckCallingPermission(Constants::PERMISSION_INSTALL_BUNDLE)) { + APP_LOGE("uninstall permission denied"); + statusReceiver->OnFinished(ERR_APPEXECFWK_UNINSTALL_PERMISSION_DENIED, ""); + return false; + } + manager_->CreateUninstallTask(bundleName, installParam, statusReceiver); + return true; +} + +bool BundleInstallerHost::Uninstall(const std::string &bundleName, const std::string &modulePackage, + const InstallParam &installParam, const sptr &statusReceiver) +{ + if (installParam.userId == Constants::INVALID_USERID) { + APP_LOGE("userId invalid"); + return false; + } + if (!CheckBundleInstallerManager(statusReceiver)) { + APP_LOGE("statusReceiver invalid"); + return false; + } + if (!BundlePermissionMgr::CheckCallingPermission(Constants::PERMISSION_INSTALL_BUNDLE)) { + APP_LOGE("uninstall permission denied"); + statusReceiver->OnFinished(ERR_APPEXECFWK_UNINSTALL_PERMISSION_DENIED, ""); + return false; + } + manager_->CreateUninstallTask(bundleName, modulePackage, installParam, statusReceiver); + return true; +} + +bool BundleInstallerHost::CheckBundleInstallerManager(const sptr &statusReceiver) const +{ + if (!statusReceiver) { + APP_LOGE("the receiver is nullptr"); + return false; + } + if (!manager_) { + APP_LOGE("the bundle installer manager is nullptr"); + statusReceiver->OnFinished(ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR, GET_MANAGER_FAIL); + return false; + } + return true; +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/bundlemgr/src/bundle_installer_manager.cpp b/services/bundlemgr/src/bundle_installer_manager.cpp new file mode 100755 index 000000000..69d8a1977 --- /dev/null +++ b/services/bundlemgr/src/bundle_installer_manager.cpp @@ -0,0 +1,128 @@ +/* + * 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_installer_manager.h" +#include + +#include "datetime_ex.h" + +#include "app_log_wrapper.h" +#include "appexecfwk_errors.h" + +namespace OHOS { +namespace AppExecFwk { +namespace { + +const std::string ADD_INSTALLER_FAIL = "fail to add installer in bundle installer manager"; + +} + +BundleInstallerManager::BundleInstallerManager(const std::shared_ptr &runner) : EventHandler(runner) +{ + APP_LOGI("create bundle installer manager instance"); + installersPool_.Start(THREAD_NUMBER); + installersPool_.SetMaxTaskNum(MAX_TASK_NUMBER); +} + +BundleInstallerManager::~BundleInstallerManager() +{ + APP_LOGI("destroy bundle installer manager instance"); + installersPool_.Stop(); +} + +void BundleInstallerManager::ProcessEvent(const InnerEvent::Pointer &event) +{ + APP_LOGI("process event : %{public}u", event->GetInnerEventId()); + switch (event->GetInnerEventId()) { + case REMOVE_BUNDLE_INSTALLER: + RemoveInstaller(event->GetParam()); + break; + default: + APP_LOGW("the eventId is not supported"); + } +} + +void BundleInstallerManager::CreateInstallTask( + const std::string &bundleFilePath, const InstallParam &installParam, const sptr &statusReceiver) +{ + auto installer = CreateInstaller(statusReceiver); + if (!installer) { + APP_LOGE("create installer failed"); + return; + } + auto task = [installer, bundleFilePath, installParam] { installer->Install(bundleFilePath, installParam); }; + installersPool_.AddTask(task); +} + +void BundleInstallerManager::CreateUninstallTask( + const std::string &bundleName, const InstallParam &installParam, const sptr &statusReceiver) +{ + auto installer = CreateInstaller(statusReceiver); + if (!installer) { + APP_LOGE("create installer failed"); + return; + } + auto task = [installer, bundleName, installParam] { installer->Uninstall(bundleName, installParam); }; + installersPool_.AddTask(task); +} + +void BundleInstallerManager::CreateUninstallTask(const std::string &bundleName, const std::string &modulePackage, + const InstallParam &installParam, const sptr &statusReceiver) +{ + auto installer = CreateInstaller(statusReceiver); + if (!installer) { + APP_LOGE("create installer failed"); + return; + } + auto task = [installer, bundleName, modulePackage, installParam] { + installer->Uninstall(bundleName, modulePackage, installParam); + }; + installersPool_.AddTask(task); +} + +std::shared_ptr BundleInstallerManager::CreateInstaller(const sptr &statusReceiver) +{ + int64_t installerId = GetMicroTickCount(); + auto installer = std::make_shared(installerId, shared_from_this(), statusReceiver); + if (!installer) { + APP_LOGE("create bundle installer failed"); + return nullptr; + } + bool isSuccess = false; + { + std::lock_guard lock(mutex_); + auto result = installers_.try_emplace(installer->GetInstallerId(), installer); + isSuccess = result.second; + } + if (isSuccess) { + APP_LOGD("add the specific %{public}" PRId64 " installer", installerId); + } else { + APP_LOGE("fail to add bundle installer"); + installer.reset(); + statusReceiver->OnFinished(ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR, ADD_INSTALLER_FAIL); + } + return installer; +} + +void BundleInstallerManager::RemoveInstaller(const int64_t installerId) +{ + std::lock_guard lock(mutex_); + if (installers_.erase(installerId) > 0) { + APP_LOGD("erase the specific %{public}" PRId64 " installer", installerId); + } +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/bundlemgr/src/bundle_mgr_host_impl.cpp b/services/bundlemgr/src/bundle_mgr_host_impl.cpp new file mode 100755 index 000000000..cb913a3e3 --- /dev/null +++ b/services/bundlemgr/src/bundle_mgr_host_impl.cpp @@ -0,0 +1,428 @@ +/* + * 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_mgr_host_impl.h" + +#include + +#include "json_serializer.h" +#include "app_log_wrapper.h" +#include "bundle_mgr_service.h" +#include "bundle_util.h" +#include "bundle_parser.h" +#include "installd_client.h" +#include "bundle_permission_mgr.h" + +namespace OHOS { +namespace AppExecFwk { + +bool BundleMgrHostImpl::GetApplicationInfo( + const std::string &appName, const ApplicationFlag flag, const int userId, ApplicationInfo &appInfo) +{ + auto dataMgr = GetDataMgrFromService(); + if (dataMgr == nullptr) { + APP_LOGE("DataMgr is nullptr"); + return false; + } + return dataMgr->GetApplicationInfo(appName, flag, userId, appInfo); +} + +bool BundleMgrHostImpl::GetApplicationInfos( + const ApplicationFlag flag, const int userId, std::vector &appInfos) +{ + auto dataMgr = GetDataMgrFromService(); + if (dataMgr == nullptr) { + APP_LOGE("DataMgr is nullptr"); + return false; + } + return dataMgr->GetApplicationInfos(flag, userId, appInfos); +} + +bool BundleMgrHostImpl::GetBundleInfo(const std::string &bundleName, const BundleFlag flag, BundleInfo &bundleInfo) +{ + auto dataMgr = GetDataMgrFromService(); + if (dataMgr == nullptr) { + APP_LOGE("DataMgr is nullptr"); + return false; + } + return dataMgr->GetBundleInfo(bundleName, flag, bundleInfo); +} + +bool BundleMgrHostImpl::GetBundleInfos(const BundleFlag flag, std::vector &bundleInfos) +{ + auto dataMgr = GetDataMgrFromService(); + if (dataMgr == nullptr) { + APP_LOGE("DataMgr is nullptr"); + return false; + } + return dataMgr->GetBundleInfos(flag, bundleInfos); +} + +bool BundleMgrHostImpl::GetBundleNameForUid(const int uid, std::string &bundleName) +{ + auto dataMgr = GetDataMgrFromService(); + if (dataMgr == nullptr) { + APP_LOGE("DataMgr is nullptr"); + return false; + } + return dataMgr->GetBundleNameForUid(uid, bundleName); +} + +bool BundleMgrHostImpl::GetBundleGids(const std::string &bundleName, std::vector &gids) +{ + auto dataMgr = GetDataMgrFromService(); + if (dataMgr == nullptr) { + APP_LOGE("DataMgr is nullptr"); + return false; + } + return dataMgr->GetBundleGids(bundleName, gids); +} + +bool BundleMgrHostImpl::CheckIsSystemAppByUid(const int uid) +{ + auto dataMgr = GetDataMgrFromService(); + if (dataMgr == nullptr) { + APP_LOGE("DataMgr is nullptr"); + return false; + } + return dataMgr->CheckIsSystemAppByUid(uid); +} + +bool BundleMgrHostImpl::GetBundleInfosByMetaData(const std::string &metaData, std::vector &bundleInfos) +{ + auto dataMgr = GetDataMgrFromService(); + if (dataMgr == nullptr) { + APP_LOGE("DataMgr is nullptr"); + return false; + } + return dataMgr->GetBundleInfosByMetaData(metaData, bundleInfos); +} + +bool BundleMgrHostImpl::QueryAbilityInfo(const Want &want, AbilityInfo &abilityInfo) +{ + auto dataMgr = GetDataMgrFromService(); + if (dataMgr == nullptr) { + APP_LOGE("DataMgr is nullptr"); + return false; + } + return dataMgr->QueryAbilityInfo(want, abilityInfo); +} + +bool BundleMgrHostImpl::QueryAbilityInfoByUri(const std::string &abilityUri, AbilityInfo &abilityInfo) +{ + auto dataMgr = GetDataMgrFromService(); + if (dataMgr == nullptr) { + APP_LOGE("DataMgr is nullptr"); + return false; + } + return dataMgr->QueryAbilityInfoByUri(abilityUri, abilityInfo); +} + +bool BundleMgrHostImpl::QueryKeepAliveBundleInfos(std::vector &bundleInfos) +{ + auto dataMgr = GetDataMgrFromService(); + if (dataMgr == nullptr) { + APP_LOGE("DataMgr is nullptr"); + return false; + } + return dataMgr->QueryKeepAliveBundleInfos(bundleInfos); +} + +std::string BundleMgrHostImpl::GetAbilityLabel(const std::string &bundleName, const std::string &className) +{ + auto dataMgr = GetDataMgrFromService(); + if (dataMgr == nullptr) { + APP_LOGE("DataMgr is nullptr"); + return Constants::EMPTY_STRING; + } + return dataMgr->GetAbilityLabel(bundleName, className); +} + +bool BundleMgrHostImpl::GetBundleArchiveInfo( + const std::string &hapFilePath, const BundleFlag flag, BundleInfo &bundleInfo) +{ + std::string realPath; + auto ret = BundleUtil::CheckFilePath(hapFilePath, realPath); + if (ret != ERR_OK) { + APP_LOGE("GetBundleArchiveInfo file path %{public}s invalid", hapFilePath.c_str()); + return false; + } + InnerBundleInfo info; + BundleParser bundleParser; + ret = bundleParser.Parse(realPath, info); + if (ret != ERR_OK) { + APP_LOGE("parse bundle info failed, error: %{public}d", ret); + return false; + } + info.GetBundleInfo(flag, bundleInfo); + return true; +} + +bool BundleMgrHostImpl::GetHapModuleInfo(const AbilityInfo &abilityInfo, HapModuleInfo &hapModuleInfo) +{ + if (abilityInfo.bundleName.empty() || abilityInfo.package.empty()) { + APP_LOGE("fail to GetHapModuleInfo due to params empty"); + return false; + } + auto dataMgr = GetDataMgrFromService(); + if (dataMgr == nullptr) { + APP_LOGE("DataMgr is nullptr"); + return false; + } + return dataMgr->GetHapModuleInfo(abilityInfo, hapModuleInfo); +} + +bool BundleMgrHostImpl::GetLaunchWantForBundle(const std::string &bundleName, Want &want) +{ + auto dataMgr = GetDataMgrFromService(); + if (dataMgr == nullptr) { + APP_LOGE("DataMgr is nullptr"); + return false; + } + return dataMgr->GetLaunchWantForBundle(bundleName, want); +} + +int BundleMgrHostImpl::CheckPublicKeys(const std::string &firstBundleName, const std::string &secondBundleName) +{ + return -1; +} + +int BundleMgrHostImpl::CheckPermission(const std::string &bundleName, const std::string &permission) +{ + if (bundleName.empty() || permission.empty()) { + APP_LOGE("fail to CheckPermission due to params empty"); + return Constants::PERMISSION_NOT_GRANTED; + } + return BundlePermissionMgr::VerifyPermission(bundleName, permission, Constants::DEFAULT_USERID); +} + +bool BundleMgrHostImpl::GetPermissionDef(const std::string &permissionName, PermissionDef &permissionDef) +{ + if (permissionName.empty()) { + APP_LOGE("fail to GetPermissionDef due to params empty"); + return false; + } + return BundlePermissionMgr::GetPermissionDef(permissionName, permissionDef); +} + +bool BundleMgrHostImpl::GetAllPermissionGroupDefs(std::vector &permissionDefs) +{ + return true; +} + +bool BundleMgrHostImpl::GetAppsGrantedPermissions( + const std::vector &permissions, std::vector &appNames) +{ + return true; +} + +bool BundleMgrHostImpl::HasSystemCapability(const std::string &capName) +{ + return true; +} + +bool BundleMgrHostImpl::GetSystemAvailableCapabilities(std::vector &systemCaps) +{ + return true; +} + +bool BundleMgrHostImpl::IsSafeMode() +{ + return true; +} + +bool BundleMgrHostImpl::CleanBundleCacheFiles( + const std::string &bundleName, const sptr &cleanCacheCallback) +{ + if (!cleanCacheCallback || bundleName.empty()) { + APP_LOGE("the cleanCacheCallback is nullptr or bundleName empty"); + return false; + } + ApplicationInfo applicationInfo; + if (!GetApplicationInfo(bundleName, ApplicationFlag::GET_BASIC_APPLICATION_INFO, 0, applicationInfo)) { + APP_LOGE("can not get application info of %{public}s", bundleName.c_str()); + return false; + } + auto cacheDir = applicationInfo.cacheDir; + std::thread([cacheDir, cleanCacheCallback]() { + auto ret = InstalldClient::GetInstance()->CleanBundleDataDir(cacheDir); + cleanCacheCallback->OnCleanCacheFinished((ret == ERR_OK) ? true : false); + }).detach(); + return true; +} + +bool BundleMgrHostImpl::CleanBundleDataFiles(const std::string &bundleName) +{ + if (bundleName.empty()) { + APP_LOGE("the bundleName empty"); + return false; + } + ApplicationInfo applicationInfo; + if (!GetApplicationInfo(bundleName, ApplicationFlag::GET_BASIC_APPLICATION_INFO, 0, applicationInfo)) { + APP_LOGE("can not get application info of %{public}s", bundleName.c_str()); + return false; + } + if (InstalldClient::GetInstance()->CleanBundleDataDir(applicationInfo.dataDir) != ERR_OK) { + return false; + } + return true; +} + +bool BundleMgrHostImpl::RegisterBundleStatusCallback(const sptr &bundleStatusCallback) +{ + if ((!bundleStatusCallback) || (bundleStatusCallback->GetBundleName().empty())) { + APP_LOGE("the bundleStatusCallback is nullptr or bundleName empty"); + return false; + } + auto dataMgr = GetDataMgrFromService(); + if (dataMgr == nullptr) { + APP_LOGE("DataMgr is nullptr"); + return false; + } + return dataMgr->RegisterBundleStatusCallback(bundleStatusCallback); +} + +bool BundleMgrHostImpl::ClearBundleStatusCallback(const sptr &bundleStatusCallback) +{ + if (!bundleStatusCallback) { + APP_LOGE("the bundleStatusCallback is nullptr"); + return false; + } + auto dataMgr = GetDataMgrFromService(); + if (dataMgr == nullptr) { + APP_LOGE("DataMgr is nullptr"); + return false; + } + return dataMgr->ClearBundleStatusCallback(bundleStatusCallback); +} + +bool BundleMgrHostImpl::UnregisterBundleStatusCallback() +{ + auto dataMgr = GetDataMgrFromService(); + if (dataMgr == nullptr) { + APP_LOGE("DataMgr is nullptr"); + return false; + } + return dataMgr->UnregisterBundleStatusCallback(); +} + +bool BundleMgrHostImpl::DumpInfos(const DumpFlag flag, const std::string &bundleName, std::string &result) +{ + auto dataMgr = GetDataMgrFromService(); + if (dataMgr == nullptr) { + APP_LOGE("DataMgr is nullptr"); + return false; + } + bool ret = false; + switch (flag) { + case DumpFlag::DUMP_BUNDLE_LIST: { + std::vector bundleNames; + ret = dataMgr->GetBundleList(bundleNames); + if (ret) { + for (const auto &name : bundleNames) { + result.append(name); + result.append("\n"); + } + APP_LOGI("get installed bundles success"); + } + break; + } + case DumpFlag::DUMP_ALL_BUNDLE_INFO: { + std::vector bundleInfos; + ret = GetBundleInfos(BundleFlag::GET_BUNDLE_WITH_ABILITIES, bundleInfos); + if (ret) { + for (const auto &info : bundleInfos) { + result.append(info.name); + result.append(":\n"); + nlohmann::json jsonObject = info; + result.append(jsonObject.dump(Constants::DUMP_INDENT)); + result.append("\n"); + } + APP_LOGI("get all bundle info success"); + } + break; + } + case DumpFlag::DUMP_BUNDLE_INFO: { + BundleInfo bundleInfo; + ret = GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_WITH_ABILITIES, bundleInfo); + if (ret) { + result.append(bundleName); + result.append(":\n"); + nlohmann::json jsonObject = bundleInfo; + result.append(jsonObject.dump(Constants::DUMP_INDENT)); + result.append("\n"); + APP_LOGI("get %{public}s bundle info success", bundleName.c_str()); + } + break; + } + default: + APP_LOGE("dump flag error"); + return false; + } + return ret; +} + +bool BundleMgrHostImpl::IsApplicationEnabled(const std::string &bundleName) +{ + auto dataMgr = GetDataMgrFromService(); + if (dataMgr == nullptr) { + APP_LOGE("DataMgr is nullptr"); + return false; + } + return dataMgr->IsApplicationEnabled(bundleName); +} + +bool BundleMgrHostImpl::SetApplicationEnabled(const std::string &bundleName, bool isEnable) +{ + auto dataMgr = GetDataMgrFromService(); + if (dataMgr == nullptr) { + APP_LOGE("DataMgr is nullptr"); + return false; + } + return dataMgr->SetApplicationEnabled(bundleName, isEnable); +} + +sptr BundleMgrHostImpl::GetBundleInstaller() +{ + return DelayedSingleton::GetInstance()->GetBundleInstaller(); +} + +bool BundleMgrHostImpl::CanRequestPermission( + const std::string &bundleName, const std::string &permissionName, const int userId) +{ + if (bundleName.empty() || permissionName.empty()) { + APP_LOGE("fail to CanRequestPermission due to params empty"); + return false; + } + return BundlePermissionMgr::CanRequestPermission(bundleName, permissionName, userId); +} + +bool BundleMgrHostImpl::RequestPermissionFromUser( + const std::string &bundleName, const std::string &permissionName, const int userId) +{ + if (bundleName.empty() || permissionName.empty()) { + APP_LOGE("fail to CanRequestPermission due to params empty"); + return false; + } + return BundlePermissionMgr::RequestPermissionFromUser(bundleName, permissionName, userId); +} + +const std::shared_ptr BundleMgrHostImpl::GetDataMgrFromService() +{ + return DelayedSingleton::GetInstance()->GetDataMgr(); +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/bundlemgr/src/bundle_mgr_service.cpp b/services/bundlemgr/src/bundle_mgr_service.cpp new file mode 100644 index 000000000..fd3020f0b --- /dev/null +++ b/services/bundlemgr/src/bundle_mgr_service.cpp @@ -0,0 +1,176 @@ +/* + * 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_mgr_service.h" + +#include "datetime_ex.h" +#include "app_log_wrapper.h" +#include "perf_profile.h" +#include "system_ability_definition.h" +#include "bundle_constants.h" +#include "system_ability_helper.h" + +namespace OHOS { +namespace AppExecFwk { + +const bool REGISTER_RESULT = + SystemAbility::MakeAndRegisterAbility(DelayedSingleton::GetInstance().get()); + +BundleMgrService::BundleMgrService() : SystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID, true) +{ + APP_LOGI("instance is created"); + PerfProfile::GetInstance().SetBmsLoadStartTime(GetTickCount()); +} + +BundleMgrService::~BundleMgrService() +{ + if (host_ != nullptr) { + host_ = nullptr; + } + if (installer_ != nullptr) { + installer_ = nullptr; + } + if (handler_) { + handler_.reset(); + } + if (runner_) { + runner_.reset(); + } + if (dataMgr_) { + dataMgr_.reset(); + } + APP_LOGI("instance is destroyed"); +} + +void BundleMgrService::OnStart() +{ + APP_LOGD("start is triggered"); + if (!Init()) { + APP_LOGE("init fail"); + return; + } + + if (!registerToService_) { + if (!SystemAbilityHelper::AddSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID, host_)) { + APP_LOGE("fail to register to system ability manager"); + return; + } + APP_LOGI("register to sam success"); + registerToService_ = true; + } + + PerfProfile::GetInstance().SetBmsLoadEndTime(GetTickCount()); + if (!needToScan_) { + PerfProfile::GetInstance().Dump(); + } +} + +void BundleMgrService::OnStop() +{ + APP_LOGI("OnStop is called"); + SelfClean(); +} + +bool BundleMgrService::IsServiceReady() const +{ + return ready_; +} + +bool BundleMgrService::Init() +{ + if (ready_) { + APP_LOGW("init more than one time"); + return false; + } + + if (host_ == nullptr) { + host_ = new (std::nothrow) BundleMgrHostImpl(); + if (!host_) { + APP_LOGE("create host instance fail"); + return false; + } + } + + APP_LOGI("init begin"); + + if (!runner_) { + runner_ = EventRunner::Create(Constants::BMS_SERVICE_NAME); + if (!runner_) { + APP_LOGE("create runner fail"); + return false; + } + } + APP_LOGD("create runner success"); + + if (!handler_) { + handler_ = std::make_shared(runner_); + if (!handler_) { + APP_LOGE("create bms event handler fail"); + return false; + } + } + APP_LOGD("create handler success"); + + if (!installer_) { + installer_ = new (std::nothrow) BundleInstallerHost(); + if (!installer_ || !installer_->Init()) { + APP_LOGE("init installer fail"); + return false; + } + } + APP_LOGD("create installer host success"); + + if (!dataMgr_) { + APP_LOGI("Create BundledataMgr"); + dataMgr_ = std::make_shared(); + } + APP_LOGD("create dataManager success"); + + if (!(dataMgr_->LoadDataFromPersistentStorage())) { + APP_LOGW("load data from persistent storage fail"); + handler_->SendEvent(BMSEventHandler::BUNDLE_SCAN_START); + needToScan_ = true; + } + + ready_ = true; + APP_LOGI("init end success"); + return true; +} + +sptr BundleMgrService::GetBundleInstaller() const +{ + return installer_; +} + +const std::shared_ptr BundleMgrService::GetDataMgr() const +{ + return dataMgr_; +} + +void BundleMgrService::SelfClean() +{ + if (ready_) { + ready_ = false; + if (registerToService_) { + registerToService_ = false; + } + if (needToScan_) { + needToScan_ = false; + } + } +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/bundlemgr/src/bundle_mgr_service_event_handler.cpp b/services/bundlemgr/src/bundle_mgr_service_event_handler.cpp new file mode 100755 index 000000000..09a50aca7 --- /dev/null +++ b/services/bundlemgr/src/bundle_mgr_service_event_handler.cpp @@ -0,0 +1,94 @@ +/* + * 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_mgr_service_event_handler.h" + +#include + +#include "app_log_wrapper.h" +#include "bundle_mgr_service.h" +#include "bundle_scanner.h" +#include "perf_profile.h" +#include "system_bundle_installer.h" + +namespace OHOS { +namespace AppExecFwk { + +BMSEventHandler::BMSEventHandler(const std::shared_ptr &runner) : EventHandler(runner) +{ + APP_LOGI("instance is created"); +} + +BMSEventHandler::~BMSEventHandler() +{ + APP_LOGI("instance is destroyed"); +} + +void BMSEventHandler::ProcessEvent(const InnerEvent::Pointer &event) +{ + switch (event->GetInnerEventId()) { + case BUNDLE_SCAN_START: { + auto future = std::async(std::launch::async, [this] { + ProcessSystemBundleInstall(Constants::AppType::SYSTEM_APP); + ProcessSystemBundleInstall(Constants::AppType::THIRD_SYSTEM_APP); + }); + future.get(); + SetAllInstallFlag(); + break; + } + case BUNDLE_SCAN_FINISHED: + break; + case BMS_START_FINISHED: + break; + default: + APP_LOGE("the eventId is not supported"); + break; + } +} + +void BMSEventHandler::ProcessSystemBundleInstall(Constants::AppType appType) const +{ + APP_LOGI("scan thread start"); + auto scanner = std::make_unique(); + if (!scanner) { + APP_LOGE("make scanner failed"); + return; + } + std::string scanDir = (appType == Constants::AppType::SYSTEM_APP) ? Constants::SYSTEM_APP_SCAN_PATH + : Constants::THIRD_SYSTEM_APP_SCAN_PATH; + APP_LOGI("scanDir %{public}s", scanDir.c_str()); + std::list bundleList = scanner->Scan(scanDir); + for (const auto &item : bundleList) { + SystemBundleInstaller installer(item); + APP_LOGI("scan item %{public}s", item.c_str()); + if (!installer.InstallSystemBundle(appType)) { + APP_LOGW("Install System app:%{public}s error", item.c_str()); + } + } + PerfProfile::GetInstance().Dump(); +} + +void BMSEventHandler::SetAllInstallFlag() const +{ + auto dataMgr = DelayedSingleton::GetInstance()->GetDataMgr(); + if (dataMgr == nullptr) { + APP_LOGE("DataMgr is nullptr"); + return; + } + dataMgr->SetAllInstallFlag(true); +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/bundlemgr/src/bundle_parser.cpp b/services/bundlemgr/src/bundle_parser.cpp new file mode 100644 index 000000000..c049cc41f --- /dev/null +++ b/services/bundlemgr/src/bundle_parser.cpp @@ -0,0 +1,48 @@ +/* + * 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_parser.h" + +#include + +#include "app_log_wrapper.h" +#include "bundle_constants.h" +#include "bundle_extractor.h" +#include "bundle_profile.h" + +namespace OHOS { +namespace AppExecFwk { + +ErrCode BundleParser::Parse(const std::string &pathName, InnerBundleInfo &innerBundleInfo) const +{ + APP_LOGI("parse from %{public}s", pathName.c_str()); + BundleExtractor bundleExtractor(pathName); + if (!bundleExtractor.Init()) { + APP_LOGE("bundle extractor init failed"); + return ERR_APPEXECFWK_PARSE_UNEXPECTED; + } + + std::ostringstream outStream; + if (!bundleExtractor.ExtractProfile(outStream)) { + APP_LOGE("extract profile file failed"); + return ERR_APPEXECFWK_PARSE_NO_PROFILE; + } + + BundleProfile bundleProfile; + return bundleProfile.TransformTo(outStream, innerBundleInfo); +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/bundlemgr/src/bundle_permission_mgr.cpp b/services/bundlemgr/src/bundle_permission_mgr.cpp new file mode 100644 index 000000000..be095ae15 --- /dev/null +++ b/services/bundlemgr/src/bundle_permission_mgr.cpp @@ -0,0 +1,355 @@ +/* + * 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_permission_mgr.h" + +#include "ipc_skeleton.h" +#include "app_log_wrapper.h" +#include "bundle_constants.h" +#include "bundle_mgr_service.h" + +namespace OHOS { +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"; +// convert the Permission::PermissionDef struct to +// AppExecFwk::PermissionDef struct that can be used in IPC process +bool ConvertPermissionDef(const Permission::PermissionDef &permDef, PermissionDef &permissionDef) +{ + permissionDef.permissionName = permDef.permissionName; + permissionDef.bundleName = permDef.bundleName; + permissionDef.grantMode = permDef.grantMode; + permissionDef.availableScope = permDef.availableScope; + permissionDef.label = permDef.label; + permissionDef.labelId = permDef.labelId; + permissionDef.description = permDef.description; + permissionDef.descriptionId = permDef.descriptionId; + return true; +} + +// Convert from the struct DefPermission that parsed from config.json +bool ConvertPermissionDef( + Permission::PermissionDef &permDef, const DefPermission &defPermission, const std::string &bundleName) +{ + permDef.permissionName = defPermission.name; + permDef.bundleName = bundleName; + permDef.grantMode = [&defPermission]() -> int { + if (defPermission.grantMode == + ProfileReader::BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_GRANTMODE_SYSTEM_GRANT) { + return Permission::GrantMode::SYSTEM_GRANT; + } + return Permission::GrantMode::USER_GRANT; + }(); + permDef.availableScope = [&defPermission]() -> int { + unsigned flag = 0; + if (std::find(defPermission.availableScope.begin(), + defPermission.availableScope.end(), + ProfileReader::BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_AVAILABLESCOPE_SIGNATURE) != + defPermission.availableScope.end()) { + flag |= Permission::AvailableScope::AVAILABLE_SCOPE_SIGNATURE; + } + if (std::find(defPermission.availableScope.begin(), + defPermission.availableScope.end(), + ProfileReader::BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_AVAILABLESCOPE_RESTRICTED) != + defPermission.availableScope.end()) { + flag |= Permission::AvailableScope::AVAILABLE_SCOPE_RESTRICTED; + } + if (flag == 0) { + return Permission::AvailableScope::AVAILABLE_SCOPE_ALL; + } + return flag; + }(); + permDef.label = defPermission.label; + permDef.labelId = defPermission.labelId; + permDef.description = defPermission.description; + permDef.descriptionId = defPermission.descriptionId; + return true; +} + +} // namespace + +bool BundlePermissionMgr::InitPermissions() +{ + // need load all system defined permissions here on first start up. + return true; +} + +int BundlePermissionMgr::AddDefPermissions(const InnerBundleInfo &innerBundleInfo) +{ + const auto bundleName = innerBundleInfo.GetBundleName(); + const auto defPermissions = innerBundleInfo.GetDefPermissions(); + int ret = Permission::RET_FAILED; + if (!defPermissions.empty()) { + std::vector permList; + for (const auto &defPermission : defPermissions) { + Permission::PermissionDef perm; + APP_LOGI("add defPermission %{public}s", defPermission.name.c_str()); + ConvertPermissionDef(perm, defPermission, bundleName); + permList.emplace_back(perm); + } + if (!permList.empty()) { + ret = Permission::PermissionKit::AddDefPermissions(permList); + } + } + return ret; +} + +bool BundlePermissionMgr::CheckPermissionAuthorization( + const Permission::PermissionDef &permissionDef, const InnerBundleInfo &innerBundleInfo) +{ + APP_LOGI("availableScope type is %{public}d", permissionDef.availableScope); + if (permissionDef.availableScope == Permission::TypeAvailableScope::AVAILABLE_SCOPE_ALL) { + return true; + } + if (permissionDef.availableScope != Permission::TypeAvailableScope::AVAILABLE_SCOPE_SIGNATURE) { + return false; + } + auto appFeature = innerBundleInfo.GetAppFeature(); + APP_LOGI("appFeature is %{public}s", appFeature.c_str()); + APP_LOGI("permission name is %{public}s", permissionDef.permissionName.c_str()); + auto dataMgr = DelayedSingleton::GetInstance()->GetDataMgr(); + if (!dataMgr) { + APP_LOGE("Get dataMgr shared_ptr nullptr"); + return false; + } + if (appFeature == HOS_NORMAL_APP) { + std::string provisionId; + bool result = dataMgr->GetProvisionId(permissionDef.bundleName, provisionId); + if (result && (provisionId == innerBundleInfo.GetProvisionId())) { + APP_LOGI("provisionId is same"); + return true; + } + } else if (appFeature == HOS_SYSTEM_APP) { + std::string oldAppFeature; + bool result = dataMgr->GetAppFeature(permissionDef.bundleName, oldAppFeature); + APP_LOGI("oldAppFeature %{public}s", oldAppFeature.c_str()); + if (result && (oldAppFeature == HOS_SYSTEM_APP)) { + APP_LOGI("appFeature is same"); + return true; + } + } + return false; +} + +int BundlePermissionMgr::AddAndGrantedReqPermissions(const InnerBundleInfo &innerBundleInfo) +{ + auto reqPermissions = innerBundleInfo.GetReqPermissions(); + std::vector userPermList; + std::vector systemPermList; + std::vector grantPermList; + for (const auto &reqPermission : reqPermissions) { + APP_LOGI("add permission %{public}s", reqPermission.name.c_str()); + Permission::PermissionDef permDef; + int ret = Permission::PermissionKit::GetDefPermission(reqPermission.name, permDef); + if (ret != Permission::RET_SUCCESS) { + APP_LOGE("get permission def failed"); + continue; + } + if (permDef.grantMode == Permission::GrantMode::USER_GRANT) { + userPermList.emplace_back(reqPermission.name); + continue; + } + if (permDef.grantMode == Permission::GrantMode::SYSTEM_GRANT) { + systemPermList.emplace_back(reqPermission.name); + if (CheckPermissionAuthorization(permDef, innerBundleInfo)) { + grantPermList.emplace_back(reqPermission.name); + } + continue; + } + } + std::string bundleName = innerBundleInfo.GetBundleName(); + APP_LOGI("add permission %{public}s %{public}zu %{public}zu %{public}zu", + bundleName.c_str(), + userPermList.size(), + systemPermList.size(), + grantPermList.size()); + if (!userPermList.empty()) { + auto ret = AddUserGrantedReqPermissions(bundleName, userPermList, Constants::DEFAULT_USERID); + if (ret != Permission::RET_SUCCESS) { + APP_LOGE("AddUserGrantedReqPermissions failed"); + } + } + if (!systemPermList.empty()) { + auto ret = AddSystemGrantedReqPermissions(bundleName, systemPermList); + if (ret != Permission::RET_SUCCESS) { + APP_LOGE("AddUserGrantedReqPermissions failed"); + } + } + for (const auto &perm : grantPermList) { + auto ret = GrantReqPermissions(bundleName, perm); + if (ret != Permission::RET_SUCCESS) { + APP_LOGE("GrantReqPermissions failed"); + } + } + return Permission::RET_SUCCESS; +} + +bool BundlePermissionMgr::InstallPermissions(const InnerBundleInfo &innerBundleInfo) +{ + int ret = AddDefPermissions(innerBundleInfo); + if (ret != Permission::RET_SUCCESS) { + APP_LOGE("AddDefPermissions ret %{public}d", ret); + } + ret = AddAndGrantedReqPermissions(innerBundleInfo); + if (ret != Permission::RET_SUCCESS) { + APP_LOGE("AddUserGrantedReqPermissions ret %{public}d", ret); + } + return true; +} + +bool BundlePermissionMgr::UpdatePermissions(const InnerBundleInfo &innerBundleInfo) +{ + // at current time the update permissions process is same as installation process. + return InstallPermissions(innerBundleInfo); +} + +bool BundlePermissionMgr::UninstallPermissions(const InnerBundleInfo &innerBundleInfo) +{ + auto bundleName = innerBundleInfo.GetBundleName(); + auto ret = RemoveDefPermissions(bundleName); + if (ret != Permission::RET_SUCCESS) { + APP_LOGE("RemoveDefPermissions ret %{public}d", ret); + } + int userId = innerBundleInfo.GetUserId(); + ret = RemoveUserGrantedReqPermissions(bundleName, userId); + if (ret != Permission::RET_SUCCESS) { + APP_LOGE("RemoveUserGrantedReqPermissions ret %{public}d", ret); + } + ret = RemoveSystemGrantedReqPermissions(bundleName); + if (ret != Permission::RET_SUCCESS) { + APP_LOGE("RemoveSystemGrantedReqPermissions ret %{public}d", ret); + } + return true; +} + +int BundlePermissionMgr::VerifyPermission( + const std::string &bundleName, const std::string &permissionName, const int userId) +{ + APP_LOGI( + "VerifyPermission bundleName %{public}s, permission %{public}s", bundleName.c_str(), permissionName.c_str()); + return Permission::PermissionKit::VerifyPermission(bundleName, permissionName, userId); +} + +bool BundlePermissionMgr::CanRequestPermission( + const std::string &bundleName, const std::string &permissionName, const int userId) +{ + APP_LOGI("CanRequestPermission bundleName %{public}s, permission %{public}s", + bundleName.c_str(), + permissionName.c_str()); + return Permission::PermissionKit::CanRequestPermission(bundleName, permissionName, userId); +} + +bool BundlePermissionMgr::RequestPermissionFromUser( + const std::string &bundleName, const std::string &permissionName, const int userId) +{ + APP_LOGI("RequestPermissionFromUser bundleName %{public}s, permission %{public}s", + bundleName.c_str(), + permissionName.c_str()); + return (Permission::PermissionKit::GrantUserGrantedPermission(bundleName, permissionName, userId) == + Permission::RET_SUCCESS); +} + +bool BundlePermissionMgr::GetPermissionDef(const std::string &permissionName, PermissionDef &permissionDef) +{ + APP_LOGI("GetPermissionDef permission %{public}s", permissionName.c_str()); + Permission::PermissionDef permDef; + int ret = Permission::PermissionKit::GetDefPermission(permissionName, permDef); + if (ret != Permission::RET_SUCCESS) { + APP_LOGE("get permission def failed"); + return false; + } + return ConvertPermissionDef(permDef, permissionDef); +} + +bool BundlePermissionMgr::CheckCallingPermission(const std::string &permissionName) +{ + int32_t uid = IPCSkeleton::GetCallingUid(); + if (uid >= Constants::ROOT_UID && uid < Constants::BASE_SYS_UID) { + APP_LOGE("check permission true for system uid %{public}d", uid); + return true; + } + auto dataMgr = DelayedSingleton::GetInstance()->GetDataMgr(); + if (!dataMgr) { + APP_LOGE("Get dataMgr shared_ptr nullptr"); + return false; + } + std::string bundleName; + bool result = dataMgr->GetBundleNameForUid(uid, bundleName); + if (!result) { + APP_LOGE("cannot get bundle name by uid %{public}d", uid); + return false; + } + // now if the application is Launcher, pass it through for installing permission + { + APP_LOGI( + "get app bundleName %{public}s and permissionName %{public}s", bundleName.c_str(), permissionName.c_str()); + ApplicationInfo appInfo; + bool ret = dataMgr->GetApplicationInfo(bundleName, ApplicationFlag::GET_BASIC_APPLICATION_INFO, + Constants::DEFAULT_USERID, appInfo); + if (ret && appInfo.isLauncherApp && (permissionName == Constants::PERMISSION_INSTALL_BUNDLE)) { + APP_LOGE("launcher app %{public}s pass through", bundleName.c_str()); + return true; + } + } + int ret = VerifyPermission(bundleName, permissionName, Constants::DEFAULT_USERID); + APP_LOGI("permission = %{public}s, uid = %{public}d, ret = %{public}d", permissionName.c_str(), uid, ret); + return ret == Permission::PermissionState::PERMISSION_GRANTED; +} + +int BundlePermissionMgr::GrantReqPermissions(const std::string &bundleName, const std::string &permissionName) +{ + APP_LOGI( + "GrantReqPermissions bundleName %{public}s, permission %{public}s", bundleName.c_str(), permissionName.c_str()); + return Permission::PermissionKit::GrantSystemGrantedPermission(bundleName, permissionName); +} + +int BundlePermissionMgr::AddUserGrantedReqPermissions( + const std::string &bundleName, const std::vector &permList, const int userId) +{ + APP_LOGI("AddUserGrantedReqPermissions bundleName %{public}s %{public}zu", bundleName.c_str(), permList.size()); + return Permission::PermissionKit::AddUserGrantedReqPermissions(bundleName, permList, userId); +} + +int BundlePermissionMgr::AddSystemGrantedReqPermissions( + const std::string &bundleName, const std::vector &permList) +{ + APP_LOGI("AddSystemGrantedReqPermissions bundleName %{public}s %{public}zu", bundleName.c_str(), permList.size()); + return Permission::PermissionKit::AddSystemGrantedReqPermissions(bundleName, permList); +} + +int BundlePermissionMgr::RemoveDefPermissions(const std::string &bundleName) +{ + APP_LOGI("RemoveDefPermissions bundleName %{public}s", bundleName.c_str()); + return Permission::PermissionKit::RemoveDefPermissions(bundleName); +} + +int BundlePermissionMgr::RemoveUserGrantedReqPermissions(const std::string &bundleName, const int userId) +{ + APP_LOGI("RemoveUserGrantedReqPermissions bundleName %{public}s", bundleName.c_str()); + return Permission::PermissionKit::RemoveUserGrantedReqPermissions(bundleName, userId); +} + +int BundlePermissionMgr::RemoveSystemGrantedReqPermissions(const std::string &bundleName) +{ + APP_LOGI("RemoveSystemGrantedReqPermissions bundleName %{public}s", bundleName.c_str()); + return Permission::PermissionKit::RemoveSystemGrantedReqPermissions(bundleName); +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/bundlemgr/src/bundle_profile.cpp b/services/bundlemgr/src/bundle_profile.cpp new file mode 100644 index 000000000..1b4565204 --- /dev/null +++ b/services/bundlemgr/src/bundle_profile.cpp @@ -0,0 +1,1168 @@ +/* + * 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_profile.h" + +#include +#include + +#include "permission/permission_kit.h" +#include "app_log_wrapper.h" +#include "bundle_constants.h" +#include "common_profile.h" + +namespace OHOS { +namespace AppExecFwk { +namespace ProfileReader { + +const std::map ABILITY_TYPE_MAP = { + {"page", AbilityType::PAGE}, {"service", AbilityType::SERVICE}, {"data", AbilityType::DATA}}; +const std::map DISPLAY_ORIENTATION_MAP = { + {"unspecified", DisplayOrientation::UNSPECIFIED}, + {"landscape", DisplayOrientation::LANDSCAPE}, + {"portrait", DisplayOrientation::PORTRAIT}, + {"followrecent", DisplayOrientation::FOLLOWRECENT}}; +const std::map LAUNCH_MODE_MAP = { + {"singleton", LaunchMode::SINGLETON}, {"singletop", LaunchMode::SINGLETOP}, {"standard", LaunchMode::STANDARD}}; + +struct Version { + int32_t code = 0; + std::string name; +}; + +struct ApiVersion { + uint32_t compatible = 0; + uint32_t target = 0; + std::string releaseType = "Release"; +}; +// config.json app +struct App { + std::string bundleName; + std::string vendor; + Version version; + ApiVersion apiVersion; +}; + +struct ReqVersion { + uint32_t compatible = 0; + uint32_t target = 0; +}; + +struct Ark { + ReqVersion reqVersion; + std::string flag; +}; + +struct Domain { + bool subDomains = false; + std::string name; +}; + +struct DomainSetting { + bool cleartextPermitted = false; + std::vector domains; +}; + +struct SecurityConfig { + DomainSetting domainSetting; +}; + +struct Network { + bool usesCleartext = false; + SecurityConfig securityConfig; +}; + +struct Device { + std::string jointUserId; + std::string process; + bool keepAlive = false; + Ark ark; + bool directLaunch = false; + bool supportBackup = false; + bool compressNativeLibs = true; + Network network; +}; +// config.json deviceConfig +struct DeviceConfig { + Device defaultDevice; + Device phone; + Device tablet; + Device tv; + Device car; + Device wearable; + Device liteWearable; + Device smartVision; +}; + +struct Form { + std::vector formEntity; + int32_t minHeight = 0; + int32_t defaultHeight = 0; + int32_t minWidth = 0; + int32_t defaultWidth = 0; +}; + +struct FormsCustomizeData { + std::string name; + std::string value; +}; + +struct FormsMetaData { + std::vector customizeData; +}; + +struct Forms { + std::string name; + std::string description; + bool isDefault = false; + std::string type; + std::string colorMode = "auto"; + std::vector supportDimensions; + std::string defaultDimension; + std::vector landscapeLayouts; + std::vector portraitLayouts; + bool updateEnabled = false; + std::string scheduledUpateTime = "0:0"; + int32_t updateDuration = 0; + std::string deepLink; + std::string jsComponentName; + FormsMetaData metaData; +}; + +struct UriPermission { + std::string mode; + std::string path; +}; + +struct Ability { + std::string name; + std::string description; + int32_t descriptionId = 0; + std::string icon; + int32_t iconId = 0; + std::string label; + int32_t labelId = 0; + std::string uri; + std::string process; + std::string launchType = "standard"; + std::string theme; + bool visible = false; + std::vector permissions; + std::vector skills; + std::vector deviceCapability; + MetaData metaData; + std::string type; + bool formEnabled = false; + Form form; + std::string orientation = "unspecified"; + std::vector backgroundModes; + bool grantPermission; + UriPermission uriPermission; + std::string readPermission; + std::string writePermission; + bool directLaunch = false; + std::vector configChanges; + std::string mission; + std::string targetAbility; + bool multiUserShared = false; + bool supportPipMode = false; + bool formsEnabled = false; + std::vector formses; +}; + +struct Window { + int32_t designWidth = 750; + bool autoDesignWidth = false; +}; + +struct Js { + std::string name = "default"; + std::vector pages; + Window window; + std::string type = "normal"; +}; + +struct Intent { + std::string targetClass; + std::string targetBundle; +}; + +struct CommonEvent { + std::string name; + std::string permission; + std::vector data; + std::vector type; + std::vector events; +}; + +struct Shortcut { + std::string shortcutId; + std::string label; + std::vector intents; +}; + +// config.json module +struct Module { + std::string package; + std::string name; + std::string description; + std::vector supportedModes; + std::vector reqCapabilities; + std::vector deviceType; + Distro distro; + MetaData metaData; + std::vector abilities; + std::vector jses; + std::vector commonEvents; + std::vector shortcuts; + std::vector defPermissions; + std::vector reqPermissions; +}; + +// config.json +struct ConfigJson { + App app; + DeviceConfig deveicConfig; + Module module; +}; + +/* + * form_json is global static overload method in self namespace ProfileReader, + * which need callback by json library, and can not rename this function, + * so don't named according UpperCamelCase style + */ +void from_json(const nlohmann::json &jsonObject, Version &version) +{ + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(BUNDLE_APP_PROFILE_KEY_CODE) != jsonObjectEnd) { + version.code = jsonObject.at(BUNDLE_APP_PROFILE_KEY_CODE).get(); + } + + if (jsonObject.find(PROFILE_KEY_NAME) != jsonObjectEnd) { + version.name = jsonObject.at(PROFILE_KEY_NAME).get(); + } +} + +void from_json(const nlohmann::json &jsonObject, ApiVersion &apiVersion) +{ + // these are required fields. + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(BUNDLE_APP_PROFILE_KEY_COMPATIBLE) != jsonObjectEnd) { + apiVersion.compatible = jsonObject.at(BUNDLE_APP_PROFILE_KEY_COMPATIBLE).get(); + } + // these are not required fields. + if (jsonObject.find(BUNDLE_APP_PROFILE_KEY_TARGET) != jsonObjectEnd) { + apiVersion.target = jsonObject.at(BUNDLE_APP_PROFILE_KEY_TARGET).get(); + } + + if (jsonObject.find(BUNDLE_APP_PROFILE_KEY_RELEASE_TYPE) != jsonObjectEnd) { + apiVersion.releaseType = jsonObject.at(BUNDLE_APP_PROFILE_KEY_RELEASE_TYPE).get(); + } +} + +void from_json(const nlohmann::json &jsonObject, App &app) +{ + // these are required fields. + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(BUNDLE_APP_PROFILE_KEY_BUNDLE_NAME) != jsonObjectEnd) { + app.bundleName = jsonObject.at(BUNDLE_APP_PROFILE_KEY_BUNDLE_NAME).get(); + } + + if (jsonObject.find(BUNDLE_APP_PROFILE_KEY_VERSION) != jsonObjectEnd) { + app.version = jsonObject.at(BUNDLE_APP_PROFILE_KEY_VERSION).get(); + } + + if (jsonObject.find(BUNDLE_APP_PROFILE_KEY_API_VERSION) != jsonObjectEnd) { + app.apiVersion = jsonObject.at(BUNDLE_APP_PROFILE_KEY_API_VERSION).get(); + } + // these are not required fields. + + if (jsonObject.find(BUNDLE_APP_PROFILE_KEY_VENDOR) != jsonObjectEnd) { + app.vendor = jsonObject.at(BUNDLE_APP_PROFILE_KEY_VENDOR).get(); + } +} + +void from_json(const nlohmann::json &jsonObject, ReqVersion &reqVersion) +{ + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_COMPATIBLE) != jsonObjectEnd) { + reqVersion.compatible = jsonObject.at(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_COMPATIBLE).get(); + } + + if (jsonObject.find(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_TARGET) != jsonObjectEnd) { + reqVersion.target = jsonObject.at(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_TARGET).get(); + } +} + +void from_json(const nlohmann::json &jsonObject, Ark &ark) +{ + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_REQ_VERSION) != jsonObjectEnd) { + ark.reqVersion = jsonObject.at(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_REQ_VERSION).get(); + } + + if (jsonObject.find(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_FLAG) != jsonObjectEnd) { + ark.flag = jsonObject.at(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_FLAG).get(); + } +} + +void from_json(const nlohmann::json &jsonObject, Domain &domain) +{ + // these are not required fields. + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_SUB_DOMAINS) != jsonObjectEnd) { + domain.subDomains = jsonObject.at(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_SUB_DOMAINS).get(); + } + if (jsonObject.find(PROFILE_KEY_NAME) != jsonObjectEnd) { + domain.name = jsonObject.at(PROFILE_KEY_NAME).get(); + } +} + +void from_json(const nlohmann::json &jsonObject, DomainSetting &domainSetting) +{ + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_CLEAR_TEXT_PERMITTED) != jsonObjectEnd) { + domainSetting.cleartextPermitted = + jsonObject.at(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_CLEAR_TEXT_PERMITTED).get(); + } + + if (jsonObject.find(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_DOMAINS) != jsonObjectEnd) { + domainSetting.domains = jsonObject.at(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_DOMAINS).get>(); + } +} + +void from_json(const nlohmann::json &jsonObject, SecurityConfig &securityConfig) +{ + // these are not required fields. + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_DOMAIN_SETTINGS) != jsonObjectEnd) { + securityConfig.domainSetting = + jsonObject.at(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_DOMAIN_SETTINGS).get(); + } +} + +void from_json(const nlohmann::json &jsonObject, Network &network) +{ + // these are not required fields. + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_USES_CLEAR_TEXT) != jsonObjectEnd) { + network.usesCleartext = jsonObject.at(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_USES_CLEAR_TEXT).get(); + } + + if (jsonObject.find(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_SECURITY_CONFIG) != jsonObjectEnd) { + network.securityConfig = jsonObject.at(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_SECURITY_CONFIG).get(); + } +} + +void from_json(const nlohmann::json &jsonObject, Device &device) +{ + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_JOINT_USER_ID) != jsonObjectEnd) { + device.jointUserId = jsonObject.at(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_JOINT_USER_ID).get(); + } + + if (jsonObject.find(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_PROCESS) != jsonObjectEnd) { + device.process = jsonObject.at(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_PROCESS).get(); + } + + if (jsonObject.find(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_KEEP_ALIVE) != jsonObjectEnd) { + device.keepAlive = jsonObject.at(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_KEEP_ALIVE).get(); + } + + if (jsonObject.find(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_ARK) != jsonObjectEnd) { + device.ark = jsonObject.at(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_ARK).get(); + } + + if (jsonObject.find(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_DIRECT_LAUNCH) != jsonObjectEnd) { + device.directLaunch = jsonObject.at(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_DIRECT_LAUNCH).get(); + } + + if (jsonObject.find(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_SUPPORT_BACKUP) != jsonObjectEnd) { + device.supportBackup = jsonObject.at(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_SUPPORT_BACKUP).get(); + } + + if (jsonObject.find(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_COMPRESS_NATIVE_LIBS) != jsonObjectEnd) { + device.compressNativeLibs = jsonObject.at(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_COMPRESS_NATIVE_LIBS).get(); + } + + if (jsonObject.find(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_NETWORK) != jsonObjectEnd) { + device.network = jsonObject.at(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_NETWORK).get(); + } +} + +void from_json(const nlohmann::json &jsonObject, DeviceConfig &deviceConfig) +{ + // these are required fields. + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_DEFAULT) != jsonObjectEnd) { + deviceConfig.defaultDevice = jsonObject.at(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_DEFAULT).get(); + } + // these are not required fields. + if (jsonObject.find(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_PHONE) != jsonObjectEnd) { + deviceConfig.phone = jsonObject.at(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_PHONE).get(); + } + + if (jsonObject.find(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_TABLET) != jsonObjectEnd) { + deviceConfig.tablet = jsonObject.at(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_TABLET).get(); + } + + if (jsonObject.find(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_TV) != jsonObjectEnd) { + deviceConfig.tv = jsonObject.at(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_TV).get(); + } + + if (jsonObject.find(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_CAR) != jsonObjectEnd) { + deviceConfig.car = jsonObject.at(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_CAR).get(); + } + + if (jsonObject.find(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_WEARABLE) != jsonObjectEnd) { + deviceConfig.wearable = jsonObject.at(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_WEARABLE).get(); + } + + if (jsonObject.find(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_LITE_WEARABLE) != jsonObjectEnd) { + deviceConfig.liteWearable = jsonObject.at(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_LITE_WEARABLE).get(); + } + + if (jsonObject.find(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_SMART_VISION) != jsonObjectEnd) { + deviceConfig.smartVision = jsonObject.at(BUNDLE_DEVICE_CONFIG_PROFILE_KEY_SMART_VISION).get(); + } +} + +void from_json(const nlohmann::json &jsonObject, Form &form) +{ + // these are not required fields. + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(BUNDLE_MODULE_PROFILE_FORM_ENTITY) != jsonObjectEnd) { + form.formEntity = jsonObject.at(BUNDLE_MODULE_PROFILE_FORM_ENTITY).get>(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_FORM_MIN_HEIGHT) != jsonObjectEnd) { + form.minHeight = jsonObject.at(BUNDLE_MODULE_PROFILE_FORM_MIN_HEIGHT).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_FORM_DEFAULT_HEIGHT) != jsonObjectEnd) { + form.defaultHeight = jsonObject.at(BUNDLE_MODULE_PROFILE_FORM_DEFAULT_HEIGHT).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_FORM_MIN_WIDTH) != jsonObjectEnd) { + form.minWidth = jsonObject.at(BUNDLE_MODULE_PROFILE_FORM_MIN_WIDTH).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_FORM_DEFAULT_WIDTH) != jsonObjectEnd) { + form.defaultWidth = jsonObject.at(BUNDLE_MODULE_PROFILE_FORM_DEFAULT_WIDTH).get(); + } +} + +void from_json(const nlohmann::json &jsonObject, FormsCustomizeData &customizeDataForms) +{ + // these are not required fields. + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(PROFILE_KEY_NAME) != jsonObjectEnd) { + customizeDataForms.name = jsonObject.at(PROFILE_KEY_NAME).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_FORMS_VALUE) != jsonObjectEnd) { + customizeDataForms.value = jsonObject.at(BUNDLE_MODULE_PROFILE_FORMS_VALUE).get(); + } +} + +void from_json(const nlohmann::json &jsonObject, FormsMetaData &formsMetaData) +{ + // these are not required fields. + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(PROFILE_KEY_NAME) != jsonObjectEnd) { + formsMetaData.customizeData = + jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_CUSTOMIZE_DATA).get>(); + } +} + +void from_json(const nlohmann::json &jsonObject, Forms &forms) +{ + // these are required fields. + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(PROFILE_KEY_NAME) != jsonObjectEnd) { + forms.name = jsonObject.at(PROFILE_KEY_NAME).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_FORMS_IS_DEFAULT) != jsonObjectEnd) { + forms.isDefault = jsonObject.at(BUNDLE_MODULE_PROFILE_FORMS_IS_DEFAULT).get(); + } + + if (jsonObject.find(PROFILE_KEY_TYPE) != jsonObjectEnd) { + forms.type = jsonObject.at(PROFILE_KEY_TYPE).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_FORMS_SUPPORT_DIMENSIONS) != jsonObjectEnd) { + forms.supportDimensions = + jsonObject.at(BUNDLE_MODULE_PROFILE_FORMS_SUPPORT_DIMENSIONS).get>(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_FORMS_DEFAULT_DIMENSION) != jsonObjectEnd) { + forms.defaultDimension = jsonObject.at(BUNDLE_MODULE_PROFILE_FORMS_DEFAULT_DIMENSION).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_FORMS_LANDSCAPE_LAYOUTS) != jsonObjectEnd) { + forms.landscapeLayouts = + jsonObject.at(BUNDLE_MODULE_PROFILE_FORMS_LANDSCAPE_LAYOUTS).get>(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_FORMS_PORTRAIT_LAYOUTS) != jsonObjectEnd) { + forms.portraitLayouts = + jsonObject.at(BUNDLE_MODULE_PROFILE_FORMS_PORTRAIT_LAYOUTS).get>(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_FORMS_UPDATEENABLED) != jsonObjectEnd) { + forms.updateEnabled = jsonObject.at(BUNDLE_MODULE_PROFILE_FORMS_UPDATEENABLED).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_FORMS_JS_COMPONENT_NAME) != jsonObjectEnd) { + forms.jsComponentName = jsonObject.at(BUNDLE_MODULE_PROFILE_FORMS_JS_COMPONENT_NAME).get(); + } + + // these are not required fields. + if (jsonObject.find(PROFILE_KEY_DESCRIPTION) != jsonObjectEnd) { + forms.description = jsonObject.at(PROFILE_KEY_DESCRIPTION).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_FORMS_COLOR_MODE) != jsonObjectEnd) { + forms.colorMode = jsonObject.at(BUNDLE_MODULE_PROFILE_FORMS_COLOR_MODE).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_FORMS_SCHEDULED_UPDATE_TIME) != jsonObjectEnd) { + forms.scheduledUpateTime = jsonObject.at(BUNDLE_MODULE_PROFILE_FORMS_SCHEDULED_UPDATE_TIME).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_FORMS_UPDATE_DURATION) != jsonObjectEnd) { + forms.updateDuration = jsonObject.at(BUNDLE_MODULE_PROFILE_FORMS_UPDATE_DURATION).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_FORMS_DEEP_LINK) != jsonObjectEnd) { + forms.deepLink = jsonObject.at(BUNDLE_MODULE_PROFILE_FORMS_DEEP_LINK).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_META_DATA) != jsonObjectEnd) { + forms.metaData = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_META_DATA).get(); + } +} + +void from_json(const nlohmann::json &jsonObject, UriPermission &uriPermission) +{ + // these are not required fields. + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_MODE) != jsonObjectEnd) { + uriPermission.mode = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_MODE).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_PATH) != jsonObjectEnd) { + uriPermission.path = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_PATH).get(); + } +} + +void from_json(const nlohmann::json &jsonObject, Ability &ability) +{ + // these are required fields. + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(PROFILE_KEY_NAME) != jsonObjectEnd) { + ability.name = jsonObject.at(PROFILE_KEY_NAME).get(); + } + + if (jsonObject.find(PROFILE_KEY_TYPE) != jsonObjectEnd) { + ability.type = jsonObject.at(PROFILE_KEY_TYPE).get(); + } + // these are not required fields. + if (jsonObject.find(PROFILE_KEY_DESCRIPTION) != jsonObjectEnd) { + ability.description = jsonObject.at(PROFILE_KEY_DESCRIPTION).get(); + } + + if (jsonObject.find(PROFILE_KEY_DESCRIPTION_ID) != jsonObjectEnd) { + ability.descriptionId = jsonObject.at(PROFILE_KEY_DESCRIPTION_ID).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_ICON) != jsonObjectEnd) { + ability.icon = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_ICON).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_ICON_ID) != jsonObjectEnd) { + ability.iconId = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_ICON_ID).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_PROCESS) != jsonObjectEnd) { + ability.process = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_PROCESS).get(); + } + + if (jsonObject.find(PROFILE_KEY_LABEL) != jsonObjectEnd) { + ability.label = jsonObject.at(PROFILE_KEY_LABEL).get(); + } + + if (jsonObject.find(PROFILE_KEY_LABEL_ID) != jsonObjectEnd) { + ability.labelId = jsonObject.at(PROFILE_KEY_LABEL_ID).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_URI) != jsonObjectEnd) { + ability.uri = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_URI).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_LAUNCH_TYPE) != jsonObjectEnd) { + ability.launchType = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_LAUNCH_TYPE).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_LAUNCH_THEME) != jsonObjectEnd) { + ability.theme = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_LAUNCH_THEME).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_VISIBLE) != jsonObjectEnd) { + ability.visible = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_VISIBLE).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_PERMISSIONS) != jsonObjectEnd) { + ability.permissions = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_PERMISSIONS).get>(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_SKILLS) != jsonObjectEnd) { + ability.skills = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_SKILLS).get>(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_DEVICE_CAP_ABILITY) != jsonObjectEnd) { + ability.deviceCapability = + jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_DEVICE_CAP_ABILITY).get>(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_META_DATA) != jsonObjectEnd) { + ability.metaData = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_META_DATA).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_FORM_ENABLED) != jsonObjectEnd) { + ability.formEnabled = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_FORM_ENABLED).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_FORM) != jsonObjectEnd) { + ability.form = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_FORM).get
(); + } + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_ORIENTATION) != jsonObjectEnd) { + ability.orientation = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_ORIENTATION).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_BACKGROUND_MODES) != jsonObjectEnd) { + ability.backgroundModes = + jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_BACKGROUND_MODES).get>(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_GRANT_PERMISSION) != jsonObjectEnd) { + ability.grantPermission = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_GRANT_PERMISSION).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_URI_PERMISSION) != jsonObjectEnd) { + ability.uriPermission = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_URI_PERMISSION).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_READ_PERMISSION) != jsonObjectEnd) { + ability.readPermission = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_READ_PERMISSION).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_WRITE_PERMISSION) != jsonObjectEnd) { + ability.writePermission = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_WRITE_PERMISSION).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_DIRECT_LAUNCH) != jsonObjectEnd) { + ability.directLaunch = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_DIRECT_LAUNCH).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_CONFIG_CHANGES) != jsonObjectEnd) { + ability.configChanges = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_CONFIG_CHANGES).get>(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_MISSION) != jsonObjectEnd) { + ability.mission = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_MISSION).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_TARGET_ABILITY) != jsonObjectEnd) { + ability.targetAbility = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_TARGET_ABILITY).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_MULTIUSER_SHARED) != jsonObjectEnd) { + ability.multiUserShared = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_MULTIUSER_SHARED).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_SUPPORT_PIP_MODE) != jsonObjectEnd) { + ability.supportPipMode = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_SUPPORT_PIP_MODE).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_FORMS_ENABLED) != jsonObjectEnd) { + ability.formsEnabled = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_FORMS_ENABLED).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_FORMS) != jsonObjectEnd) { + ability.formses = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_FORMS).get>(); + } +} + +void from_json(const nlohmann::json &jsonObject, Window &window) +{ + // these are not required fields. + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_DESIGN_WIDTH) != jsonObjectEnd) { + window.designWidth = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_DESIGN_WIDTH).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_AUTO_DESIGN_WIDTH) != jsonObjectEnd) { + window.autoDesignWidth = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_AUTO_DESIGN_WIDTH).get(); + } +} + +void from_json(const nlohmann::json &jsonObject, Js &js) +{ + // these are required fields. + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(PROFILE_KEY_NAME) != jsonObjectEnd) { + js.name = jsonObject.at(PROFILE_KEY_NAME).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_PAGES) != jsonObjectEnd) { + js.pages = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_PAGES).get>(); + } + // these are not required fields. + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_WINDOW) != jsonObjectEnd) { + js.window = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_WINDOW).get(); + } + + if (jsonObject.find(PROFILE_KEY_TYPE) != jsonObjectEnd) { + js.type = jsonObject.at(PROFILE_KEY_TYPE).get(); + } +} + +void from_json(const nlohmann::json &jsonObject, Intent &intent) +{ + // these are not required fields. + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_TARGET_CLASS) != jsonObjectEnd) { + intent.targetClass = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_TARGET_CLASS).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_TARGET_BUNDLE) != jsonObjectEnd) { + intent.targetBundle = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_TARGET_BUNDLE).get(); + } +} + +void from_json(const nlohmann::json &jsonObject, CommonEvent &commonEvent) +{ + // these are required fields. + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(PROFILE_KEY_NAME) != jsonObjectEnd) { + commonEvent.name = jsonObject.at(PROFILE_KEY_NAME).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_EVENTS) != jsonObjectEnd) { + commonEvent.events = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_EVENTS).get>(); + } + // these are not required fields. + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_PERMISSION) != jsonObjectEnd) { + commonEvent.permission = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_PERMISSION).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_DATA) != jsonObjectEnd) { + commonEvent.data = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_DATA).get>(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_TYPE) != jsonObjectEnd) { + commonEvent.type = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_TYPE).get>(); + } +} + +void from_json(const nlohmann::json &jsonObject, Shortcut &shortcut) +{ + // these are required fields. + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_SHORTCUT_ID) != jsonObjectEnd) { + shortcut.shortcutId = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_SHORTCUT_ID).get(); + } + // these are not required fields. + + if (jsonObject.find(PROFILE_KEY_LABEL) != jsonObjectEnd) { + shortcut.label = jsonObject.at(PROFILE_KEY_LABEL).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_SHORTCUT_INTENTS) != jsonObjectEnd) { + shortcut.intents = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_SHORTCUT_INTENTS).get>(); + } +} + +void from_json(const nlohmann::json &jsonObject, Module &module) +{ + // these are required fields. + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_PACKAGE) != jsonObjectEnd) { + module.package = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_PACKAGE).get(); + } + + if (jsonObject.find(PROFILE_KEY_NAME) != jsonObjectEnd) { + module.name = jsonObject.at(PROFILE_KEY_NAME).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_DEVICE_TYPE) != jsonObjectEnd) { + module.deviceType = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_DEVICE_TYPE).get>(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_DISTRO) != jsonObjectEnd) { + module.distro = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_DISTRO).get(); + } + + // these are not required fields. + if (jsonObject.find(PROFILE_KEY_DESCRIPTION) != jsonObjectEnd) { + module.description = jsonObject.at(PROFILE_KEY_DESCRIPTION).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_SUPPORTED_MODES) != jsonObjectEnd) { + module.supportedModes = + jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_SUPPORTED_MODES).get>(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_REQ_CAPABILITIES) != jsonObjectEnd) { + module.reqCapabilities = + jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_REQ_CAPABILITIES).get>(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_META_DATA) != jsonObjectEnd) { + module.metaData = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_META_DATA).get(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_ABILITIES) != jsonObjectEnd) { + module.abilities = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_ABILITIES).get>(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_JS) != jsonObjectEnd) { + module.jses = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_JS).get>(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_COMMON_EVENTS) != jsonObjectEnd) { + module.commonEvents = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_COMMON_EVENTS).get>(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_SHORTCUTS) != jsonObjectEnd) { + module.shortcuts = jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_SHORTCUTS).get>(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS) != jsonObjectEnd) { + module.defPermissions = + jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS).get>(); + } + + if (jsonObject.find(BUNDLE_MODULE_PROFILE_KEY_REQ_PERMISSIONS) != jsonObjectEnd) { + module.reqPermissions = + jsonObject.at(BUNDLE_MODULE_PROFILE_KEY_REQ_PERMISSIONS).get>(); + } +} + +void from_json(const nlohmann::json &jsonObject, ConfigJson &configJson) +{ + // Because it does not support exceptions, every element needs to be searched first + APP_LOGI("read 'app' tag from config.json"); + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(BUNDLE_PROFILE_KEY_APP) != jsonObjectEnd) { + configJson.app = jsonObject.at(BUNDLE_PROFILE_KEY_APP).get(); + } + APP_LOGI("read 'device' tag from config.json"); + if (jsonObject.find(BUNDLE_PROFILE_KEY_DEVICE_CONFIG) != jsonObjectEnd) { + configJson.deveicConfig = jsonObject.at(BUNDLE_PROFILE_KEY_DEVICE_CONFIG).get(); + } + APP_LOGI("read 'module' tag from config.json"); + if (jsonObject.find(BUNDLE_PROFILE_KEY_MODULE) != jsonObjectEnd) { + configJson.module = jsonObject.at(BUNDLE_PROFILE_KEY_MODULE).get(); + } +} + +} // namespace ProfileReader + +namespace { + +bool CheckBundleNameIsValid(const std::string &bundleName) +{ + if (bundleName.empty()) { + return false; + } + if (bundleName.size() < Constants::MIN_BUNDLE_NAME || bundleName.size() > Constants::MAX_BUNDLE_NAME) { + return false; + } + char head = bundleName.at(0); + if (head < 'A' || ('Z' < head && head < 'a') || head > 'z') { + return false; + } + for (const auto &c : bundleName) { + if (c < '.' || c == '/' || ('9' < c && c < 'A') || ('Z' < c && c < '_') || c == '`' || c > 'z') { + return false; + } + } + return true; +} + +bool CheckModuleInfosIsValid(ProfileReader::ConfigJson &configJson) +{ + if (configJson.module.deviceType.empty()) { + APP_LOGE("module deviceType invalid"); + return false; + } + if (!configJson.module.abilities.empty()) { + for (const auto &ability : configJson.module.abilities) { + if (ability.name.empty() || ability.type.empty()) { + APP_LOGE("ability name or type invalid"); + return false; + } + } + } + if (configJson.app.version.code <= 0) { + APP_LOGE("version code invalid"); + return false; + } + auto iter = + std::find_if(configJson.module.deviceType.begin(), configJson.module.deviceType.end(), [](const auto &d) { + return ((d.compare(ProfileReader::BUNDLE_DEVICE_CONFIG_PROFILE_KEY_LITE_WEARABLE) == 0 || + d.compare(ProfileReader::BUNDLE_DEVICE_CONFIG_PROFILE_KEY_SMART_VISION) == 0)); + }); + if (iter != configJson.module.deviceType.end()) { + APP_LOGE("this is a lite device app, ignores other check"); + // if lite device hap doesn't have a module package name, assign it as bundle name. + if (configJson.module.package.empty()) { + configJson.module.package = configJson.app.bundleName; + } + return true; + } + if (configJson.module.package.empty()) { + APP_LOGE("module package invalid"); + return false; + } + if (configJson.module.name.empty()) { + APP_LOGE("module name invalid"); + return false; + } + if (configJson.module.distro.moduleName.empty()) { + APP_LOGE("module distro invalid"); + return false; + } + return true; +} + +bool TransformToInfo(const ProfileReader::ConfigJson &configJson, ApplicationInfo &applicationInfo) +{ + applicationInfo.name = configJson.app.bundleName; + applicationInfo.bundleName = configJson.app.bundleName; + applicationInfo.deviceId = Constants::CURRENT_DEVICE_ID; + applicationInfo.isLauncherApp = false; + auto it = find(configJson.module.supportedModes.begin(), configJson.module.supportedModes.end(), "drive"); + if (it != configJson.module.supportedModes.end()) { + applicationInfo.supportedModes = 1; + } else { + applicationInfo.supportedModes = 0; + } + applicationInfo.process = configJson.deveicConfig.defaultDevice.process; + return true; +} + +bool TransformToInfo(const ProfileReader::ConfigJson &configJson, BundleInfo &bundleInfo) +{ + bundleInfo.name = configJson.app.bundleName; + bundleInfo.vendor = configJson.app.vendor; + bundleInfo.versionCode = static_cast(configJson.app.version.code); + bundleInfo.versionName = configJson.app.version.name; + bundleInfo.jointUserId = configJson.deveicConfig.defaultDevice.jointUserId; + bundleInfo.minSdkVersion = configJson.deveicConfig.defaultDevice.ark.reqVersion.compatible; + if (configJson.deveicConfig.defaultDevice.ark.reqVersion.target == Constants::EQUAL_ZERO) { + bundleInfo.maxSdkVersion = bundleInfo.minSdkVersion; + } else { + bundleInfo.minSdkVersion = configJson.deveicConfig.defaultDevice.ark.reqVersion.target; + } + bundleInfo.compatibleVersion = configJson.app.apiVersion.compatible; + bundleInfo.targetVersion = configJson.app.apiVersion.target; + bundleInfo.releaseType = configJson.app.apiVersion.releaseType; + bundleInfo.isKeepAlive = configJson.deveicConfig.defaultDevice.keepAlive; + if (configJson.module.abilities.size() > 0) { + bundleInfo.label = configJson.module.abilities[0].label; + } + if (configJson.module.distro.moduleType == ProfileReader::MODULE_DISTRO_MODULE_TYPE_VALUE_ENTRY) { + bundleInfo.description = configJson.module.description; + } + return true; +} + +bool TransformToInfo(const ProfileReader::ConfigJson &configJson, InnerModuleInfo &innerModuleInfo) +{ + innerModuleInfo.modulePackage = configJson.module.package; + innerModuleInfo.moduleName = configJson.module.name; + innerModuleInfo.description = configJson.module.description; + innerModuleInfo.metaData = configJson.module.metaData; + innerModuleInfo.distro = configJson.module.distro; + innerModuleInfo.reqCapabilities = configJson.module.reqCapabilities; + innerModuleInfo.defPermissions = configJson.module.defPermissions; + innerModuleInfo.reqPermissions = configJson.module.reqPermissions; + return true; +} + +bool TransformToInfo( + const ProfileReader::ConfigJson &configJson, const ProfileReader::Ability &ability, AbilityInfo &abilityInfo) +{ + abilityInfo.name = ability.name; + abilityInfo.label = ability.label; + abilityInfo.description = ability.description; + abilityInfo.iconPath = ability.icon; + abilityInfo.visible = ability.visible; + abilityInfo.kind = ability.type; + 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; }); + if (iterType != ProfileReader::ABILITY_TYPE_MAP.end()) { + abilityInfo.type = iterType->second; + } else { + return false; + } + + auto iterOrientation = std::find_if(std::begin(ProfileReader::DISPLAY_ORIENTATION_MAP), + std::end(ProfileReader::DISPLAY_ORIENTATION_MAP), + [&ability](const auto &item) { return item.first == ability.orientation; }); + if (iterOrientation != ProfileReader::DISPLAY_ORIENTATION_MAP.end()) { + abilityInfo.orientation = iterOrientation->second; + } + + auto iterLaunch = std::find_if(std::begin(ProfileReader::LAUNCH_MODE_MAP), + std::end(ProfileReader::LAUNCH_MODE_MAP), + [&ability](const auto &item) { return item.first == ability.launchType; }); + if (iterLaunch != ProfileReader::LAUNCH_MODE_MAP.end()) { + abilityInfo.launchMode = iterLaunch->second; + } + + for (const auto &permission : ability.permissions) { + abilityInfo.permissions.emplace_back(permission); + } + abilityInfo.process = (ability.process.empty()) ? configJson.deveicConfig.defaultDevice.process : ability.process; + abilityInfo.deviceTypes = configJson.module.deviceType; + abilityInfo.deviceCapabilities = ability.deviceCapability; + abilityInfo.uri = ability.uri; + abilityInfo.package = configJson.module.package; + abilityInfo.bundleName = configJson.app.bundleName; + abilityInfo.moduleName = configJson.module.name; + abilityInfo.applicationName = configJson.app.bundleName; + return true; +} + +bool TransformToInfo(ProfileReader::ConfigJson &configJson, InnerBundleInfo &innerBundleInfo) +{ + APP_LOGD("transform profile configJson to innerBundleInfo"); + if (!CheckBundleNameIsValid(configJson.app.bundleName)) { + APP_LOGE("bundle name is valid"); + return false; + } + if (!CheckModuleInfosIsValid(configJson)) { + APP_LOGE("module infos is valid"); + return false; + } + ApplicationInfo applicationInfo; + TransformToInfo(configJson, applicationInfo); + applicationInfo.isSystemApp = (innerBundleInfo.GetAppType() == Constants::AppType::SYSTEM_APP) ? true : false; + + BundleInfo bundleInfo; + TransformToInfo(configJson, bundleInfo); + + InnerModuleInfo innerModuleInfo; + TransformToInfo(configJson, innerModuleInfo); + + bool find = false; + for (const auto &ability : configJson.module.abilities) { + AbilityInfo abilityInfo; + if (!TransformToInfo(configJson, ability, abilityInfo)) { + APP_LOGE("ability type is valid"); + return false; + } + std::string keyName = configJson.app.bundleName + configJson.module.package + abilityInfo.name; + innerModuleInfo.abilityKeys.emplace_back(keyName); + innerModuleInfo.skillKeys.emplace_back(keyName); + innerBundleInfo.InsertSkillInfo(keyName, ability.skills); + if (!find) { + for (const auto &skill : ability.skills) { + if (std::find(skill.actions.begin(), skill.actions.end(), Constants::INTENT_ACTION_HOME) != + skill.actions.end() && + std::find(skill.entities.begin(), skill.entities.end(), Constants::INTENT_ENTITY_HOME) != + skill.entities.end() && + (find == false)) { + innerBundleInfo.SetMainAbility(keyName); + innerBundleInfo.SetMainAbilityName(ability.name); + // if there is main ability, it's label will be the application's label + applicationInfo.label = ability.label; + applicationInfo.labelId = ability.labelId; + applicationInfo.iconPath = ability.icon; + applicationInfo.iconId = ability.iconId; + applicationInfo.description = ability.description; + applicationInfo.descriptionId = ability.descriptionId; + find = true; + } + if (std::find(skill.entities.begin(), + skill.entities.end(), + Constants::FLAG_HW_HOME_INTENT_FROM_SYSTEM) != skill.entities.end()) { + applicationInfo.isLauncherApp = true; + abilityInfo.isLauncherAbility = true; + } + } + } + if (configJson.module.jses.empty()) { + bundleInfo.isNativeApp = true; + abilityInfo.isNativeAbility = true; + } + innerBundleInfo.InsertAbilitiesInfo(keyName, abilityInfo); + } + + if (configJson.module.distro.moduleType == ProfileReader::MODULE_DISTRO_MODULE_TYPE_VALUE_ENTRY) { + innerBundleInfo.SetHasEntry(true); + innerModuleInfo.isEntry = true; + } + innerBundleInfo.SetIsSupportBackup(configJson.deveicConfig.defaultDevice.supportBackup); + innerBundleInfo.SetCurrentModulePackage(configJson.module.package); + innerBundleInfo.SetBaseApplicationInfo(applicationInfo); + innerBundleInfo.SetBaseBundleInfo(bundleInfo); + innerBundleInfo.InsertInnerModuleInfo(configJson.module.package, innerModuleInfo); + return true; +} + +} // namespace + +ErrCode BundleProfile::TransformTo(const std::ostringstream &source, InnerBundleInfo &innerBundleInfo) const +{ + APP_LOGI("transform profile stream to bundle info"); + if (source.str().size() == 0) { + return ERR_APPEXECFWK_PARSE_BAD_PROFILE; + } + + ProfileReader::ConfigJson configJson; + try { + nlohmann::json jsonObject = nlohmann::json::parse(source.str()); + configJson = jsonObject.get(); + } catch (nlohmann::detail::parse_error &exception) { + APP_LOGE("has a parse_error:%{public}s", exception.what()); + return ERR_APPEXECFWK_PARSE_BAD_PROFILE; + } catch (nlohmann::detail::type_error &exception) { + APP_LOGE("has a type_error:%{public}s", exception.what()); + return ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR; + } catch (nlohmann::detail::out_of_range &exception) { + APP_LOGE("has an out_of_range exception:%{public}s", exception.what()); + return ERR_APPEXECFWK_PARSE_PROFILE_MISSING_PROP; + } catch (...) { + APP_LOGE("has an other exception"); + return ERR_APPEXECFWK_PARSE_PROFILE_MISSING_PROP; + } + + if (!TransformToInfo(configJson, innerBundleInfo)) { + return ERR_APPEXECFWK_PARSE_BAD_PROFILE; + } + return ERR_OK; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/bundlemgr/src/bundle_scanner.cpp b/services/bundlemgr/src/bundle_scanner.cpp new file mode 100755 index 000000000..2d7a6e258 --- /dev/null +++ b/services/bundlemgr/src/bundle_scanner.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 "bundle_scanner.h" + +#include +#include +#include + +#include "datetime_ex.h" +#include "string_ex.h" +#include "app_log_wrapper.h" +#include "perf_profile.h" +#include "bundle_util.h" +#include "bundle_constants.h" +#include "bundle_mgr_service.h" + +namespace OHOS { +namespace AppExecFwk { + +BundleScanner::BundleScanner() +{ + APP_LOGI("BundleScanner instance is created"); +} + +BundleScanner::~BundleScanner() +{ + APP_LOGI("BundleScanner instance is destroyed"); +} + +const std::list &BundleScanner::Scan(const std::string &dirPath) +{ + PerfProfile::GetInstance().SetBundleScanStartTime(GetTickCount()); + + APP_LOGD("path:%{private}s", dirPath.c_str()); + if (!dirPath.empty()) { + if (!ScanImpl(dirPath)) { + APP_LOGW("BundleScanner::Scan scan error"); + } + } + + APP_LOGD("scan result num:%{public}zu", entries_.size()); + for (const auto &item : entries_) { + APP_LOGD("app item:%{private}s", item.c_str()); + } + + PerfProfile::GetInstance().SetBundleScanEndTime(GetTickCount()); + return entries_; +} + +bool BundleScanner::ScanImpl(const std::string &dirPath) +{ + DIR *dirp = opendir(dirPath.c_str()); + if (dirp == nullptr) { + APP_LOGE("BundleScanner::ScanImpl open dir:%{private}s fail", dirPath.c_str()); + return false; + } + + struct dirent *dirent = nullptr; + for (;;) { + dirent = readdir(dirp); + if (dirent == nullptr) { + break; + } + + std::string currentName(dirent->d_name); + APP_LOGD("folder found:'%{private}s'", dirent->d_name); + if (currentName.compare(".") == 0 || currentName.compare("..") == 0) { + continue; + } + + if (BundleUtil::CheckFileType(currentName, Constants::INSTALL_FILE_SUFFIX)) { + entries_.push_back(dirPath + Constants::PATH_SEPARATOR + currentName); + } + } + + if (closedir(dirp) == -1) { + APP_LOGW("close dir fail"); + } + return true; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/bundlemgr/src/bundle_status_callback_death_recipient.cpp b/services/bundlemgr/src/bundle_status_callback_death_recipient.cpp new file mode 100644 index 000000000..540eeb012 --- /dev/null +++ b/services/bundlemgr/src/bundle_status_callback_death_recipient.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 "bundle_status_callback_death_recipient.h" + +#include "app_log_wrapper.h" +#include "singleton.h" +#include "bundle_mgr_service.h" +#include "bundle_status_callback_interface.h" + +namespace OHOS { +namespace AppExecFwk { + +BundleStatusCallbackDeathRecipient::BundleStatusCallbackDeathRecipient() +{ + APP_LOGI("create BundleStatusCallbackDeathRecipient instance"); +} + +BundleStatusCallbackDeathRecipient::~BundleStatusCallbackDeathRecipient() +{ + APP_LOGI("destroy BundleStatusCallbackDeathRecipient instance"); +} + +void BundleStatusCallbackDeathRecipient::OnRemoteDied(const wptr &remote) +{ + APP_LOGI("bundle status service died, remove the proxy object"); + sptr callback = iface_cast(remote.promote()); + APP_LOGI("bundle status service died"); + if (!callback) { + APP_LOGE("callback is nullptr"); + return; + } + auto dataMgr = DelayedSingleton::GetInstance()->GetDataMgr(); + if (dataMgr == nullptr) { + APP_LOGE("DataMgr is nullptr"); + return; + } + dataMgr->ClearBundleStatusCallback(callback); +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/bundlemgr/src/bundle_util.cpp b/services/bundlemgr/src/bundle_util.cpp new file mode 100644 index 000000000..001c09d9b --- /dev/null +++ b/services/bundlemgr/src/bundle_util.cpp @@ -0,0 +1,80 @@ +/* + * 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_util.h" + +#include + +#include "string_ex.h" +#include "directory_ex.h" +#include "app_log_wrapper.h" +#include "bundle_constants.h" + +namespace OHOS { +namespace AppExecFwk { + +ErrCode BundleUtil::CheckFilePath(const std::string &bundlePath, std::string &realPath) +{ + if (!CheckFileName(bundlePath)) { + APP_LOGE("bundle file path invalid"); + return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID; + } + if (!CheckFileType(bundlePath, Constants::INSTALL_FILE_SUFFIX)) { + APP_LOGE("file is not hap"); + return ERR_APPEXECFWK_INSTALL_INVALID_HAP_NAME; + } + if (!PathToRealPath(bundlePath, realPath)) { + APP_LOGE("file is not real path"); + return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID; + } + if (access(realPath.c_str(), F_OK) != 0) { + APP_LOGE("can not access the bundle file path: %{private}s", realPath.c_str()); + return ERR_APPEXECFWK_INSTALL_INVALID_BUNDLE_FILE; + } + return ERR_OK; +} + +bool BundleUtil::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()); + if (!CheckFileName(fileName)) { + return false; + } + + auto position = fileName.rfind('.'); + if (position == std::string::npos) { + APP_LOGE("filename no extension name"); + return false; + } + + std::string suffixStr = fileName.substr(position); + return LowerStr(suffixStr) == extensionName; +} + +bool BundleUtil::CheckFileName(const std::string &fileName) +{ + if (fileName.empty()) { + APP_LOGE("the file name is empty"); + return false; + } + if (fileName.size() > Constants::PATH_MAX_SIZE) { + APP_LOGE("bundle file path length %{public}zu too long", fileName.size()); + return false; + } + return true; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/bundlemgr/src/bundle_verify_mgr.cpp b/services/bundlemgr/src/bundle_verify_mgr.cpp new file mode 100644 index 000000000..e119888b6 --- /dev/null +++ b/services/bundlemgr/src/bundle_verify_mgr.cpp @@ -0,0 +1,36 @@ +/* + * 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_verify_mgr.h" + +#include "ipc_skeleton.h" +#include "interfaces/hap_verify.h" +#include "app_log_wrapper.h" +#include "bundle_constants.h" + +namespace OHOS { +namespace AppExecFwk { + +using namespace OHOS::Security; + +bool BundleVerifyMgr::HapVerify(const std::string &filePath, Verify::HapVerifyResult &hapVerifyResult) +{ + auto ret = Verify::HapVerify(filePath, hapVerifyResult); + APP_LOGI("HapVerify result %{public}d", ret); + return ret == Verify::HapVerifyResultCode::VERIFY_SUCCESS; +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/bundlemgr/src/inner_bundle_info.cpp b/services/bundlemgr/src/inner_bundle_info.cpp new file mode 100644 index 000000000..090ea0d93 --- /dev/null +++ b/services/bundlemgr/src/inner_bundle_info.cpp @@ -0,0 +1,709 @@ +/* + * 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 "inner_bundle_info.h" + +#include "app_log_wrapper.h" +#include "common_profile.h" + +namespace OHOS { +namespace AppExecFwk { +namespace { + +const std::string IS_SUPPORT_BACKUP = "isSupportBackup"; +const std::string APP_TYPE = "appType"; +const std::string UID = "uid"; +const std::string GID = "gid"; +const std::string BASE_DATA_DIR = "baseDataDir"; +const std::string BUNDLE_STATUS = "bundleStatus"; +const std::string BASE_APPLICATION_INFO = "baseApplicationInfo"; +const std::string BASE_BUNDLE_INFO = "baseBundleInfo"; +const std::string BASE_ABILITY_INFO = "baseAbilityInfos"; +const std::string INNER_MODULE_INFO = "innerModuleInfos"; +const std::string MAIN_ABILITY = "mainAbility"; +const std::string SKILL_INFOS = "skillInfos"; +const std::string USER_ID = "userId_"; +const std::string IS_KEEP_DATA = "isKeepData"; +const std::string PROVISION_ID = "provisionId"; +const std::string APP_FEATURE = "appFeature"; +const std::string HAS_ENTRY = "hasEntry"; +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_IS_ENTRY = "isEntry"; +const std::string MODULE_METADATA = "metaData"; +const std::string MODULE_DISTRO = "distro"; +const std::string MODULE_REQ_CAPABILITIES = "reqCapabilities"; +const std::string MODULE_REQ_PERMS = "reqPermissions"; +const std::string MODULE_DEF_PERMS = "defPermissions"; +const std::string MODULE_DATA_DIR = "moduleDataDir"; +const std::string MODULE_RES_PATH = "moduleResPath"; +const std::string MODULE_ABILITY_KEYS = "abilityKeys"; +const std::string MODULE_SKILL_KEYS = "skillKeys"; + +} // namespace + +InnerBundleInfo::InnerBundleInfo() +{ + APP_LOGD("inner bundle info instance is created"); +} + +InnerBundleInfo::~InnerBundleInfo() +{ + APP_LOGD("inner bundle info instance is destroyed"); +} + +void to_json(nlohmann::json &jsonObject, const CustomizeData &customizeData) +{ + jsonObject = nlohmann::json{ + {ProfileReader::PROFILE_KEY_NAME, customizeData.name}, + {ProfileReader::BUNDLE_MODULE_META_KEY_EXTRA, customizeData.extra}, + {ProfileReader::BUNDLE_MODULE_META_KEY_VALUE, customizeData.value} + }; +} + +void to_json(nlohmann::json &jsonObject, const Parameters ¶meters) +{ + jsonObject = nlohmann::json{ + {ProfileReader::BUNDLE_MODULE_PROFILE_KEY_TYPE, parameters.type}, + {ProfileReader::PROFILE_KEY_DESCRIPTION, parameters.description}, + {ProfileReader::PROFILE_KEY_NAME, parameters.name} + }; +} + +void to_json(nlohmann::json &jsonObject, const Results &results) +{ + jsonObject = nlohmann::json{ + {ProfileReader::BUNDLE_MODULE_PROFILE_KEY_TYPE, results.type}, + {ProfileReader::PROFILE_KEY_DESCRIPTION, results.description}, + {ProfileReader::PROFILE_KEY_NAME, results.name} + }; +} + +void to_json(nlohmann::json &jsonObject, const MetaData &metaData) +{ + jsonObject = nlohmann::json{ + {ProfileReader::BUNDLE_MODULE_META_KEY_CUSTOMIZE_DATA, metaData.customizeData}, + {ProfileReader::BUNDLE_MODULE_META_KEY_PARAMETERS, metaData.parameters}, + {ProfileReader::BUNDLE_MODULE_META_KEY_RESULTS, metaData.results} + }; +} + +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} + }; +} + +void to_json(nlohmann::json &jsonObject, const UsedScene &usedScene) +{ + jsonObject = nlohmann::json{ + {ProfileReader::BUNDLE_MODULE_PROFILE_KEY_REQ_PERMISSIONS_ABILITY, usedScene.ability}, + {ProfileReader::BUNDLE_MODULE_PROFILE_KEY_REQ_PERMISSIONS_WHEN, usedScene.when} + }; +} + +void to_json(nlohmann::json &jsonObject, const ReqPermission &reqPermission) +{ + jsonObject = nlohmann::json{ + {ProfileReader::BUNDLE_MODULE_PROFILE_KEY_REQ_PERMISSIONS_NAME, reqPermission.name}, + {ProfileReader::BUNDLE_MODULE_PROFILE_KEY_REQ_PERMISSIONS_REASON, reqPermission.reason}, + {ProfileReader::BUNDLE_MODULE_PROFILE_KEY_REQ_PERMISSIONS_USEDSCENE, reqPermission.usedScene} + }; +} + +void to_json(nlohmann::json &jsonObject, const DefPermission &defPermission) +{ + jsonObject = nlohmann::json{ + {ProfileReader::BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_NAME, defPermission.name}, + {ProfileReader::BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_GRANTMODE, defPermission.grantMode}, + {ProfileReader::BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_AVAILABLESCOPE, defPermission.availableScope}, + {ProfileReader::BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_LABEL, defPermission.label}, + {ProfileReader::BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_LABEL_ID, defPermission.labelId}, + {ProfileReader::BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_DESCRIPTION, defPermission.description}, + {ProfileReader::BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_DESCRIPTION_ID, defPermission.descriptionId} + }; +} + +void to_json(nlohmann::json &jsonObject, const InnerModuleInfo &info) +{ + jsonObject = nlohmann::json{ + {MODULE_PACKAGE, info.modulePackage}, + {MODULE_NAME, info.moduleName}, + {MODULE_PATH, info.modulePath}, + {MODULE_DATA_DIR, info.moduleDataDir}, + {MODULE_RES_PATH, info.moduleResPath}, + {MODULE_IS_ENTRY, info.isEntry}, + {MODULE_METADATA, info.metaData}, + {MODULE_DISTRO, info.distro}, + {MODULE_DESCRIPTION, info.description}, + {MODULE_REQ_CAPABILITIES, info.reqCapabilities}, + {MODULE_REQ_PERMS, info.reqPermissions}, + {MODULE_DEF_PERMS, info.defPermissions}, + {MODULE_ABILITY_KEYS, info.abilityKeys}, + {MODULE_SKILL_KEYS, info.skillKeys} + }; +} + +void to_json(nlohmann::json &jsonObject, const SkillUri &uri) +{ + jsonObject = nlohmann::json{ + {ProfileReader::BUNDLE_MODULE_PROFILE_KEY_SCHEME, uri.scheme}, + {ProfileReader::BUNDLE_MODULE_PROFILE_KEY_HOST, uri.host}, + {ProfileReader::BUNDLE_MODULE_PROFILE_KEY_PORT, uri.port}, + {ProfileReader::BUNDLE_MODULE_PROFILE_KEY_PATH, uri.path}, + {ProfileReader::BUNDLE_MODULE_PROFILE_KEY_TYPE, uri.type} + }; +} + +void to_json(nlohmann::json &jsonObject, const Skill &skill) +{ + jsonObject = nlohmann::json{ + {ProfileReader::BUNDLE_MODULE_PROFILE_KEY_ACTIONS, skill.actions}, + {ProfileReader::BUNDLE_MODULE_PROFILE_KEY_ENTITIES, skill.entities}, + {ProfileReader::BUNDLE_MODULE_PROFILE_KEY_URIS, skill.uris} + }; +} + +void InnerBundleInfo::ToJson(nlohmann::json &jsonObject) const +{ + jsonObject[IS_SUPPORT_BACKUP] = isSupportBackup_; + jsonObject[APP_TYPE] = appType_; + jsonObject[UID] = uid_; + jsonObject[GID] = gid_; + jsonObject[BASE_DATA_DIR] = baseDataDir_; + jsonObject[BUNDLE_STATUS] = bundleStatus_; + jsonObject[BASE_APPLICATION_INFO] = baseApplicationInfo_; + jsonObject[BASE_BUNDLE_INFO] = baseBundleInfo_; + jsonObject[BASE_ABILITY_INFO] = baseAbilityInfos_; + jsonObject[INNER_MODULE_INFO] = innerModuleInfos_; + jsonObject[SKILL_INFOS] = skillInfos_; + jsonObject[IS_KEEP_DATA] = isKeepData_; + jsonObject[USER_ID] = userId_; + jsonObject[MAIN_ABILITY] = mainAbility_; + jsonObject[PROVISION_ID] = provisionId_; + jsonObject[APP_FEATURE] = appFeature_; + jsonObject[HAS_ENTRY] = hasEntry_; +} + +void from_json(const nlohmann::json &jsonObject, InnerModuleInfo &info) +{ + // these are not required fields. + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(MODULE_PACKAGE) != jsonObjectEnd) { + info.modulePackage = jsonObject.at(MODULE_PACKAGE).get(); + } + if (jsonObject.find(MODULE_NAME) != jsonObjectEnd) { + info.moduleName = jsonObject.at(MODULE_NAME).get(); + } + if (jsonObject.find(MODULE_PATH) != jsonObjectEnd) { + info.modulePath = jsonObject.at(MODULE_PATH).get(); + } + if (jsonObject.find(MODULE_DATA_DIR) != jsonObjectEnd) { + info.moduleDataDir = jsonObject.at(MODULE_DATA_DIR).get(); + } + if (jsonObject.find(MODULE_RES_PATH) != jsonObjectEnd) { + info.moduleResPath = jsonObject.at(MODULE_RES_PATH).get(); + } + if (jsonObject.find(MODULE_IS_ENTRY) != jsonObjectEnd) { + info.isEntry = jsonObject.at(MODULE_IS_ENTRY).get(); + } + if (jsonObject.find(MODULE_METADATA) != jsonObjectEnd) { + info.metaData = jsonObject.at(MODULE_METADATA).get(); + } + if (jsonObject.find(MODULE_DISTRO) != jsonObjectEnd) { + info.distro = jsonObject.at(MODULE_DISTRO).get(); + } + if (jsonObject.find(MODULE_DESCRIPTION) != jsonObjectEnd) { + info.description = jsonObject.at(MODULE_DESCRIPTION).get(); + } + if (jsonObject.find(MODULE_REQ_CAPABILITIES) != jsonObjectEnd) { + info.reqCapabilities = jsonObject.at(MODULE_REQ_CAPABILITIES).get>(); + } + if (jsonObject.find(MODULE_REQ_PERMS) != jsonObjectEnd) { + info.reqPermissions = jsonObject.at(MODULE_REQ_PERMS).get>(); + } + if (jsonObject.find(MODULE_DEF_PERMS) != jsonObjectEnd) { + info.defPermissions = jsonObject.at(MODULE_DEF_PERMS).get>(); + } + if (jsonObject.find(MODULE_ABILITY_KEYS) != jsonObjectEnd) { + info.abilityKeys = jsonObject.at(MODULE_ABILITY_KEYS).get>(); + } + if (jsonObject.find(MODULE_SKILL_KEYS) != jsonObjectEnd) { + info.skillKeys = jsonObject.at(MODULE_SKILL_KEYS).get>(); + } +} + +void from_json(const nlohmann::json &jsonObject, SkillUri &uri) +{ + // these are required fields. + uri.scheme = jsonObject.at(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_SCHEME).get(); + // these are not required fields. + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_HOST) != jsonObjectEnd) { + uri.host = jsonObject.at(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_HOST).get(); + } + + if (jsonObject.find(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_PORT) != jsonObjectEnd) { + uri.port = jsonObject.at(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_PORT).get(); + } + + if (jsonObject.find(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_PATH) != jsonObjectEnd) { + uri.path = jsonObject.at(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_PATH).get(); + } + + if (jsonObject.find(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_TYPE) != jsonObjectEnd) { + uri.type = jsonObject.at(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_TYPE).get(); + } +} + +void from_json(const nlohmann::json &jsonObject, Skill &skill) +{ + // these are not required fields. + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_ACTIONS) != jsonObjectEnd) { + skill.actions = jsonObject.at(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_ACTIONS).get>(); + } + + if (jsonObject.find(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_ENTITIES) != jsonObjectEnd) { + skill.entities = + jsonObject.at(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_ENTITIES).get>(); + } + + if (jsonObject.find(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_URIS) != jsonObjectEnd) { + skill.uris = jsonObject.at(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_URIS).get>(); + } +} + +void from_json(const nlohmann::json &jsonObject, CustomizeData &customizeData) +{ + // these are not required fields. + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(ProfileReader::PROFILE_KEY_NAME) != jsonObjectEnd) { + customizeData.name = jsonObject.at(ProfileReader::PROFILE_KEY_NAME).get(); + } + + if (jsonObject.find(ProfileReader::BUNDLE_MODULE_META_KEY_EXTRA) != jsonObjectEnd) { + customizeData.extra = jsonObject.at(ProfileReader::BUNDLE_MODULE_META_KEY_EXTRA).get(); + } + + if (jsonObject.find(ProfileReader::BUNDLE_MODULE_META_KEY_VALUE) != jsonObjectEnd) { + customizeData.value = jsonObject.at(ProfileReader::BUNDLE_MODULE_META_KEY_VALUE).get(); + } +} + +void from_json(const nlohmann::json &jsonObject, Parameters ¶meters) +{ + // these are required fields. + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_TYPE) != jsonObjectEnd) { + parameters.type = jsonObject.at(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_TYPE).get(); + } + // these are not required fields. + + if (jsonObject.find(ProfileReader::PROFILE_KEY_DESCRIPTION) != jsonObjectEnd) { + parameters.description = jsonObject.at(ProfileReader::PROFILE_KEY_DESCRIPTION).get(); + } + + if (jsonObject.find(ProfileReader::PROFILE_KEY_NAME) != jsonObjectEnd) { + parameters.name = jsonObject.at(ProfileReader::PROFILE_KEY_NAME).get(); + } +} + +void from_json(const nlohmann::json &jsonObject, Results &results) +{ + // these are required fields. + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_TYPE) != jsonObjectEnd) { + results.type = jsonObject.at(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_TYPE).get(); + } + // these are not required fields. + if (jsonObject.find(ProfileReader::PROFILE_KEY_DESCRIPTION) != jsonObjectEnd) { + results.description = jsonObject.at(ProfileReader::PROFILE_KEY_DESCRIPTION).get(); + } + + if (jsonObject.find(ProfileReader::PROFILE_KEY_NAME) != jsonObjectEnd) { + results.name = jsonObject.at(ProfileReader::PROFILE_KEY_NAME).get(); + } +} + +void from_json(const nlohmann::json &jsonObject, MetaData &metaData) +{ + // these are not required fields. + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(ProfileReader::BUNDLE_MODULE_META_KEY_CUSTOMIZE_DATA) != jsonObjectEnd) { + metaData.customizeData = + jsonObject.at(ProfileReader::BUNDLE_MODULE_META_KEY_CUSTOMIZE_DATA).get>(); + } + + if (jsonObject.find(ProfileReader::BUNDLE_MODULE_META_KEY_PARAMETERS) != jsonObjectEnd) { + metaData.parameters = + jsonObject.at(ProfileReader::BUNDLE_MODULE_META_KEY_PARAMETERS).get>(); + } + + if (jsonObject.find(ProfileReader::BUNDLE_MODULE_META_KEY_RESULTS) != jsonObjectEnd) { + metaData.results = jsonObject.at(ProfileReader::BUNDLE_MODULE_META_KEY_RESULTS).get>(); + } +} + +void from_json(const nlohmann::json &jsonObject, Distro &distro) +{ + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_DELIVERY_WITH_INSTALL) != jsonObjectEnd) { + distro.deliveryWithInstall = + jsonObject.at(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_DELIVERY_WITH_INSTALL).get(); + } + + if (jsonObject.find(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_MODULE_NAME) != jsonObjectEnd) { + distro.moduleName = jsonObject.at(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_MODULE_NAME).get(); + } + + if (jsonObject.find(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_MODULE_TYPE) != jsonObjectEnd) { + distro.moduleType = jsonObject.at(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_MODULE_TYPE).get(); + } +} + +void from_json(const nlohmann::json &jsonObject, UsedScene &usedScene) +{ + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_REQ_PERMISSIONS_ABILITY) != jsonObjectEnd) { + usedScene.ability = jsonObject.at(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_REQ_PERMISSIONS_ABILITY) + .get>(); + } + if (jsonObject.find(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_REQ_PERMISSIONS_WHEN) != jsonObjectEnd) { + usedScene.when = + jsonObject.at(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_REQ_PERMISSIONS_WHEN).get(); + } +} + +void from_json(const nlohmann::json &jsonObject, ReqPermission &reqPermission) +{ + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_REQ_PERMISSIONS_NAME) != jsonObjectEnd) { + reqPermission.name = + jsonObject.at(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_REQ_PERMISSIONS_NAME).get(); + } + if (jsonObject.find(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_REQ_PERMISSIONS_REASON) != jsonObjectEnd) { + reqPermission.reason = + jsonObject.at(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_REQ_PERMISSIONS_REASON).get(); + } + if (jsonObject.find(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_REQ_PERMISSIONS_USEDSCENE) != jsonObjectEnd) { + reqPermission.usedScene = + jsonObject.at(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_REQ_PERMISSIONS_USEDSCENE).get(); + } +} + +void from_json(const nlohmann::json &jsonObject, DefPermission &defPermission) +{ + const auto &jsonObjectEnd = jsonObject.end(); + if (jsonObject.find(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_NAME) != jsonObjectEnd) { + defPermission.name = + jsonObject.at(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_NAME).get(); + } + if (jsonObject.find(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_GRANTMODE) != jsonObjectEnd) { + defPermission.grantMode = + jsonObject.at(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_GRANTMODE).get(); + } + if (jsonObject.find(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_AVAILABLESCOPE) != jsonObjectEnd) { + defPermission.availableScope = + jsonObject.at(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_AVAILABLESCOPE) + .get>(); + } + if (jsonObject.find(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_LABEL) != jsonObjectEnd) { + defPermission.label = + jsonObject.at(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_LABEL).get(); + } + if (jsonObject.find(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_LABEL_ID) != jsonObjectEnd) { + defPermission.labelId = + jsonObject.at(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_LABEL_ID).get(); + } + if (jsonObject.find(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_DESCRIPTION) != jsonObjectEnd) { + defPermission.description = + jsonObject.at(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_DESCRIPTION).get(); + } + if (jsonObject.find(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_DESCRIPTION_ID) != jsonObjectEnd) { + defPermission.descriptionId = + jsonObject.at(ProfileReader::BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS_DESCRIPTION_ID).get(); + } +} + +bool InnerBundleInfo::FromJson(const nlohmann::json &jsonObject) +{ + try { + isSupportBackup_ = jsonObject.at(IS_SUPPORT_BACKUP).get(); + appType_ = jsonObject.at(APP_TYPE).get(); + uid_ = jsonObject.at(UID).get(); + gid_ = jsonObject.at(GID).get(); + baseDataDir_ = jsonObject.at(BASE_DATA_DIR).get(); + bundleStatus_ = jsonObject.at(BUNDLE_STATUS).get(); + baseBundleInfo_ = jsonObject.at(BASE_BUNDLE_INFO).get(); + baseApplicationInfo_ = jsonObject.at(BASE_APPLICATION_INFO).get(); + baseAbilityInfos_ = jsonObject.at(BASE_ABILITY_INFO).get>(); + innerModuleInfos_ = jsonObject.at(INNER_MODULE_INFO).get>(); + skillInfos_ = jsonObject.at(SKILL_INFOS).get>>(); + isKeepData_ = jsonObject.at(IS_KEEP_DATA).get(); + userId_ = jsonObject.at(USER_ID).get(); + mainAbility_ = jsonObject.at(MAIN_ABILITY).get(); + provisionId_ = jsonObject.at(PROVISION_ID).get(); + appFeature_ = jsonObject.at(APP_FEATURE).get(); + hasEntry_ = jsonObject.at(HAS_ENTRY).get(); + } catch (nlohmann::detail::parse_error &exception) { + APP_LOGE("has a parse_error:%{public}s", exception.what()); + return false; + } catch (nlohmann::detail::type_error &exception) { + APP_LOGE("has a type_error:%{public}s.", exception.what()); + return false; + } catch (nlohmann::detail::out_of_range &exception) { + APP_LOGE("has an out_of_range exception:%{public}s.", exception.what()); + return false; + } + return true; +} + +std::optional> InnerBundleInfo::FindSkills(const std::string &keyName) const +{ + auto skillsInfo = skillInfos_.find(keyName); + if (skillsInfo == skillInfos_.end()) { + return std::nullopt; + } + auto &skills = skillsInfo->second; + if (skills.empty()) { + return std::nullopt; + } + return std::optional> {skills}; +} + +std::optional InnerBundleInfo::FindHapModuleInfo(const std::string &modulePackage) const +{ + auto it = innerModuleInfos_.find(modulePackage); + if (it == innerModuleInfos_.end()) { + APP_LOGE("can not find module %{public}s", modulePackage.c_str()); + return std::nullopt; + } + HapModuleInfo hapInfo; + hapInfo.name = it->second.modulePackage; + hapInfo.moduleName = it->second.moduleName; + hapInfo.description = it->second.description; + hapInfo.supportedModes = baseApplicationInfo_.supportedModes; + hapInfo.reqCapabilities = it->second.reqCapabilities; + bool first = false; + for (auto &ability : baseAbilityInfos_) { + if (ability.first.find(modulePackage) != std::string::npos) { + if (!first) { + hapInfo.label = ability.second.label; + hapInfo.iconPath = ability.second.iconPath; + hapInfo.deviceTypes = ability.second.deviceTypes; + first = true; + } + auto &abilityInfo = hapInfo.abilityInfos.emplace_back(ability.second); + GetApplicationInfo(ApplicationFlag::GET_APPLICATION_INFO_WITH_PERMS, 0, abilityInfo.applicationInfo); + } + } + return hapInfo; +} + +std::optional InnerBundleInfo::FindAbilityInfo( + const std::string &bundleName, const std::string &abilityName) const +{ + for (const auto &ability : baseAbilityInfos_) { + if ((ability.second.bundleName == bundleName) && (ability.second.name == abilityName)) { + return ability.second; + } + } + return std::nullopt; +} + +bool InnerBundleInfo::AddModuleInfo(const InnerBundleInfo &newInfo) +{ + if (newInfo.currentPackage_.empty()) { + APP_LOGE("current package is empty"); + return false; + } + if (FindModule(newInfo.currentPackage_)) { + APP_LOGE("current package %{public}s is exist", currentPackage_.c_str()); + return false; + } + if (!hasEntry_ && newInfo.HasEntry()) { + hasEntry_ = true; + } + if (mainAbility_.empty() && !newInfo.mainAbility_.empty()) { + UpdateBaseApplicationInfo(newInfo.baseApplicationInfo_); + SetMainAbility(newInfo.mainAbility_); + SetMainAbilityName(newInfo.mainAbilityName_); + } + AddInnerModuleInfo(newInfo.innerModuleInfos_); + AddModuleAbilityInfo(newInfo.baseAbilityInfos_); + AddModuleSkillInfo(newInfo.skillInfos_); + return true; +} + +void InnerBundleInfo::UpdateVersionInfo(const InnerBundleInfo &newInfo) +{ + if (baseBundleInfo_.versionCode == newInfo.GetVersionCode()) { + APP_LOGE("old version equals to new version"); + return; + } + baseBundleInfo_.versionCode = newInfo.GetVersionCode(); + baseBundleInfo_.vendor = newInfo.GetBaseBundleInfo().vendor; + baseBundleInfo_.versionName = newInfo.GetBaseBundleInfo().versionName; + baseBundleInfo_.minSdkVersion = newInfo.GetBaseBundleInfo().minSdkVersion; + baseBundleInfo_.maxSdkVersion = newInfo.GetBaseBundleInfo().maxSdkVersion; + baseBundleInfo_.compatibleVersion = newInfo.GetBaseBundleInfo().compatibleVersion; + baseBundleInfo_.targetVersion = newInfo.GetBaseBundleInfo().targetVersion; + baseBundleInfo_.releaseType = newInfo.GetBaseBundleInfo().releaseType; +} + +void InnerBundleInfo::UpdateModuleInfo(const InnerBundleInfo &newInfo) +{ + if (newInfo.currentPackage_.empty()) { + APP_LOGE("no package in new info"); + return; + } + innerModuleInfos_.erase(newInfo.currentPackage_); + for (auto it = baseAbilityInfos_.begin(); it != baseAbilityInfos_.end();) { + if (it->first.find(newInfo.currentPackage_) != std::string::npos) { + skillInfos_.erase(it->first); + it = baseAbilityInfos_.erase(it); + } else { + ++it; + } + } + if (!hasEntry_ && newInfo.HasEntry()) { + hasEntry_ = true; + } + if (mainAbility_ == newInfo.mainAbility_) { + UpdateBaseApplicationInfo(newInfo.baseApplicationInfo_); + } + AddInnerModuleInfo(newInfo.innerModuleInfos_); + AddModuleAbilityInfo(newInfo.baseAbilityInfos_); + AddModuleSkillInfo(newInfo.skillInfos_); +} + +void InnerBundleInfo::RemoveModuleInfo(const std::string &modulePackage) +{ + if (innerModuleInfos_.find(modulePackage) == innerModuleInfos_.end()) { + APP_LOGE("can not find module %{public}s", modulePackage.c_str()); + return; + } + if (mainAbility_.find(modulePackage) != std::string::npos) { + mainAbility_.clear(); + } + for (auto it = innerModuleInfos_.begin(); it != innerModuleInfos_.end();) { + (it->first == modulePackage) ? innerModuleInfos_.erase(it++) : (++it); + } + for (auto it = baseAbilityInfos_.begin(); it != baseAbilityInfos_.end();) { + (it->first.find(modulePackage) != std::string::npos) ? baseAbilityInfos_.erase(it++) : (++it); + } + for (auto it = skillInfos_.begin(); it != skillInfos_.end();) { + (it->first.find(modulePackage) != std::string::npos) ? skillInfos_.erase(it++) : (++it); + } +} + +std::string InnerBundleInfo::ToString() const +{ + nlohmann::json j; + j[IS_SUPPORT_BACKUP] = isSupportBackup_; + j[APP_TYPE] = appType_; + j[UID] = uid_; + j[GID] = gid_; + j[BASE_DATA_DIR] = baseDataDir_; + j[BUNDLE_STATUS] = bundleStatus_; + j[BASE_APPLICATION_INFO] = baseApplicationInfo_; + j[BASE_BUNDLE_INFO] = baseBundleInfo_; + j[BASE_ABILITY_INFO] = baseAbilityInfos_; + j[INNER_MODULE_INFO] = innerModuleInfos_; + j[SKILL_INFOS] = skillInfos_; + j[IS_KEEP_DATA] = isKeepData_; + j[USER_ID] = userId_; + j[MAIN_ABILITY] = mainAbility_; + j[APP_FEATURE] = appFeature_; + j[PROVISION_ID] = provisionId_; + j[HAS_ENTRY] = hasEntry_; + return j.dump(); +} + +void InnerBundleInfo::GetApplicationInfo(const ApplicationFlag flag, const int userId, ApplicationInfo &appInfo) const +{ + appInfo = baseApplicationInfo_; + for (const auto &info : innerModuleInfos_) { + ModuleInfo moduleInfo; + moduleInfo.moduleName = info.second.moduleName; + moduleInfo.moduleSourceDir = info.second.modulePath; + appInfo.moduleInfos.emplace_back(moduleInfo); + appInfo.moduleSourceDirs.emplace_back(info.second.modulePath); + if (info.second.isEntry) { + appInfo.entryDir = info.second.modulePath; + } + if (flag == ApplicationFlag::GET_APPLICATION_INFO_WITH_PERMS) { + std::transform(info.second.reqPermissions.begin(), + info.second.reqPermissions.end(), + std::back_inserter(appInfo.permissions), + [](const auto &p) { return p.name; }); + } + } +} + +void InnerBundleInfo::GetBundleInfo(const BundleFlag flag, BundleInfo &bundleInfo) const +{ + bundleInfo = baseBundleInfo_; + GetApplicationInfo(ApplicationFlag::GET_APPLICATION_INFO_WITH_PERMS, 0, bundleInfo.applicationInfo); + for (const auto &info : innerModuleInfos_) { + std::transform(info.second.reqPermissions.begin(), + info.second.reqPermissions.end(), + std::back_inserter(bundleInfo.reqPermissions), + [](const auto &p) { return p.name; }); + std::transform(info.second.defPermissions.begin(), + info.second.defPermissions.end(), + std::back_inserter(bundleInfo.defPermissions), + [](const auto &p) { return p.name; }); + bundleInfo.hapModuleNames.emplace_back(info.second.modulePackage); + bundleInfo.moduleNames.emplace_back(info.second.moduleName); + bundleInfo.moduleDirs.emplace_back(info.second.modulePath); + bundleInfo.modulePublicDirs.emplace_back(info.second.moduleDataDir); + bundleInfo.moduleResPaths.emplace_back(info.second.moduleResPath); + if (info.second.isEntry) { + bundleInfo.mainEntry = info.second.modulePackage; + bundleInfo.entryModuleName = info.second.moduleName; + } + } + if (flag == BundleFlag::GET_BUNDLE_WITH_ABILITIES) { + std::transform(baseAbilityInfos_.begin(), + baseAbilityInfos_.end(), + std::back_inserter(bundleInfo.abilityInfos), + [this](auto m) { + GetApplicationInfo(ApplicationFlag::GET_APPLICATION_INFO_WITH_PERMS, 0, m.second.applicationInfo); + return m.second; + }); + } +} + +bool InnerBundleInfo::CheckSpecialMetaData(const std::string &metaData) const +{ + for (const auto &moduleInfo : innerModuleInfos_) { + for (const auto &data : moduleInfo.second.metaData.customizeData) { + if (metaData == data.name) { + return true; + } + } + } + return false; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/bundlemgr/src/installd/installd_host_impl.cpp b/services/bundlemgr/src/installd/installd_host_impl.cpp new file mode 100644 index 000000000..b850b712a --- /dev/null +++ b/services/bundlemgr/src/installd/installd_host_impl.cpp @@ -0,0 +1,233 @@ +/* + * 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 "installd/installd_host_impl.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "directory_ex.h" +#include "bundle_constants.h" +#include "app_log_wrapper.h" +#include "installd/installd_operator.h" + +namespace OHOS { +namespace AppExecFwk { + +InstalldHostImpl::InstalldHostImpl() +{ + APP_LOGI("installd service instance is created"); +} + +InstalldHostImpl::~InstalldHostImpl() +{ + APP_LOGI("installd service instance is destroyed"); +} + +ErrCode InstalldHostImpl::CreateBundleDir(const std::string &bundleDir) +{ + if (bundleDir.empty()) { + return ERR_APPEXECFWK_INSTALLD_PARAM_ERROR; + } + if (InstalldOperator::IsExistDir(bundleDir)) { + APP_LOGE("bundleDir %{public}s is exist", bundleDir.c_str()); + return ERR_APPEXECFWK_INSTALLD_CREATE_DIR_EXIST; + } + if (!InstalldOperator::MkRecursiveDir(bundleDir, true)) { + APP_LOGE("create bundle dir %{public}s failed", bundleDir.c_str()); + return ERR_APPEXECFWK_INSTALLD_CREATE_DIR_FAILED; + } + return ERR_OK; +} + +ErrCode InstalldHostImpl::RemoveBundleDir(const std::string &bundleDir) +{ + if (bundleDir.empty()) { + return ERR_APPEXECFWK_INSTALLD_PARAM_ERROR; + } + if (!InstalldOperator::DeleteDir(bundleDir)) { + APP_LOGE("remove bundle dir %{public}s failed", bundleDir.c_str()); + return ERR_APPEXECFWK_INSTALLD_REMOVE_DIR_FAILED; + } + return ERR_OK; +} + +ErrCode InstalldHostImpl::ExtractModuleFiles(const std::string &srcModulePath, const std::string &targetPath) +{ + if (srcModulePath.empty() || targetPath.empty()) { + return ERR_APPEXECFWK_INSTALLD_PARAM_ERROR; + } + if (!InstalldOperator::MkRecursiveDir(targetPath, true)) { + APP_LOGE("create target dir %{public}s failed", targetPath.c_str()); + return ERR_APPEXECFWK_INSTALLD_EXTRACT_FILES_FAILED; + } + if (!InstalldOperator::ExtractFiles(srcModulePath, targetPath)) { + APP_LOGE("extract %{public}s to %{public}s failed", srcModulePath.c_str(), targetPath.c_str()); + InstalldOperator::DeleteDir(targetPath); + return ERR_APPEXECFWK_INSTALLD_EXTRACT_FILES_FAILED; + } + return ERR_OK; +} + +ErrCode InstalldHostImpl::RemoveModuleDir(const std::string &moduleDir) +{ + if (moduleDir.empty()) { + return ERR_APPEXECFWK_INSTALLD_PARAM_ERROR; + } + if (!InstalldOperator::DeleteDir(moduleDir)) { + APP_LOGE("remove module dir %{public}s failed", moduleDir.c_str()); + return ERR_APPEXECFWK_INSTALLD_REMOVE_DIR_FAILED; + } + return ERR_OK; +} + +ErrCode InstalldHostImpl::RenameModuleDir(const std::string &oldPath, const std::string &newPath) +{ + APP_LOGI("rename %{public}s to %{public}s", oldPath.c_str(), newPath.c_str()); + if (oldPath.empty() || newPath.empty()) { + return ERR_APPEXECFWK_INSTALLD_PARAM_ERROR; + } + if (!InstalldOperator::RenameDir(oldPath, newPath)) { + APP_LOGE("rename module dir %{public}s to %{public}s failed", oldPath.c_str(), newPath.c_str()); + return ERR_APPEXECFWK_INSTALLD_RNAME_DIR_FAILED; + } + return ERR_OK; +} + +ErrCode InstalldHostImpl::CreateBundleDataDir(const std::string &bundleDir, const int uid, const int gid) +{ + if (bundleDir.empty() || uid < 0 || gid < 0) { + return ERR_APPEXECFWK_INSTALLD_PARAM_ERROR; + } + std::string createDir; + if (bundleDir.back() != Constants::PATH_SEPARATOR[0]) { + createDir = bundleDir + Constants::PATH_SEPARATOR; + } else { + createDir = bundleDir; + } + + if (!InstalldOperator::MkOwnerDir(createDir + Constants::DATA_DIR, true, uid, gid)) { + return ERR_APPEXECFWK_INSTALLD_CREATE_DIR_FAILED; + } + + if (!InstalldOperator::MkOwnerDir(createDir + Constants::DATA_BASE_DIR, true, uid, gid)) { + return ERR_APPEXECFWK_INSTALLD_CREATE_DIR_FAILED; + } + + if (!InstalldOperator::MkOwnerDir(createDir + Constants::CACHE_DIR, true, uid, gid)) { + return ERR_APPEXECFWK_INSTALLD_CREATE_DIR_FAILED; + } + + if (!InstalldOperator::MkOwnerDir(createDir + Constants::SHARED_PREFERENCE_DIR, true, uid, gid)) { + return ERR_APPEXECFWK_INSTALLD_CREATE_DIR_FAILED; + } + return ERR_OK; +} + +ErrCode InstalldHostImpl::RemoveBundleDataDir(const std::string &bundleDataDir) +{ + if (bundleDataDir.empty()) { + return ERR_APPEXECFWK_INSTALLD_PARAM_ERROR; + } + if (!InstalldOperator::DeleteDir(bundleDataDir)) { + APP_LOGE("remove bundle data dir %{public}s failed", bundleDataDir.c_str()); + return ERR_APPEXECFWK_INSTALLD_REMOVE_DIR_FAILED; + } + return ERR_OK; +} + +ErrCode InstalldHostImpl::CreateModuleDataDir( + const std::string &ModuleDir, const std::vector &abilityDirs, const int uid, const int gid) +{ + if (ModuleDir.empty() || uid < 0 || gid < 0) { + return ERR_APPEXECFWK_INSTALLD_PARAM_ERROR; + } + std::string createDir; + if (ModuleDir.back() != Constants::PATH_SEPARATOR[0]) { + createDir = ModuleDir + Constants::PATH_SEPARATOR; + } else { + createDir = ModuleDir; + } + + if (!InstalldOperator::MkOwnerDir(createDir + Constants::SHARED_DIR, true, uid, gid)) { + return ERR_APPEXECFWK_INSTALLD_CREATE_DIR_FAILED; + } + + for (auto &abilityDir : abilityDirs) { + if (!InstalldOperator::MkOwnerDir( + createDir + abilityDir + Constants::PATH_SEPARATOR + Constants::DATA_DIR, + true, + uid, + gid)) { + return ERR_APPEXECFWK_INSTALLD_CREATE_DIR_FAILED; + } + if (!InstalldOperator::MkOwnerDir( + createDir + abilityDir + Constants::PATH_SEPARATOR + Constants::CACHE_DIR, + true, + uid, + gid)) { + return ERR_APPEXECFWK_INSTALLD_CREATE_DIR_FAILED; + } + if (!InstalldOperator::MkOwnerDir( + createDir + abilityDir + Constants::PATH_SEPARATOR + Constants::DATA_BASE_DIR, + true, + uid, + gid)) { + return ERR_APPEXECFWK_INSTALLD_CREATE_DIR_FAILED; + } + if (!InstalldOperator::MkOwnerDir( + createDir + abilityDir + Constants::PATH_SEPARATOR + Constants::SHARED_PREFERENCE_DIR, + true, + uid, + gid)) { + return ERR_APPEXECFWK_INSTALLD_CREATE_DIR_FAILED; + } + } + + return ERR_OK; +} + +ErrCode InstalldHostImpl::RemoveModuleDataDir(const std::string &moduleDataDir) +{ + if (moduleDataDir.empty()) { + return ERR_APPEXECFWK_INSTALLD_PARAM_ERROR; + } + if (!InstalldOperator::DeleteDir(moduleDataDir)) { + APP_LOGE("remove module dir %{public}s failed", moduleDataDir.c_str()); + return ERR_APPEXECFWK_INSTALLD_REMOVE_DIR_FAILED; + } + return ERR_OK; +} + +ErrCode InstalldHostImpl::CleanBundleDataDir(const std::string &dataDir) +{ + if (dataDir.empty()) { + return ERR_APPEXECFWK_INSTALLD_PARAM_ERROR; + } + + if (!InstalldOperator::DeleteFiles(dataDir)) { + return ERR_APPEXECFWK_INSTALLD_CLEAN_DIR_FAILED; + } + return ERR_OK; +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/bundlemgr/src/installd/installd_main.cpp b/services/bundlemgr/src/installd/installd_main.cpp new file mode 100644 index 000000000..7f03862f1 --- /dev/null +++ b/services/bundlemgr/src/installd/installd_main.cpp @@ -0,0 +1,42 @@ +/* + * 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 "ipc_skeleton.h" + +#include "app_log_wrapper.h" +#include "installd/installd_service.h" + +int main([[maybe_unused]] int argc, [[maybe_unused]] char **argv) +{ + using namespace OHOS::AppExecFwk; + std::unique_ptr service = std::make_unique(); + if (!service) { + APP_LOGE("fail to create the installd service"); + std::exit(EXIT_FAILURE); + } + service->Start(); + if (!service->IsServiceReady()) { + APP_LOGW("can't start the installd service, try again"); + service->Start(); + if (!service->IsServiceReady()) { + APP_LOGE("fail to start the installd service"); + std::exit(EXIT_FAILURE); + } + } + OHOS::IPCSkeleton::JoinWorkThread(); + service->Stop(); + APP_LOGE("installd service stopped"); + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/services/bundlemgr/src/installd/installd_operator.cpp b/services/bundlemgr/src/installd/installd_operator.cpp new file mode 100644 index 000000000..b2d89c385 --- /dev/null +++ b/services/bundlemgr/src/installd/installd_operator.cpp @@ -0,0 +1,240 @@ +/* + * 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 "installd/installd_operator.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "directory_ex.h" +#include "app_log_wrapper.h" +#include "bundle_constants.h" +#include "bundle_extractor.h" + +namespace OHOS { +namespace AppExecFwk { +namespace {} // namespace + +bool InstalldOperator::IsExistFile(const std::string &path) +{ + if (path.empty()) { + return false; + } + + struct stat buf = {}; + if (stat(path.c_str(), &buf) != 0) { + return false; + } + return S_ISREG(buf.st_mode); +} + +bool InstalldOperator::IsExistDir(const std::string &path) +{ + if (path.empty()) { + return false; + } + + struct stat buf = {}; + if (stat(path.c_str(), &buf) != 0) { + return false; + } + return S_ISDIR(buf.st_mode); +} + +bool InstalldOperator::MkRecursiveDir(const std::string &path, bool isReadByOthers) +{ + if (!OHOS::ForceCreateDirectory(path)) { + APP_LOGE("mkdir failed"); + return false; + } + mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IXOTH; + mode |= (isReadByOthers ? S_IROTH : 0); + return OHOS::ChangeModeDirectory(path, mode); +} + +bool InstalldOperator::DeleteDir(const std::string &path) +{ + if (IsExistFile(path)) { + return OHOS::RemoveFile(path); + } + if (IsExistDir(path)) { + return OHOS::ForceRemoveDirectory(path); + } + return true; +} + +bool InstalldOperator::ExtractFiles(const std::string &sourcePath, const std::string &targetPath) +{ + BundleExtractor extractor(sourcePath); + if (!extractor.Init()) { + return false; + } + std::vector entryNames; + if (!extractor.GetZipFileNames(entryNames)) { + return false; + } + if (entryNames.empty()) { + return false; + } + + std::string targetDir = targetPath; + if (targetPath.back() != Constants::PATH_SEPARATOR[0]) { + targetDir = targetPath + Constants::PATH_SEPARATOR; + } + for (const auto &entryName : entryNames) { + if (entryName.find("..") != std::string::npos) { + return false; + } + if (entryName.back() == Constants::PATH_SEPARATOR[0]) { + continue; + } + const std::string dir = GetPathDir(entryName); + std::string filePath = targetDir + dir; + if (!dir.empty()) { + if (!MkRecursiveDir(filePath, true)) { + return false; + } + } + filePath = targetDir + entryName; + if (!extractor.ExtractFile(entryName, filePath)) { + return false; + } + mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + if (!OHOS::ChangeModeFile(filePath, mode)) { + APP_LOGE("change mode failed"); + } + filePath.clear(); + } + return true; +} + +bool InstalldOperator::RenameDir(const std::string &oldPath, const std::string &newPath) +{ + if (oldPath.empty() || oldPath.size() > PATH_MAX) { + APP_LOGE("oldpath error"); + return false; + } + std::string realOldPath; + realOldPath.reserve(PATH_MAX); + realOldPath.resize(PATH_MAX - 1); + if (realpath(oldPath.c_str(), &(realOldPath[0])) == nullptr) { + APP_LOGE("realOldPath %{public}s", realOldPath.c_str()); + return false; + } + if (!(IsValideCodePath(realOldPath) && IsValideCodePath(newPath))) { + APP_LOGE("IsValideCodePath failed"); + return false; + } + return RenameFile(realOldPath, newPath); +} + +std::string InstalldOperator::GetPathDir(const std::string &path) +{ + std::size_t pos = path.rfind(Constants::PATH_SEPARATOR); + if (pos == std::string::npos) { + return std::string(); + } + return path.substr(0, pos + 1); +} + +bool InstalldOperator::ChangeFileAttr(const std::string &filePath, const int uid, const int gid) +{ + APP_LOGD("begin to change %{private}s file attribute", filePath.c_str()); + if (chown(filePath.c_str(), uid, gid) != 0) { + APP_LOGE("fail to change %{private}s ownership", filePath.c_str()); + return false; + } + APP_LOGD("change %{private}s file attribute successfully", filePath.c_str()); + return true; +} + +bool InstalldOperator::RenameFile(const std::string &oldPath, const std::string &newPath) +{ + if (oldPath.empty() || newPath.empty()) { + return false; + } + if (!DeleteDir(newPath)) { + return false; + } + return rename(oldPath.c_str(), newPath.c_str()) == 0; +} + +bool InstalldOperator::IsValidPath(const std::string &rootDir, const std::string &path) +{ + if (rootDir.find(Constants::PATH_SEPARATOR) != 0 || + rootDir.rfind(Constants::PATH_SEPARATOR) != (rootDir.size() - 1) || rootDir.find("..") != std::string::npos) { + return false; + } + if (path.find("..") != std::string::npos) { + return false; + } + return path.compare(0, rootDir.size(), rootDir) == 0; +} + +bool InstalldOperator::IsValideCodePath(const std::string &codePath) +{ + if (codePath.empty()) { + return false; + } + return IsValidPath(Constants::THIRD_PARTY_APP_INSTALL_PATH + Constants::PATH_SEPARATOR, codePath) || + IsValidPath(Constants::SYSTEM_APP_INSTALL_PATH + Constants::PATH_SEPARATOR, codePath); +} + +bool InstalldOperator::DeleteFiles(const std::string &dataPath) +{ + std::string subPath; + bool ret = true; + DIR *dir = opendir(dataPath.c_str()); + if (dir == nullptr) { + return false; + } + while (true) { + struct dirent *ptr = readdir(dir); + if (ptr == nullptr) { + break; + } + if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) { + continue; + } + subPath = OHOS::IncludeTrailingPathDelimiter(dataPath) + std::string(ptr->d_name); + if (ptr->d_type == DT_DIR) { + ret = OHOS::ForceRemoveDirectory(subPath); + } else { + if (access(subPath.c_str(), F_OK) == 0) { + ret = OHOS::RemoveFile(subPath); + } + } + } + closedir(dir); + return ret; +} + +bool InstalldOperator::MkOwnerDir(const std::string &path, bool isReadByOthers, const int uid, const int gid) +{ + if (!MkRecursiveDir(path, isReadByOthers)) { + return false; + } + return ChangeFileAttr(path, uid, gid); +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/bundlemgr/src/installd/installd_service.cpp b/services/bundlemgr/src/installd/installd_service.cpp new file mode 100644 index 000000000..0da97b781 --- /dev/null +++ b/services/bundlemgr/src/installd/installd_service.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 "installd/installd_service.h" + +#include +#include +#include +#include +#include + +#include "app_log_wrapper.h" +#include "system_ability_definition.h" +#include "system_ability_helper.h" +#include "bundle_constants.h" + +using namespace std::chrono_literals; + +namespace OHOS { +namespace AppExecFwk { + +InstalldService::InstalldService() +{ + APP_LOGI("installd service instance is created"); +} + +InstalldService::~InstalldService() +{ + APP_LOGI("installd service instance is destroyed"); +} + +bool InstalldService::Init() +{ + if (isReady_) { + APP_LOGW("the installd service is already ready"); + return false; + } + // installd service need mask 000 + umask(Constants::INSTALLD_UMASK); + hostImpl_ = new (std::nothrow) InstalldHostImpl(); + if (hostImpl_ == nullptr) { + APP_LOGI("InstalldHostImpl Init failed"); + return false; + } + if (!InitDir(Constants::THIRD_PARTY_APP_INSTALL_PATH)) { + APP_LOGI("THIRD_PARTY_APP_INSTALL_PATH Path already exists"); + } + if (!InitDir(Constants::SYSTEM_APP_INSTALL_PATH)) { + APP_LOGI("SYSTEM_APP_INSTALL_PATH is already exists"); + } + if (!InitDir(Constants::BUNDLE_DATA_BASE_DIR)) { + APP_LOGI("BUNDLE_DATA_BASE_DIR is already exists"); + } + if (!InitDir(Constants::EXTRACT_TMP_PATH)) { + APP_LOGI("EXTRACT_TMP_PATH is already exists"); + } + if (!InitDir(Constants::HAP_COPY_PATH)) { + APP_LOGI("HAP_COPY_PATH is already exists"); + } + return true; +} + +bool InstalldService::InitDir(const std::string &path) +{ + if (InstalldOperator::IsExistDir(path)) { + APP_LOGI("Path already exists"); + return false; + } + if (!InstalldOperator::MkOwnerDir(path, true, Constants::BMS_UID, Constants::BMS_GID)) { + APP_LOGE("create path failed %{public}s", strerror(errno)); + return false; + } + return true; +} + +void InstalldService::Start() +{ + if (!(Init())) { + APP_LOGE("init fail"); + return; + } + // add installd service to system ability manager. + // need to retry some times due to installd start faster than system ability manager. + if (!SystemAbilityHelper::AddSystemAbility(INSTALLD_SERVICE_ID, hostImpl_)) { + APP_LOGW("installd service fail to register into system ability manager, retry it"); + int32_t tryTimes = 3; + bool isSuccess = false; + for (int32_t i = 0; i < tryTimes; i++) { + std::this_thread::sleep_for(100ms); + if (SystemAbilityHelper::AddSystemAbility(INSTALLD_SERVICE_ID, hostImpl_)) { + isSuccess = true; + break; + } + } + if (!isSuccess) { + APP_LOGE("installd service fail to register into system ability manager"); + return; + } + } + isReady_ = true; + APP_LOGI("installd service start successfully"); +} + +void InstalldService::Stop() +{ + if (!isReady_) { + APP_LOGW("the installd service is already stopped"); + return; + } + // remove installd service from system ability manager. + // since we can't handle the fail case, just ignore the result. + SystemAbilityHelper::RemoveSystemAbility(INSTALLD_SERVICE_ID); + isReady_ = false; + APP_LOGI("installd service stop successfully"); +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/bundlemgr/src/installd_client.cpp b/services/bundlemgr/src/installd_client.cpp new file mode 100644 index 000000000..90c2dcedc --- /dev/null +++ b/services/bundlemgr/src/installd_client.cpp @@ -0,0 +1,137 @@ +/* + * 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 "installd_client.h" + +#include "app_log_wrapper.h" +#include "bundle_constants.h" +#include "installd_death_recipient.h" +#include "system_ability_definition.h" +#include "system_ability_helper.h" + +namespace OHOS { +namespace AppExecFwk { + +ErrCode InstalldClient::CreateBundleDir(const std::string &bundleDir) +{ + if (!GetInstalldProxy()) { + return ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR; + } + return installdProxy_->CreateBundleDir(bundleDir); +} + +ErrCode InstalldClient::RemoveBundleDir(const std::string &bundleDir) +{ + if (!GetInstalldProxy()) { + return ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR; + } + return installdProxy_->RemoveBundleDir(bundleDir); +} + +ErrCode InstalldClient::RemoveBundleDataDir(const std::string &bundleDataDir) +{ + if (!GetInstalldProxy()) { + return ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR; + } + return installdProxy_->RemoveBundleDir(bundleDataDir); +} + +ErrCode InstalldClient::ExtractModuleFiles(const std::string &srcModulePath, const std::string &targetPath) +{ + if (!GetInstalldProxy()) { + return ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR; + } + return installdProxy_->ExtractModuleFiles(srcModulePath, targetPath); +} + +ErrCode InstalldClient::RemoveModuleDir(const std::string &moduleDir) +{ + if (!GetInstalldProxy()) { + return ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR; + } + return installdProxy_->RemoveModuleDir(moduleDir); +} + +ErrCode InstalldClient::RenameModuleDir(const std::string &oldPath, const std::string &newPath) +{ + if (!GetInstalldProxy()) { + return ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR; + } + return installdProxy_->RenameModuleDir(oldPath, newPath); +} + +ErrCode InstalldClient::CreateBundleDataDir(const std::string &bundleDir, const int uid, const int gid) +{ + if (!GetInstalldProxy()) { + return ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR; + } + return installdProxy_->CreateBundleDataDir(bundleDir, uid, gid); +} + +ErrCode InstalldClient::CreateModuleDataDir( + const std::string &ModuleDir, const std::vector &abilityDirs, const int uid, const int gid) +{ + if (!GetInstalldProxy()) { + return ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR; + } + return installdProxy_->CreateModuleDataDir(ModuleDir, abilityDirs, uid, gid); +} + +ErrCode InstalldClient::RemoveModuleDataDir(const std::string &moduleDataDir) +{ + if (!GetInstalldProxy()) { + return ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR; + } + return installdProxy_->RemoveModuleDataDir(moduleDataDir); +} + +ErrCode InstalldClient::CleanBundleDataDir(const std::string &bundleDir) +{ + if (!GetInstalldProxy()) { + return ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR; + } + return installdProxy_->CleanBundleDataDir(bundleDir); +} + +void InstalldClient::ResetInstalldProxy() +{ + if ((installdProxy_ != nullptr) && (installdProxy_->AsObject() != nullptr)) { + installdProxy_->AsObject()->RemoveDeathRecipient(recipient_); + } + installdProxy_ = nullptr; +} + +bool InstalldClient::GetInstalldProxy() +{ + if (!installdProxy_) { + APP_LOGD("try to get installd proxy"); + std::lock_guard lock(mutex_); + if (!installdProxy_) { + sptr tempProxy = + iface_cast(SystemAbilityHelper::GetSystemAbility(INSTALLD_SERVICE_ID)); + if ((!tempProxy) || (!tempProxy->AsObject())) { + APP_LOGE("the installd proxy or remote object is null"); + return false; + } + recipient_ = new (std::nothrow) InstalldDeathRecipient(); + tempProxy->AsObject()->AddDeathRecipient(recipient_); + installdProxy_ = tempProxy; + } + } + return true; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/bundlemgr/src/installd_death_recipient.cpp b/services/bundlemgr/src/installd_death_recipient.cpp new file mode 100644 index 000000000..c3f8bac24 --- /dev/null +++ b/services/bundlemgr/src/installd_death_recipient.cpp @@ -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. + */ + +#include "installd_death_recipient.h" + +#include "app_log_wrapper.h" +#include "installd_client.h" + +namespace OHOS { +namespace AppExecFwk { + +void InstalldDeathRecipient::OnRemoteDied([[maybe_unused]] const wptr &remote) +{ + APP_LOGI("installd service died, remove the proxy object"); + InstalldClient::GetInstance()->ResetInstalldProxy(); +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/bundlemgr/src/ipc/installd_host.cpp b/services/bundlemgr/src/ipc/installd_host.cpp new file mode 100644 index 000000000..a4ee36dd7 --- /dev/null +++ b/services/bundlemgr/src/ipc/installd_host.cpp @@ -0,0 +1,210 @@ +/* + * 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 "ipc/installd_host.h" + +#include "app_log_wrapper.h" +#include "appexecfwk_errors.h" +#include "bundle_constants.h" +#include "parcel_macro.h" + +namespace OHOS { +namespace AppExecFwk { + +InstalldHost::InstalldHost() +{ + APP_LOGI("installd host instance is created"); +} + +InstalldHost::~InstalldHost() +{ + APP_LOGI("installd host instance is destroyed"); +} + +int InstalldHost::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + APP_LOGD( + "installd host receives message from client, code = %{public}d, flags = %{public}d", code, option.GetFlags()); + std::u16string descripter = InstalldHost::GetDescriptor(); + std::u16string remoteDescripter = data.ReadInterfaceToken(); + if (descripter != remoteDescripter) { + APP_LOGE("installd host fail to write reply message due to the reply is nullptr"); + return OHOS::ERR_APPEXECFWK_PARCEL_ERROR; + } + switch (code) { + case static_cast(IInstalld::Message::CREATE_BUNDLE_DIR): { + if (!HandleCreateBundleDir(data, reply)) { + return OHOS::ERR_APPEXECFWK_PARCEL_ERROR; + } + break; + } + case static_cast(IInstalld::Message::REMOVE_BUNDLE_DIR): { + if (!HandleRemoveBundleDir(data, reply)) { + return OHOS::ERR_APPEXECFWK_PARCEL_ERROR; + } + break; + } + case static_cast(IInstalld::Message::EXTRACT_MODULE_FILES): { + if (!HandleExtractModuleFiles(data, reply)) { + return OHOS::ERR_APPEXECFWK_PARCEL_ERROR; + } + break; + } + case static_cast(IInstalld::Message::REMOVE_MODULE_DIR): { + if (!HandleRemoveModuleDir(data, reply)) { + return OHOS::ERR_APPEXECFWK_PARCEL_ERROR; + } + break; + } + case static_cast(IInstalld::Message::RENAME_MODULE_DIR): { + if (!HandleRenameModuleDir(data, reply)) { + return OHOS::ERR_APPEXECFWK_PARCEL_ERROR; + } + break; + } + case static_cast(IInstalld::Message::CREATE_BUNDLE_DATA_DIR): { + if (!HandleCreateBundleDataDir(data, reply)) { + return OHOS::ERR_APPEXECFWK_PARCEL_ERROR; + } + break; + } + case static_cast(IInstalld::Message::REMOVE_BUNDLE_DATA_DIR): { + if (!HandleRemoveBundleDataDir(data, reply)) { + return OHOS::ERR_APPEXECFWK_PARCEL_ERROR; + } + break; + } + case static_cast(IInstalld::Message::CREATE_MODULE_DATA_DIR): { + if (!HandleCreateModuleDataDir(data, reply)) { + return OHOS::ERR_APPEXECFWK_PARCEL_ERROR; + } + break; + } + case static_cast(IInstalld::Message::REMOVE_MODULE_DATA_DIR): { + if (!HandleRemoveModuleDataDir(data, reply)) { + return OHOS::ERR_APPEXECFWK_PARCEL_ERROR; + } + break; + } + case static_cast(IInstalld::Message::CLEAN_BUNDLE_DATA_DIR): { + if (!HandleCleanBundleDataDir(data, reply)) { + return OHOS::ERR_APPEXECFWK_PARCEL_ERROR; + } + break; + } + default: + APP_LOGW("installd host receives unknown code, code = %{public}d", code); + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); + } + APP_LOGD("installd host finish to process message from client"); + return NO_ERROR; +} + +bool InstalldHost::HandleCreateBundleDir(MessageParcel &data, MessageParcel &reply) +{ + std::string bundleDir = data.ReadString(); + APP_LOGI("bundleName %{public}s", bundleDir.c_str()); + ErrCode result = CreateBundleDir(bundleDir); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, reply, result); + return true; +} + +bool InstalldHost::HandleRemoveBundleDir(MessageParcel &data, MessageParcel &reply) +{ + std::string bundleDir = data.ReadString(); + ErrCode result = RemoveBundleDir(bundleDir); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, reply, result); + return true; +} + +bool InstalldHost::HandleExtractModuleFiles(MessageParcel &data, MessageParcel &reply) +{ + std::string srcModulePath = data.ReadString(); + std::string targetPath = data.ReadString(); + APP_LOGI("extract module %{public}s", targetPath.c_str()); + ErrCode result = ExtractModuleFiles(srcModulePath, targetPath); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, reply, result); + return true; +} + +bool InstalldHost::HandleRenameModuleDir(MessageParcel &data, MessageParcel &reply) +{ + std::string oldPath = data.ReadString(); + std::string newPath = data.ReadString(); + APP_LOGI("rename moduleDir %{public}s", oldPath.c_str()); + ErrCode result = RenameModuleDir(oldPath, newPath); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, reply, result); + return true; +} + +bool InstalldHost::HandleRemoveModuleDir(MessageParcel &data, MessageParcel &reply) +{ + std::string moduleDir = data.ReadString(); + APP_LOGI("remove moduleDir %{public}s", moduleDir.c_str()); + ErrCode result = RemoveModuleDir(moduleDir); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, reply, result); + return true; +} + +bool InstalldHost::HandleCreateBundleDataDir(MessageParcel &data, MessageParcel &reply) +{ + std::string bundleDir = data.ReadString(); + int uid = data.ReadInt32(); + int gid = data.ReadInt32(); + ErrCode result = CreateBundleDataDir(bundleDir, uid, gid); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, reply, result); + return true; +} + +bool InstalldHost::HandleRemoveBundleDataDir(MessageParcel &data, MessageParcel &reply) +{ + std::string bundleDataDir = data.ReadString(); + ErrCode result = RemoveBundleDataDir(bundleDataDir); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, reply, result); + return true; +} + +bool InstalldHost::HandleCreateModuleDataDir(MessageParcel &data, MessageParcel &reply) +{ + std::string bundleDir = data.ReadString(); + std::vector abilityDirs; + if (!data.ReadStringVector(&abilityDirs)) { + return false; + } + int uid = data.ReadInt32(); + int gid = data.ReadInt32(); + ErrCode result = CreateModuleDataDir(bundleDir, abilityDirs, uid, gid); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, reply, result); + return true; +} + +bool InstalldHost::HandleRemoveModuleDataDir(MessageParcel &data, MessageParcel &reply) +{ + std::string bundleDataDir = data.ReadString(); + ErrCode result = RemoveBundleDataDir(bundleDataDir); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, reply, result); + return true; +} + +bool InstalldHost::HandleCleanBundleDataDir(MessageParcel &data, MessageParcel &reply) +{ + std::string bundleDir = data.ReadString(); + ErrCode result = CleanBundleDataDir(bundleDir); + WRITE_PARCEL_AND_RETURN_FALSE_IF_FAIL(Int32, reply, result); + return true; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/bundlemgr/src/ipc/installd_proxy.cpp b/services/bundlemgr/src/ipc/installd_proxy.cpp new file mode 100644 index 000000000..af68c9a42 --- /dev/null +++ b/services/bundlemgr/src/ipc/installd_proxy.cpp @@ -0,0 +1,246 @@ +/* + * 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 "ipc/installd_proxy.h" + +#include "ipc_types.h" + +#include "app_log_wrapper.h" +#include "bundle_constants.h" +#include "parcel_macro.h" + +namespace OHOS { +namespace AppExecFwk { + +InstalldProxy::InstalldProxy(const sptr &object) : IRemoteProxy(object) +{ + APP_LOGI("installd proxy instance is created"); +} + +InstalldProxy::~InstalldProxy() +{ + APP_LOGI("installd proxy instance is destroyed"); +} + +ErrCode InstalldProxy::CreateBundleDir(const std::string &bundleDir) +{ + MessageParcel data; + MessageParcel reply; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to send cmd to service due to data.WriteInterfaceToken(GetDescriptor())"); + return false; + } + if (!data.WriteString(bundleDir)) { + return ERR_APPEXECFWK_INSTALL_INSTALLD_SERVICE_ERROR; + } + if (!TransactInstalldCmd(IInstalld::Message::CREATE_BUNDLE_DIR, data, reply)) { + return false; + } + return reply.ReadInt32(); +} + +ErrCode InstalldProxy::RemoveBundleDir(const std::string &bundleDir) +{ + MessageParcel data; + MessageParcel reply; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to send cmd to service due to data.WriteInterfaceToken(GetDescriptor())"); + return false; + } + if (!data.WriteString(bundleDir)) { + return ERR_APPEXECFWK_INSTALL_INSTALLD_SERVICE_ERROR; + } + if (!TransactInstalldCmd(IInstalld::Message::REMOVE_BUNDLE_DIR, data, reply)) { + return false; + } + return reply.ReadInt32(); +} + +ErrCode InstalldProxy::ExtractModuleFiles(const std::string &srcModulePath, const std::string &targetPath) +{ + MessageParcel data; + MessageParcel reply; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to send cmd to service due to data.WriteInterfaceToken(GetDescriptor())"); + return false; + } + if (!data.WriteString(srcModulePath)) { + return ERR_APPEXECFWK_INSTALL_INSTALLD_SERVICE_ERROR; + } + if (!data.WriteString(targetPath)) { + return ERR_APPEXECFWK_INSTALL_INSTALLD_SERVICE_ERROR; + } + if (!TransactInstalldCmd(IInstalld::Message::EXTRACT_MODULE_FILES, data, reply)) { + return false; + } + return reply.ReadInt32(); +} + +ErrCode InstalldProxy::RemoveModuleDir(const std::string &moduleDir) +{ + MessageParcel data; + MessageParcel reply; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to send cmd to service due to data.WriteInterfaceToken(GetDescriptor())"); + return false; + } + if (!data.WriteString(moduleDir)) { + return ERR_APPEXECFWK_INSTALL_INSTALLD_SERVICE_ERROR; + } + if (!TransactInstalldCmd(IInstalld::Message::REMOVE_MODULE_DIR, data, reply)) { + return false; + } + return reply.ReadInt32(); +} + +ErrCode InstalldProxy::RenameModuleDir(const std::string &oldPath, const std::string &newPath) +{ + MessageParcel data; + MessageParcel reply; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to send cmd to service due to data.WriteInterfaceToken(GetDescriptor())"); + return false; + } + if (!data.WriteString(oldPath)) { + return ERR_APPEXECFWK_INSTALL_INSTALLD_SERVICE_ERROR; + } + if (!data.WriteString(newPath)) { + return ERR_APPEXECFWK_INSTALL_INSTALLD_SERVICE_ERROR; + } + if (!TransactInstalldCmd(IInstalld::Message::RENAME_MODULE_DIR, data, reply)) { + return ERR_APPEXECFWK_INSTALL_INSTALLD_SERVICE_ERROR; + } + return reply.ReadInt32(); +} + +ErrCode InstalldProxy::CreateBundleDataDir(const std::string &bundleDir, const int uid, const int gid) +{ + MessageParcel data; + MessageParcel reply; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to send cmd to service due to data.WriteInterfaceToken(GetDescriptor())"); + return ERR_APPEXECFWK_INSTALL_INSTALLD_SERVICE_ERROR; + } + if (!data.WriteString(bundleDir)) { + return ERR_APPEXECFWK_INSTALL_INSTALLD_SERVICE_ERROR; + } + if (!data.WriteInt32(uid)) { + return ERR_APPEXECFWK_INSTALL_INSTALLD_SERVICE_ERROR; + } + if (!data.WriteInt32(gid)) { + return ERR_APPEXECFWK_INSTALL_INSTALLD_SERVICE_ERROR; + } + if (!TransactInstalldCmd(IInstalld::Message::CREATE_BUNDLE_DATA_DIR, data, reply)) { + return ERR_APPEXECFWK_INSTALL_INSTALLD_SERVICE_ERROR; + } + return reply.ReadInt32(); +} + +ErrCode InstalldProxy::RemoveBundleDataDir(const std::string &bundleDataPath) +{ + MessageParcel data; + MessageParcel reply; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to send cmd to service due to data.WriteInterfaceToken(GetDescriptor())"); + return false; + } + if (!data.WriteString(bundleDataPath)) { + return ERR_APPEXECFWK_INSTALL_INSTALLD_SERVICE_ERROR; + } + if (!TransactInstalldCmd(IInstalld::Message::REMOVE_BUNDLE_DATA_DIR, data, reply)) { + return false; + } + return reply.ReadInt32(); +} + +ErrCode InstalldProxy::CreateModuleDataDir( + const std::string &ModuleDir, const std::vector &abilityDirs, const int uid, const int gid) +{ + MessageParcel data; + MessageParcel reply; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to send cmd to service due to data.WriteInterfaceToken(GetDescriptor())"); + return ERR_APPEXECFWK_INSTALL_INSTALLD_SERVICE_ERROR; + } + if (!data.WriteString(ModuleDir)) { + return ERR_APPEXECFWK_INSTALL_INSTALLD_SERVICE_ERROR; + } + if (!data.WriteStringVector(abilityDirs)) { + return ERR_APPEXECFWK_INSTALL_INSTALLD_SERVICE_ERROR; + } + if (!data.WriteInt32(uid)) { + return ERR_APPEXECFWK_INSTALL_INSTALLD_SERVICE_ERROR; + } + if (!data.WriteInt32(gid)) { + return ERR_APPEXECFWK_INSTALL_INSTALLD_SERVICE_ERROR; + } + if (!TransactInstalldCmd(IInstalld::Message::CREATE_MODULE_DATA_DIR, data, reply)) { + return ERR_APPEXECFWK_INSTALL_INSTALLD_SERVICE_ERROR; + } + return reply.ReadInt32(); +} + +ErrCode InstalldProxy::RemoveModuleDataDir(const std::string &moduleDataDir) +{ + MessageParcel data; + MessageParcel reply; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to send cmd to service due to data.WriteInterfaceToken(GetDescriptor())"); + return false; + } + if (!data.WriteString(moduleDataDir)) { + return ERR_APPEXECFWK_INSTALL_INSTALLD_SERVICE_ERROR; + } + if (!TransactInstalldCmd(IInstalld::Message::REMOVE_MODULE_DATA_DIR, data, reply)) { + return false; + } + return reply.ReadInt32(); +} + +ErrCode InstalldProxy::CleanBundleDataDir(const std::string &bundleDir) +{ + MessageParcel data; + MessageParcel reply; + if (!data.WriteInterfaceToken(GetDescriptor())) { + APP_LOGE("fail to send cmd to service due to data.WriteInterfaceToken(GetDescriptor())"); + return false; + } + if (!data.WriteString(bundleDir)) { + return ERR_APPEXECFWK_INSTALL_INSTALLD_SERVICE_ERROR; + } + if (!TransactInstalldCmd(IInstalld::Message::CLEAN_BUNDLE_DATA_DIR, data, reply)) { + return ERR_APPEXECFWK_INSTALL_INSTALLD_SERVICE_ERROR; + } + return reply.ReadInt32(); +} + +bool InstalldProxy::TransactInstalldCmd(IInstalld::Message code, MessageParcel &data, MessageParcel &reply) +{ + sptr remote = Remote(); + MessageOption option(MessageOption::TF_SYNC); + if (remote == nullptr) { + APP_LOGE("fail to send %{public}d cmd to service due to remote object is null", code); + return false; + } + int32_t result = remote->SendRequest(static_cast(code), data, reply, option); + if (result != OHOS::NO_ERROR) { + APP_LOGE("fail to send %{public}d cmd to service due to transact error", code); + return false; + } + return true; +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/bundlemgr/src/system_ability_helper.cpp b/services/bundlemgr/src/system_ability_helper.cpp new file mode 100644 index 000000000..c70896bb4 --- /dev/null +++ b/services/bundlemgr/src/system_ability_helper.cpp @@ -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. + */ + +#include "system_ability_helper.h" + +#include "string_ex.h" +#include "if_system_ability_manager.h" +#include "iservice_registry.h" +#include "ipc_skeleton.h" +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { + +sptr SystemAbilityHelper::GetSystemAbility(const int32_t systemAbilityId) +{ + sptr systemAbilityMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (!systemAbilityMgr) { + APP_LOGE("fail to get the system ability manager to get %{public}d proxy", systemAbilityId); + return nullptr; + } + return systemAbilityMgr->GetSystemAbility(systemAbilityId); +} + +bool SystemAbilityHelper::AddSystemAbility(const int32_t systemAbilityId, const sptr &systemAbility) +{ + sptr systemAbilityMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (systemAbilityMgr && (systemAbilityMgr->AddSystemAbility(systemAbilityId, systemAbility) == 0)) { + return true; + } + APP_LOGE("fail to register %{public}d to system ability manager", systemAbilityId); + return false; +} + +bool SystemAbilityHelper::RemoveSystemAbility(const int32_t systemAbilityId) +{ + sptr systemAbilityMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (systemAbilityMgr && (systemAbilityMgr->RemoveSystemAbility(systemAbilityId) == 0)) { + return true; + } + APP_LOGE("fail to remove %{public}d from system ability manager", systemAbilityId); + return false; +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/bundlemgr/src/system_bundle_installer.cpp b/services/bundlemgr/src/system_bundle_installer.cpp new file mode 100644 index 000000000..ded37b5f6 --- /dev/null +++ b/services/bundlemgr/src/system_bundle_installer.cpp @@ -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. + */ + +#include "system_bundle_installer.h" + +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { + +SystemBundleInstaller::SystemBundleInstaller(const std::string &filePath) : filePath_(filePath) +{ + APP_LOGI("system bundle installer instance is created"); +} + +SystemBundleInstaller::~SystemBundleInstaller() +{ + APP_LOGI("system bundle installer instance is destroyed"); +} + +bool SystemBundleInstaller::InstallSystemBundle(Constants::AppType appType) +{ + InstallParam installParam; + installParam.userId = Constants::DEFAULT_USERID; + ErrCode result = InstallBundle(filePath_, installParam, appType); + if (result != ERR_OK) { + APP_LOGE("install system bundle fail, error: %{public}d", result); + return false; + } + return true; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/bundlemgr/src/zip_file.cpp b/services/bundlemgr/src/zip_file.cpp new file mode 100755 index 000000000..211aecd46 --- /dev/null +++ b/services/bundlemgr/src/zip_file.cpp @@ -0,0 +1,583 @@ +/* + * 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 "zip_file.h" + +#include +#include +#include + +#include "securec.h" +#include "zlib.h" +#include "app_log_wrapper.h" + +namespace OHOS { +namespace AppExecFwk { +namespace { + +constexpr uint32_t MAX_FILE_NAME = 256; +constexpr uint32_t UNZIP_BUFFER_SIZE = 1024; +constexpr uint32_t UNZIP_BUF_IN_LEN = 160 * UNZIP_BUFFER_SIZE; // in buffer length: 160KB +constexpr uint32_t UNZIP_BUF_OUT_LEN = 320 * UNZIP_BUFFER_SIZE; // out buffer length: 320KB +constexpr uint32_t LOCAL_HEADER_SIGNATURE = 0x04034b50; +constexpr uint32_t CENTRAL_SIGNATURE = 0x02014b50; +constexpr uint32_t EOCD_SIGNATURE = 0x06054b50; +constexpr uint32_t DATA_DESC_SIGNATURE = 0x08074b50; +constexpr uint32_t FLAG_DATA_DESC = 0x8; +constexpr size_t FILE_READ_COUNT = 1; + +} // namespace + +ZipEntry::ZipEntry(const CentralDirEntry ¢ralEntry) +{ + compressionMethod = centralEntry.compressionMethod; + uncompressedSize = centralEntry.uncompressedSize; + compressedSize = centralEntry.compressedSize; + localHeaderOffset = centralEntry.localHeaderOffset; + crc = centralEntry.crc; + flags = centralEntry.flags; +} + +ZipFile::ZipFile(const std::string &pathName) : pathName_(pathName) +{ + APP_LOGI("create instance from %{private}s", pathName_.c_str()); +} + +ZipFile::~ZipFile() +{ + Close(); +} + +void ZipFile::SetContentLocation(const ZipPos start, const size_t length) +{ + APP_LOGD("set content location start position(%{public}llu), length(%{public}zu)", start, length); + fileStartPos_ = start; + fileLength_ = length; +} + +bool ZipFile::CheckEndDir(const EndDir &endDir) const +{ + size_t lenEndDir = sizeof(EndDir); + if ((endDir.numDisk != 0) || (endDir.signature != EOCD_SIGNATURE) || (endDir.startDiskOfCentralDir != 0) || + (endDir.offset >= fileLength_) || (endDir.totalEntriesInThisDisk != endDir.totalEntries) || + (endDir.commentLen != 0) || + // central dir can't overlap end of central dir + ((endDir.offset + endDir.sizeOfCentralDir + lenEndDir) > fileLength_)) { + APP_LOGE("end dir format error"); + return false; + } + return true; +} + +bool ZipFile::ParseEndDirectory() +{ + size_t endDirLen = sizeof(EndDir); + size_t endFilePos = fileStartPos_ + fileLength_; + + if (fileLength_ <= endDirLen) { + APP_LOGE("parse EOCD file length(%{public}llu) <= end dir length(%{public}llu)", fileStartPos_, fileLength_); + return false; + } + + size_t eocdPos = endFilePos - endDirLen; + if (fseek(file_, eocdPos, SEEK_SET) != 0) { + APP_LOGE("locate EOCD seek failed, error: %{public}s", strerror(errno)); + return false; + } + + if (fread(&endDir_, sizeof(EndDir), FILE_READ_COUNT, file_) != FILE_READ_COUNT) { + APP_LOGE("read EOCD struct failed, error: %{public}s", strerror(errno)); + return false; + } + + centralDirPos_ = endDir_.offset + fileStartPos_; + APP_LOGD("parse EOCD offset(0x%{public}08x) file start position(0x%{public}08llx)", endDir_.offset, fileStartPos_); + + return CheckEndDir(endDir_); +} + +bool ZipFile::ParseAllEntries() +{ + bool ret = true; + ZipPos currentPos = centralDirPos_; + CentralDirEntry directoryEntry = {0}; + size_t fileLength = 0; + + for (int32_t i = 0; i < endDir_.totalEntries; i++) { + std::string fileName; + fileName.reserve(MAX_FILE_NAME); + fileName.resize(MAX_FILE_NAME - 1); + + if (fseek(file_, currentPos, SEEK_SET) != 0) { + APP_LOGE("parse entry(%{public}d) seek zipEntry failed, error: %{public}s", i, strerror(errno)); + ret = false; + break; + } + + if (fread(&directoryEntry, sizeof(CentralDirEntry), FILE_READ_COUNT, file_) != FILE_READ_COUNT) { + APP_LOGE("parse entry(%{public}d) read ZipEntry failed, error: %{public}s", i, strerror(errno)); + ret = false; + break; + } + + if (directoryEntry.signature != CENTRAL_SIGNATURE) { + APP_LOGE("parse entry(%{public}d) check signature(0x%08x) at pos(0x%08llx) failed", + i, + directoryEntry.signature, + currentPos); + ret = false; + break; + } + + fileLength = (directoryEntry.nameSize >= MAX_FILE_NAME) ? (MAX_FILE_NAME - 1) : directoryEntry.nameSize; + if (fread(&(fileName[0]), fileLength, FILE_READ_COUNT, file_) != FILE_READ_COUNT) { + APP_LOGE("parse entry(%{public}d) read file name failed, error: %{public}s", i, strerror(errno)); + ret = false; + break; + } + fileName.resize(fileLength); + + ZipEntry currentEntry(directoryEntry); + currentEntry.fileName = fileName; + entriesMap_[fileName] = currentEntry; + + currentPos += sizeof(directoryEntry); + currentPos += directoryEntry.nameSize + directoryEntry.extraSize + directoryEntry.commentSize; + } + + APP_LOGD("parse %{public}d central entries from %{private}s", endDir_.totalEntries, pathName_.c_str()); + return ret; +} + +bool ZipFile::Open() +{ + APP_LOGD("open: %{private}s", pathName_.c_str()); + + if (isOpen_) { + APP_LOGE("has already opened"); + return true; + } + + if (pathName_.length() > PATH_MAX) { + APP_LOGE("path length(%{public}u) longer than max path length(%{public}d)", + static_cast(pathName_.length()), + PATH_MAX); + return false; + } + std::string realPath; + realPath.reserve(PATH_MAX); + realPath.resize(PATH_MAX - 1); + if (realpath(pathName_.c_str(), &(realPath[0])) == nullptr) { + APP_LOGE("transform real path error: %{public}s", strerror(errno)); + return false; + } + + FILE *tmpFile = fopen(&(realPath[0]), "rb"); + if (tmpFile == nullptr) { + APP_LOGE("open file(%{private}s) failed, error: %{public}s", pathName_.c_str(), strerror(errno)); + return false; + } + + if (fileLength_ == 0) { + if (fseek(tmpFile, 0, SEEK_END) != 0) { + APP_LOGE("file seek failed, error: %{public}s", strerror(errno)); + fclose(tmpFile); + return false; + } + + fileLength_ = ftell(tmpFile); + if (fileStartPos_ >= fileLength_) { + APP_LOGE("open start pos > length failed"); + fclose(tmpFile); + return false; + } + + fileLength_ -= fileStartPos_; + } + + file_ = tmpFile; + bool result = ParseEndDirectory(); + if (result) { + result = ParseAllEntries(); + } + // it means open file success. + isOpen_ = true; + return result; +} + +void ZipFile::Close() +{ + APP_LOGD("close: %{private}s", pathName_.c_str()); + + if (!isOpen_ || file_ == nullptr) { + APP_LOGW("file is not opened"); + return; + } + + entriesMap_.clear(); + pathName_ = ""; + isOpen_ = false; + + if (fclose(file_) != 0) { + APP_LOGW("close failed, error: %{public}s", strerror(errno)); + } + file_ = nullptr; +} + +// Get all file zipEntry in this file +const ZipEntryMap &ZipFile::GetAllEntries() const +{ + return entriesMap_; +} + +bool ZipFile::GetEntry(const std::string &entryName, ZipEntry &resultEntry) const +{ + APP_LOGD("get entry by name: %{public}s", entryName.c_str()); + auto iter = entriesMap_.find(entryName); + if (iter != entriesMap_.end()) { + resultEntry = iter->second; + APP_LOGD("get entry succeed"); + return true; + } + APP_LOGE("get entry failed"); + return false; +} + +size_t ZipFile::GetLocalHeaderSize(const uint16_t nameSize, const uint16_t extraSize) const +{ + return sizeof(LocalHeader) + nameSize + extraSize; +} + +bool ZipFile::CheckDataDesc(const ZipEntry &zipEntry, const LocalHeader &localHeader) const +{ + uint32_t crcLocal = 0; + uint32_t compressedLocal = 0; + uint32_t uncompressedLocal = 0; + + if (localHeader.flags & FLAG_DATA_DESC) { // use data desc + DataDesc dataDesc; + ZipPos descPos = zipEntry.localHeaderOffset + GetLocalHeaderSize(localHeader.nameSize, localHeader.extraSize); + descPos += fileStartPos_ + zipEntry.compressedSize; + + if (fseek(file_, descPos, SEEK_SET) != 0) { + APP_LOGE("check local header seek datadesc failed, error: %{public}s", strerror(errno)); + return false; + } + + if (fread(&dataDesc, sizeof(DataDesc), FILE_READ_COUNT, file_) != FILE_READ_COUNT) { + APP_LOGE("check local header read datadesc failed, error: %{public}s", strerror(errno)); + return false; + } + + if (dataDesc.signature != DATA_DESC_SIGNATURE) { + APP_LOGE("check local header check datadesc signature failed"); + return false; + } + + crcLocal = dataDesc.crc; + compressedLocal = dataDesc.compressedSize; + uncompressedLocal = dataDesc.uncompressedSize; + } else { + crcLocal = localHeader.crc; + compressedLocal = localHeader.compressedSize; + uncompressedLocal = localHeader.uncompressedSize; + } + + if ((zipEntry.crc != crcLocal) || (zipEntry.compressedSize != compressedLocal) || + (zipEntry.uncompressedSize != uncompressedLocal)) { + APP_LOGE("check local header compressed size corrupted"); + return false; + } + + return true; +} + +bool ZipFile::CheckCoherencyLocalHeader(const ZipEntry &zipEntry, uint16_t &extraSize) const +{ + LocalHeader localHeader = {0}; + + if (zipEntry.localHeaderOffset >= fileLength_) { + APP_LOGE("check local file header offset is overflow %{public}d", zipEntry.localHeaderOffset); + return false; + } + + if (fseek(file_, fileStartPos_ + zipEntry.localHeaderOffset, SEEK_SET) != 0) { + APP_LOGE("check local header seek failed, error: %{public}s", strerror(errno)); + return false; + } + + if (fread(&localHeader, sizeof(LocalHeader), FILE_READ_COUNT, file_) != FILE_READ_COUNT) { + APP_LOGE("check local header read localheader failed, error: %{public}s", strerror(errno)); + return false; + } + + if ((localHeader.signature != LOCAL_HEADER_SIGNATURE) || + (zipEntry.compressionMethod != localHeader.compressionMethod)) { + APP_LOGE("check local header signature or compressionMethod failed"); + return false; + } + + // current only support store and Z_DEFLATED method + if ((zipEntry.compressionMethod != Z_DEFLATED) && (zipEntry.compressionMethod != 0)) { + APP_LOGE("check local header compressionMethod(%{public}d) not support", zipEntry.compressionMethod); + return false; + } + + std::string fileName; + fileName.reserve(MAX_FILE_NAME); + fileName.resize(MAX_FILE_NAME - 1); + size_t fileLength = (localHeader.nameSize >= MAX_FILE_NAME) ? (MAX_FILE_NAME - 1) : localHeader.nameSize; + if (fileLength != zipEntry.fileName.length()) { + APP_LOGE("check local header file name size failed"); + return false; + } + if (fread(&(fileName[0]), fileLength, FILE_READ_COUNT, file_) != FILE_READ_COUNT) { + APP_LOGE("check local header read file name failed, error: %{public}s", strerror(errno)); + return false; + } + fileName.resize(fileLength); + if (zipEntry.fileName != fileName) { + APP_LOGE("check local header file name corrupted"); + return false; + } + + if (!CheckDataDesc(zipEntry, localHeader)) { + APP_LOGE("check data desc failed"); + return false; + } + + extraSize = localHeader.extraSize; + return true; +} + +bool ZipFile::SeekToEntryStart(const ZipEntry &zipEntry, const uint16_t extraSize) const +{ + ZipPos startOffset = zipEntry.localHeaderOffset; + // get data offset, add signature+localheader+namesize+extrasize + startOffset += GetLocalHeaderSize(zipEntry.fileName.length(), extraSize); + if (startOffset + zipEntry.compressedSize > fileLength_) { + APP_LOGE("startOffset(%{public}lld)+entryCompressedSize(%{public}ud) > fileLength(%{public}llu)", + startOffset, + zipEntry.compressedSize, + fileLength_); + return false; + } + startOffset += fileStartPos_; // add file start relative to file stream + + APP_LOGD("seek to entry start 0x%{public}08llx", startOffset); + if (fseek(file_, startOffset, SEEK_SET) != 0) { + APP_LOGE("seek failed, error: %{public}s", strerror(errno)); + return false; + } + return true; +} + +bool ZipFile::UnzipWithStore(const ZipEntry &zipEntry, const uint16_t extraSize, std::ostream &dest) const +{ + APP_LOGD("unzip with store"); + + if (!SeekToEntryStart(zipEntry, extraSize)) { + APP_LOGE("seek to entry start failed"); + return false; + } + + uint32_t remainSize = zipEntry.compressedSize; + std::string readBuffer; + readBuffer.reserve(UNZIP_BUF_OUT_LEN); + readBuffer.resize(UNZIP_BUF_OUT_LEN - 1); + while (remainSize > 0) { + size_t readBytes; + size_t readLen = (remainSize > UNZIP_BUF_OUT_LEN) ? UNZIP_BUF_OUT_LEN : remainSize; + readBytes = fread(&(readBuffer[0]), sizeof(Byte), readLen, file_); + if (readBytes == 0) { + APP_LOGE("unzip store read failed, error: %{public}s", strerror(errno)); + return false; + } + remainSize -= readBytes; + dest.write(&(readBuffer[0]), readBytes); + } + + return true; +} + +bool ZipFile::InitZStream(z_stream &zstream) const +{ + // init zlib stream + if (memset_s(&zstream, sizeof(z_stream), 0, sizeof(z_stream))) { + APP_LOGE("unzip stream buffer init failed"); + return false; + } + int32_t zlibErr = inflateInit2(&zstream, -MAX_WBITS); + if (zlibErr != Z_OK) { + APP_LOGE("unzip inflated init failed"); + return false; + } + + BytePtr bufOut = new (std::nothrow) Byte[UNZIP_BUF_OUT_LEN]; + if (bufOut == nullptr) { + APP_LOGE("unzip inflated new out buffer failed"); + return false; + } + + BytePtr bufIn = new (std::nothrow) Byte[UNZIP_BUF_IN_LEN]; + if (bufIn == nullptr) { + APP_LOGE("unzip inflated new in buffer failed"); + delete[] bufOut; + return false; + } + zstream.next_out = bufOut; + zstream.next_in = bufIn; + zstream.avail_out = UNZIP_BUF_OUT_LEN; + return true; +} + +bool ZipFile::ReadZStream(const BytePtr &buffer, z_stream &zstream, uint32_t &remainCompressedSize) const +{ + if (zstream.avail_in == 0) { + size_t readBytes; + size_t remainBytes = (remainCompressedSize > UNZIP_BUF_IN_LEN) ? UNZIP_BUF_IN_LEN : remainCompressedSize; + readBytes = fread(buffer, sizeof(Byte), remainBytes, file_); + if (readBytes == 0) { + APP_LOGE("unzip inflated read failed, error: %{public}s", strerror(errno)); + return false; + } + + remainCompressedSize -= readBytes; + zstream.avail_in = readBytes; + zstream.next_in = buffer; + } + return true; +} + +bool ZipFile::UnzipWithInflated(const ZipEntry &zipEntry, const uint16_t extraSize, std::ostream &dest) const +{ + APP_LOGD("unzip with inflated"); + + z_stream zstream; + if (!SeekToEntryStart(zipEntry, extraSize)) { + APP_LOGE("seek to entry start failed"); + return false; + } + if (!InitZStream(zstream)) { + APP_LOGE("init zstream failed"); + return false; + } + BytePtr bufIn = zstream.next_in; + BytePtr bufOut = zstream.next_out; + + bool ret = true; + int32_t zlibErr = Z_OK; + uint32_t remainCompressedSize = zipEntry.compressedSize; + size_t inflateLen = 0; + uint32_t crc = 0; + while ((remainCompressedSize > 0) || (zstream.avail_in > 0)) { + if (!ReadZStream(bufIn, zstream, remainCompressedSize)) { + ret = false; + break; + } + + zlibErr = inflate(&zstream, Z_SYNC_FLUSH); + if ((zlibErr >= Z_OK) && (zstream.msg != nullptr)) { + APP_LOGE("unzip inflated inflate, error: %{public}d, err msg: %{public}s", zlibErr, zstream.msg); + ret = false; + break; + } + + inflateLen = UNZIP_BUF_OUT_LEN - zstream.avail_out; + if (inflateLen > 0) { + dest.write((const char *)bufOut, inflateLen); + crc = crc32(crc, bufOut, inflateLen); + zstream.next_out = bufOut; + zstream.avail_out = UNZIP_BUF_OUT_LEN; + } + } + + if (crc != zipEntry.crc) { + APP_LOGE("unzip inflate crc check"); + ret = false; + } + + // free all dynamically allocated data structures except the next_in and next_out for this stream. + zlibErr = inflateEnd(&zstream); + if (zlibErr != Z_OK) { + APP_LOGE("unzip inflateEnd error, error: %{public}d", zlibErr); + ret = false; + } + + delete[] bufOut; + delete[] bufIn; + return ret; +} + +ZipPos ZipFile::GetEntryDataOffset(const ZipEntry &zipEntry, const uint16_t extraSize) const +{ + // get entry data offset relative file + ZipPos offset = zipEntry.localHeaderOffset; + + offset += GetLocalHeaderSize(zipEntry.fileName.length(), extraSize); + offset += fileStartPos_; + + return offset; +} + +bool ZipFile::GetDataOffsetRelative(const std::string &file, ZipPos &offset, uint32_t &length) const +{ + APP_LOGD("get data relative offset for file %{private}s", file.c_str()); + + ZipEntry zipEntry; + if (!GetEntry(file, zipEntry)) { + APP_LOGE("extract file: not find file"); + return false; + } + + uint16_t extraSize = 0; + if (!CheckCoherencyLocalHeader(zipEntry, extraSize)) { + APP_LOGE("check coherency local header failed"); + return false; + } + + offset = GetEntryDataOffset(zipEntry, extraSize); + length = zipEntry.compressedSize; + return true; +} + +bool ZipFile::ExtractFile(const std::string &file, std::ostream &dest) const +{ + APP_LOGD("extract file %{private}s", file.c_str()); + + ZipEntry zipEntry; + if (!GetEntry(file, zipEntry)) { + APP_LOGE("extract file: not find file"); + return false; + } + + uint16_t extraSize = 0; + if (!CheckCoherencyLocalHeader(zipEntry, extraSize)) { + APP_LOGE("check coherency local header failed"); + return false; + } + + bool ret = true; + if (zipEntry.compressionMethod == 0) { + ret = UnzipWithStore(zipEntry, extraSize, dest); + } else { + ret = UnzipWithInflated(zipEntry, extraSize, dest); + } + + return ret; +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/bundlemgr/test/BUILD.gn b/services/bundlemgr/test/BUILD.gn new file mode 100644 index 000000000..77a05151a --- /dev/null +++ b/services/bundlemgr/test/BUILD.gn @@ -0,0 +1,52 @@ +# 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("bundlemgr_test_config") { + include_dirs = [ + "//utils/native/base/include", + "//utils/system/safwk/native/include", + "mock/include", + "//foundation/aafwk/standard/interfaces/innerkits/want/include/ohos/aafwk/content/", + "//foundation/aafwk/standard/interfaces/innerkits/base/include", + "//foundation/aafwk/standard/interfaces/innerkits/ability_manager/include", + "//foundation/distributedschedule/dmsfwk/services/dtbschedmgr/include", + "//foundation/aafwk/standard/services/abilitymgr/include", + "//foundation/aafwk/standard/services/common/include", + "//base/notification/ces_standard/cesfwk/kits/native/include", + ] + + configs = [ + "${services_path}/bundlemgr:bundlemgr_config", + "${services_path}/bundlemgr:bundlemgr_common_config", + "${common_path}:appexecfwk_common_config", + ] +} + +group("unittest") { + testonly = true + + deps = [ + "unittest/bms_bundle_data_storage_test:unittest", + "unittest/bms_bundle_installer_test:unittest", + "unittest/bms_bundle_kit_service_test:unittest", + "unittest/bms_bundle_parser_test:unittest", + "unittest/bms_bundle_uninstaller_test:unittest", + "unittest/bms_bundle_updater_test:unittest", + "unittest/bms_data_mgr_test:unittest", + "unittest/bms_install_daemon_test:unittest", + "unittest/bms_service_bundle_scan_test:unittest", + "unittest/bms_service_startup_test:unittest", + ] +} diff --git a/services/bundlemgr/test/mock/include/json_constants.h b/services/bundlemgr/test/mock/include/json_constants.h new file mode 100644 index 000000000..7019d89ac --- /dev/null +++ b/services/bundlemgr/test/mock/include/json_constants.h @@ -0,0 +1,72 @@ +/* + * 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_INCLUDE_JSON_CONSTANTS_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_TEST_MOCK_INCLUDE_JSON_CONSTANTS_H + +#include "nlohmann/json.hpp" + +namespace OHOS { +namespace AppExecFwk { +namespace JsonConstants { + +const nlohmann::json NOT_STRING_TYPE = R"( + { + "number": 234, + "bool": true, + "object": {}, + "array": [] + } + )"_json; + +const nlohmann::json NOT_NUMBER_TYPE = R"( + { + "string": "info", + "object": {}, + "array": [] + } + )"_json; + +const nlohmann::json NOT_BOOL_TYPE = R"( + { + "number": 234, + "string": "info", + "object": {}, + "array": [] + } + )"_json; + +const nlohmann::json NOT_OBJECT_TYPE = R"( + { + "bool": true, + "number": 234, + "string": "info", + "array": [] + } + )"_json; + +const nlohmann::json NOT_ARRAY_TYPE = R"( + { + "bool": true, + "number": 234, + "string": "info", + "object": {} + } + )"_json; + +} // namespace JsonConstants +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_TEST_MOCK_INCLUDE_JSON_CONSTANTS_H \ 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 new file mode 100644 index 000000000..ef55701eb --- /dev/null +++ b/services/bundlemgr/test/mock/include/mock_ability_mgr_host.h @@ -0,0 +1,146 @@ +/* + * 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" + +namespace OHOS { +namespace AppExecFwk { + +class MockAbilityMgrStub : public IRemoteStub { +public: + using Uri = OHOS::Uri; + MockAbilityMgrStub() = default; + virtual ~MockAbilityMgrStub() = default; + + 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 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 GetMissionSnapshot(const int32_t missionId, AAFwk::MissionSnapshotInfo &snapshot) + { + return 0; + } + virtual int MoveMissionToTop(int32_t missionId) + { + 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; + } +}; + +} // 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/bundlemgr/test/mock/include/mock_bundle_status.h b/services/bundlemgr/test/mock/include/mock_bundle_status.h new file mode 100644 index 000000000..c68bdd27c --- /dev/null +++ b/services/bundlemgr/test/mock/include/mock_bundle_status.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_SERVICES_BUNDLEMGR_TEST_MOCK_INCLUDE_MOCK_BUNDLE_STATUS_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_TEST_MOCK_INCLUDE_MOCK_BUNDLE_STATUS_H + +#include + +#include "nocopyable.h" + +#include "bundle_status_callback_interface.h" + +namespace OHOS { +namespace AppExecFwk { + +class MockBundleStatus : public IBundleStatusCallback { +public: + MockBundleStatus() = default; + virtual ~MockBundleStatus() override = default; + + virtual void OnBundleStateChanged(const uint8_t installType, const int32_t resultCode, const std::string &resultMsg, + const std::string &bundleName) override; + virtual sptr AsObject() override; + int32_t GetResultCode(); + +private: + std::promise signal_; + + DISALLOW_COPY_AND_MOVE(MockBundleStatus); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_TEST_MOCK_INCLUDE_MOCK_BUNDLE_STATUS_H \ No newline at end of file diff --git a/services/bundlemgr/test/mock/include/mock_clean_cache.h b/services/bundlemgr/test/mock/include/mock_clean_cache.h new file mode 100644 index 000000000..9dfa562af --- /dev/null +++ b/services/bundlemgr/test/mock/include/mock_clean_cache.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 FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_TEST_MOCK_INCLUDE_MOCK_CLEAN_CACHE_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_TEST_MOCK_INCLUDE_MOCK_CLEAN_CACHE_H + +#include + +#include "nocopyable.h" + +#include "clean_cache_callback_interface.h" + +namespace OHOS { +namespace AppExecFwk { + +class MockCleanCache : public ICleanCacheCallback { +public: + MockCleanCache() = default; + virtual ~MockCleanCache() override = default; + + virtual void OnCleanCacheFinished(bool succeeded) override; + virtual sptr AsObject() override; + bool GetResultCode(); + +private: + std::promise signal_; + + DISALLOW_COPY_AND_MOVE(MockCleanCache); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_TEST_MOCK_INCLUDE_MOCK_CLEAN_CACHE_H \ No newline at end of file diff --git a/services/bundlemgr/test/mock/include/mock_status_receiver.h b/services/bundlemgr/test/mock/include/mock_status_receiver.h new file mode 100644 index 000000000..1085c272f --- /dev/null +++ b/services/bundlemgr/test/mock/include/mock_status_receiver.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_SERVICES_BUNDLEMGR_TEST_MOCK_INCLUDE_MOCK_STATUS_RECEIVER_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_TEST_MOCK_INCLUDE_MOCK_STATUS_RECEIVER_H + +#include + +#include "nocopyable.h" + +#include "status_receiver_interface.h" + +namespace OHOS { +namespace AppExecFwk { + +class MockStatusReceiver : public IStatusReceiver { +public: + MockStatusReceiver() = default; + virtual ~MockStatusReceiver() override = default; + + virtual void OnStatusNotify(const int32_t progress) override; + virtual void OnFinished(const int32_t resultCode, [[maybe_unused]] const std::string &resultMsg) override; + virtual sptr AsObject() override; + int32_t GetResultCode(); + +private: + std::promise signal_; + + DISALLOW_COPY_AND_MOVE(MockStatusReceiver); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_TEST_MOCK_INCLUDE_MOCK_STATUS_RECEIVER_H \ No newline at end of file diff --git a/services/bundlemgr/test/mock/src/mock_bundle_status.cpp b/services/bundlemgr/test/mock/src/mock_bundle_status.cpp new file mode 100644 index 000000000..6797ae081 --- /dev/null +++ b/services/bundlemgr/test/mock/src/mock_bundle_status.cpp @@ -0,0 +1,44 @@ +/* + * 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 "mock_bundle_status.h" + +namespace OHOS { +namespace AppExecFwk { + +void MockBundleStatus::OnBundleStateChanged( + const uint8_t installType, const int32_t resultCode, const std::string &resultMsg, const std::string &bundleName) +{ + signal_.set_value(resultCode); +} + +sptr MockBundleStatus::AsObject() +{ + return nullptr; +} + +int32_t MockBundleStatus::GetResultCode() +{ + auto future = signal_.get_future(); + std::future_status status = future.wait_for(std::chrono::seconds(1)); + if (status == std::future_status::timeout) { + return ERR_TIMED_OUT; + } else { + return future.get(); + } +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/bundlemgr/test/mock/src/mock_clean_cache.cpp b/services/bundlemgr/test/mock/src/mock_clean_cache.cpp new file mode 100644 index 000000000..4440d44be --- /dev/null +++ b/services/bundlemgr/test/mock/src/mock_clean_cache.cpp @@ -0,0 +1,39 @@ +/* + * 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 "mock_clean_cache.h" + +namespace OHOS { +namespace AppExecFwk { + +void MockCleanCache::OnCleanCacheFinished(bool succeeded) +{ + signal_.set_value(succeeded); +} + +sptr MockCleanCache::AsObject() +{ + return nullptr; +} + +bool MockCleanCache::GetResultCode() +{ + auto future = signal_.get_future(); + future.wait(); + return future.get(); +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/bundlemgr/test/mock/src/mock_status_receiver.cpp b/services/bundlemgr/test/mock/src/mock_status_receiver.cpp new file mode 100644 index 000000000..cd8b57538 --- /dev/null +++ b/services/bundlemgr/test/mock/src/mock_status_receiver.cpp @@ -0,0 +1,44 @@ +/* + * 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 "mock_status_receiver.h" + +namespace OHOS { +namespace AppExecFwk { + +void MockStatusReceiver::OnFinished(const int32_t resultCode, [[maybe_unused]] const std::string &resultMsg) +{ + signal_.set_value(resultCode); +} + +void MockStatusReceiver::OnStatusNotify(const int32_t progress) +{ + return; +} + +sptr MockStatusReceiver::AsObject() +{ + return nullptr; +} + +int32_t MockStatusReceiver::GetResultCode() +{ + auto future = signal_.get_future(); + future.wait(); + return future.get(); +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/bundlemgr/test/mock/src/system_ability_helper.cpp b/services/bundlemgr/test/mock/src/system_ability_helper.cpp new file mode 100644 index 000000000..92c65c289 --- /dev/null +++ b/services/bundlemgr/test/mock/src/system_ability_helper.cpp @@ -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. + */ + +#include "system_ability_helper.h" + +#include + +#include "system_ability_definition.h" +#include "app_log_wrapper.h" +#include "mock_ability_mgr_host.h" + +namespace OHOS { +namespace AppExecFwk { +namespace { + +std::map> g_abilities; + +} // namespace + +sptr SystemAbilityHelper::GetSystemAbility(const int32_t systemAbilityId) +{ + APP_LOGD("mock system ability helper get %{public}d system ability", systemAbilityId); + auto iter = g_abilities.find(systemAbilityId); + if (iter != g_abilities.end()) { + return iter->second; + } + if (systemAbilityId == ABILITY_MGR_SERVICE_ID) { + return new (std::nothrow) MockAbilityMgrStub(); + } + return nullptr; +} + +bool SystemAbilityHelper::AddSystemAbility(const int32_t systemAbilityId, const sptr &systemAbility) +{ + if (g_abilities.erase(systemAbilityId) > 0) { + APP_LOGD("mock system ability helper add system ability erase exist key"); + } + APP_LOGD("mock system ability helper emplace %{public}d system ability", systemAbilityId); + g_abilities.emplace(systemAbilityId, systemAbility); + // mock helper always return true. + return true; +} + +bool SystemAbilityHelper::RemoveSystemAbility(const int32_t systemAbilityId) +{ + APP_LOGD("mock system ability helper remove system ability"); + if (g_abilities.erase(systemAbilityId) > 0) { + APP_LOGD("mock system ability helper remove %{public}d system ability erase exist key", systemAbilityId); + } + // mock helper always return true. + return true; +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/bundlemgr/test/unittest/bms_bundle_data_storage_test/BUILD.gn b/services/bundlemgr/test/unittest/bms_bundle_data_storage_test/BUILD.gn new file mode 100644 index 000000000..e218a3bac --- /dev/null +++ b/services/bundlemgr/test/unittest/bms_bundle_data_storage_test/BUILD.gn @@ -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. + +import("//build/test.gni") +import("//foundation/appexecfwk/standard/appexecfwk.gni") + +config("private_config") { + include_dirs = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core/include/bundlemgr", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base/include", + "${appexecfwk_path}/libs/test/mockpermission/permission", + "${services_path}/bundlemgr/test/mock/include", + "//third_party/json/include", + ] + + cflags_cc = [ "-fexceptions" ] +} + +module_output_path = "appexecfwk_standard/bundlemgrservice" + +ohos_unittest("BmsBundleDataStorageTest") { + module_out_path = module_output_path + + sources = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base/src/ability_info.cpp", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base/src/application_info.cpp", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base/src/bundle_info.cpp", + "${services_path}/bundlemgr/src/bundle_data_storage.cpp", + "${services_path}/bundlemgr/src/inner_bundle_info.cpp", + ] + + sources += [ "bms_bundle_data_storage_test.cpp" ] + + configs = [ + ":private_config", + "${services_path}/bundlemgr/test:bundlemgr_test_config", + "${services_path}/bundlemgr:bundlemgr_common_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${services_path}/bundlemgr:bundle_parser", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//third_party/googletest:gtest_main", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":BmsBundleDataStorageTest" ] +} 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 new file mode 100755 index 000000000..73aab1607 --- /dev/null +++ b/services/bundlemgr/test/unittest/bms_bundle_data_storage_test/bms_bundle_data_storage_test.cpp @@ -0,0 +1,663 @@ +/* + * 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 "json_constants.h" +#include "json_serializer.h" +#include "nlohmann/json.hpp" +#include "ability_info.h" +#include "bundle_constants.h" +#include "bundle_data_storage.h" +#include "bundle_info.h" +#include "inner_bundle_info.h" + +using namespace testing::ext; +using namespace OHOS::AppExecFwk; +using namespace OHOS::AppExecFwk::JsonConstants; + +namespace { +const std::string NORMAL_BUNDLE_NAME{"com.example.test"}; +} // namespace + +class BmsBundleDataStorageTest : public testing::Test { +public: + BmsBundleDataStorageTest(); + ~BmsBundleDataStorageTest(); + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + void ClearJsonFile() const; + +protected: + enum class InfoType { + BUNDLE_INFO, + APPLICATION_INFO, + ABILITY_INFO, + }; + + void CheckBundleSaved(const InnerBundleInfo &innerBundleInfo) const; + void CheckBundleDeleted(const InnerBundleInfo &innerBundleInfo) const; + void CheckInvalidPropDeserialize(const nlohmann::json infoJson, const InfoType infoType) const; + +protected: + nlohmann::json innerBundleInfoJson_ = R"( + { + "appFeature": "ohos_system_app", + "appType": 2, + "baseAbilityInfos": { + "com.ohos.launchercom.ohos.launchercom.ohos.launcher.MainAbility": { + "applicationName": "com.ohos.launcher", + "bundleName": "com.ohos.launcher", + "codePath": "", + "description": "$string:mainability_description", + "deviceCapabilities": [], + "deviceId": "", + "deviceTypes": [ + "phone" + ], + "iconPath": "$media:icon", + "isLauncherAbility": true, + "isNativeAbility": false, + "kind": "page", + "label": "Launcher", + "launchMode": 0, + "libPath": "", + "moduleName": ".MyApplication", + "name": "com.ohos.launcher.MainAbility", + "orientation": 0, + "package": "com.ohos.launcher", + "permissions": [], + "process": "", + "resourcePath": "/data/accounts/account_0/applications/com.ohos.launcher/com.ohos.launcher/assets/launcher/resources.index", + "type": 1, + "uri": "", + "visible": false + } + }, + "baseApplicationInfo": { + "bundleName": "com.ohos.launcher", + "cacheDir": "/data/accounts/account_0/appdata/com.ohos.launcher/cache", + "codePath": "/data/accounts/account_0/applications/com.ohos.launcher", + "dataBaseDir": "/data/accounts/account_0/appdata/com.ohos.launcher/database", + "dataDir": "/data/accounts/account_0/appdata/com.ohos.launcher/files", + "description": "$string:mainability_description", + "descriptionId": 16777217, + "deviceId": "PHONE-001", + "entryDir": "", + "iconId": 16777218, + "iconPath": "$media:icon", + "isLauncherApp": true, + "isSystemApp": false, + "label": "Launcher", + "labelId": 0, + "moduleInfos": [], + "moduleSourceDirs": [], + "name": "com.ohos.launcher", + "permissions": [], + "process": "", + "signatureKey": "", + "supportedModes": 0 + }, + "baseBundleInfo": { + "abilityInfos": [], + "appId": "", + "applicationInfo": { + "bundleName": "", + "cacheDir": "", + "codePath": "", + "dataBaseDir": "", + "dataDir": "", + "description": "", + "descriptionId": 0, + "deviceId": "", + "entryDir": "", + "iconId": 0, + "iconPath": "", + "isLauncherApp": false, + "isSystemApp": false, + "label": "", + "labelId": 0, + "moduleInfos": [], + "moduleSourceDirs": [], + "name": "", + "permissions": [], + "process": "", + "signatureKey": "", + "supportedModes": 0 + }, + "compatibleVersion": 3, + "cpuAbi": "", + "defPermissions": [], + "description": "", + "entryModuleName": "", + "gid": 10000, + "hapModuleNames": [], + "installTime": 17921, + "isKeepAlive": false, + "isNativeApp": false, + "jointUserId": "", + "label": "Launcher", + "mainEntry": "", + "maxSdkVersion": 0, + "minSdkVersion": 0, + "moduleDirs": [], + "moduleNames": [], + "modulePublicDirs": [], + "moduleResPaths": [], + "name": "com.ohos.launcher", + "releaseType": "Release", + "reqPermissions": [], + "seInfo": "", + "targetVersion": 3, + "uid": 10000, + "updateTime": 17921, + "vendor": "ohos", + "versionCode": 1, + "versionName": "1.0" + }, + "baseDataDir": "/data/accounts/account_0/appdata/com.ohos.launcher", + "bundleStatus": 1, + "gid": 10000, + "hasEntry": true, + "innerModuleInfos": { + "com.ohos.launcher": { + "abilityKeys": [ + "com.ohos.launchercom.ohos.launchercom.ohos.launcher.MainAbility" + ], + "defPermissions": [], + "description": "", + "distro": { + "deliveryWithInstall": true, + "moduleName": "launcher", + "moduleType": "entry" + }, + "isEntry": true, + "metaData": { + "customizeData": [], + "parameters": [], + "results": [] + }, + "moduleDataDir": "/data/accounts/account_0/appdata/com.ohos.launcher/com.ohos.launcher", + "moduleName": ".MyApplication", + "modulePackage": "com.ohos.launcher", + "modulePath": "/data/accounts/account_0/applications/com.ohos.launcher/com.ohos.launcher", + "moduleResPath": "/data/accounts/account_0/applications/com.ohos.launcher/com.ohos.launcher/assets/launcher/resources.index", + "reqCapabilities": [], + "reqPermissions": [], + "skillKeys": [ + "com.ohos.launchercom.ohos.launchercom.ohos.launcher.MainAbility" + ] + } + }, + "isKeepData": false, + "isSupportBackup": false, + "mainAbility": "com.ohos.launchercom.ohos.launchercom.ohos.launcher.MainAbility", + "provisionId": "BNtg4JBClbl92Rgc3jm/RfcAdrHXaM8F0QOiwVEhnV5ebE5jNIYnAx+weFRT3QTyUjRNdhmc2aAzWyi+5t5CoBM=", + "skillInfos": { + "com.ohos.launchercom.ohos.launchercom.ohos.launcher.MainAbility": [ + { + "actions": [ + "action.system.home", + "com.ohos.action.main" + ], + "entities": [ + "entity.system.home", + "flag.home.intent.from.system" + ], + "uris": [] + } + ] + }, + "uid": 10000, + "userId_": 0 + } + )"_json; + + nlohmann::json moduleInfoJson_ = R"( + { + "moduleName": "entry", + "moduleSourceDir": "" + } + )"_json; + const std::string deviceId_ = Constants::CURRENT_DEVICE_ID; + const std::string BASE_ABILITY_INFO = "baseAbilityInfos"; + // need modify with innerBundleInfoJson_ + const std::string abilityName = "com.ohos.launchercom.ohos.launchercom.ohos.launcher.MainAbility"; + const std::string BASE_BUNDLE_INFO = "baseBundleInfo"; + const std::string BASE_APPLICATION_INFO = "baseApplicationInfo"; +}; + +BmsBundleDataStorageTest::BmsBundleDataStorageTest() +{} + +BmsBundleDataStorageTest::~BmsBundleDataStorageTest() +{} + +void BmsBundleDataStorageTest::CheckBundleSaved(const InnerBundleInfo &innerBundleInfo) const +{ + BundleDataStorage bundleDataStorage; + ASSERT_TRUE(bundleDataStorage.SaveStorageBundleInfo(Constants::CURRENT_DEVICE_ID, innerBundleInfo)); + std::map> bundleData; + ASSERT_TRUE(bundleDataStorage.LoadAllData(bundleData)); + + // search allDeviceInfos by bundle name + std::string bundleName = innerBundleInfo.GetBundleName(); + auto bundleDataIter = bundleData.find(bundleName); + ASSERT_TRUE(bundleDataIter != bundleData.end()); + + // search InnerBundleInfo by device id + auto allDeviceInfos = bundleDataIter->second; + auto devicesInfosIter = allDeviceInfos.find(deviceId_); + ASSERT_TRUE(devicesInfosIter != allDeviceInfos.end()); + + InnerBundleInfo afterLoadInfo = devicesInfosIter->second; + ASSERT_TRUE(innerBundleInfo.ToString() == afterLoadInfo.ToString()); +} + +void BmsBundleDataStorageTest::CheckBundleDeleted(const InnerBundleInfo &innerBundleInfo) const +{ + BundleDataStorage bundleDataStorage; + ASSERT_TRUE(bundleDataStorage.DeleteStorageBundleInfo(Constants::CURRENT_DEVICE_ID, innerBundleInfo)); + std::map> bundleDates; + ASSERT_FALSE(bundleDataStorage.LoadAllData(bundleDates)); +} + +void BmsBundleDataStorageTest::CheckInvalidPropDeserialize(const nlohmann::json infoJson, const InfoType infoType) const +{ + APP_LOGI("deserialize infoJson = %{public}s", infoJson.dump().c_str()); + bool throwError = false; + nlohmann::json innerBundleInfoJson; + nlohmann::json bundleInfoJson = innerBundleInfoJson_.at(BASE_BUNDLE_INFO); + try { + switch (infoType) { + case InfoType::BUNDLE_INFO: { + bundleInfoJson = infoJson; + BundleInfo bundleInfo = infoJson; + break; + } + case InfoType::APPLICATION_INFO: { + bundleInfoJson["appInfo"] = infoJson; + ApplicationInfo applicationInfo = infoJson; + break; + } + case InfoType::ABILITY_INFO: { + bundleInfoJson["abilityInfos"].push_back(infoJson); + AbilityInfo abilityInfo = infoJson; + break; + } + default: + break; + } + } catch (nlohmann::detail::type_error exception) { + APP_LOGI("has a type_error: %{public}s", exception.what()); + throwError = true; + } + + ASSERT_TRUE(throwError); + if (!throwError) { + GTEST_LOG_(ERROR) << "not catch any type_error"; + } + + innerBundleInfoJson["baseBundleInfo"] = bundleInfoJson; + InnerBundleInfo fromJsonInfo; + ASSERT_FALSE(fromJsonInfo.FromJson(innerBundleInfoJson)); +} + +void BmsBundleDataStorageTest::SetUpTestCase() +{} + +void BmsBundleDataStorageTest::TearDownTestCase() +{} + +void BmsBundleDataStorageTest::SetUp() +{ + // clean bmsdb.json + ClearJsonFile(); +} + +void BmsBundleDataStorageTest::TearDown() +{} + +void BmsBundleDataStorageTest::ClearJsonFile() const +{ + std::string fileName = Constants::BUNDLE_DATA_BASE_FILE; + std::ofstream o(fileName); + if (!o.is_open()) { + return; + } + o.close(); +} + +/** + * @tc.number: BundleInfoJsonSerializer_0100 + * @tc.name: save bundle installation information to persist storage + * @tc.desc: 1.system running normally + * 2.successfully serialize and deserialize all right props in BundleInfo + */ +HWTEST_F(BmsBundleDataStorageTest, BundleInfoJsonSerializer_0100, Function | SmallTest | Level1) +{ + nlohmann::json sourceInfoJson = innerBundleInfoJson_.at(BASE_BUNDLE_INFO); + // deserialize BundleInfo from json + BundleInfo fromJsonInfo = sourceInfoJson; + // serialize fromJsonInfo to json + nlohmann::json toJsonObject = fromJsonInfo; + + ASSERT_TRUE(toJsonObject.dump() == sourceInfoJson.dump()); +} + +/** + * @tc.number: BundleInfoJsonSerializer_0200 + * @tc.name: save bundle installation information to persist storage + * @tc.desc: 1.system running normally + * 2.test can catch deserialize error for type error for name prop in BundleInfo + */ +HWTEST_F(BmsBundleDataStorageTest, BundleInfoJsonSerializer_0200, Function | SmallTest | Level1) +{ + nlohmann::json typeErrorProps; + typeErrorProps["name"] = NOT_STRING_TYPE; + typeErrorProps["label"] = NOT_STRING_TYPE; + typeErrorProps["description"] = NOT_STRING_TYPE; + typeErrorProps["vendor"] = NOT_STRING_TYPE; + typeErrorProps["mainEntry"] = NOT_STRING_TYPE; + typeErrorProps["versionName"] = NOT_STRING_TYPE; + typeErrorProps["versionCode"] = NOT_NUMBER_TYPE; + typeErrorProps["minSdkVersion"] = NOT_NUMBER_TYPE; + typeErrorProps["minSdkVersion"] = NOT_NUMBER_TYPE; + + for (nlohmann::json::iterator iter = typeErrorProps.begin(); iter != typeErrorProps.end(); iter++) { + for (auto valueIter = iter.value().begin(); valueIter != iter.value().end(); valueIter++) { + nlohmann::json infoJson = innerBundleInfoJson_.at(BASE_BUNDLE_INFO); + infoJson[iter.key()] = valueIter.value(); + } + } +} + +/** + * @tc.number: AbilityInfoJsonSerializer_0100 + * @tc.name: save bundle installation information to persist storage + * @tc.desc: 1.system running normally + * 2.successfully serialize and deserialize all right props in AbilityInfo + */ +HWTEST_F(BmsBundleDataStorageTest, AbilityInfoJsonSerializer_0100, Function | SmallTest | Level1) +{ + nlohmann::json sourceInfoJson = innerBundleInfoJson_.at(BASE_ABILITY_INFO).at(abilityName); + // deserialize AbilityInfo from json + AbilityInfo fromJsonInfo = sourceInfoJson; + // serialize fromJsonInfo to json + nlohmann::json toJsonObject = fromJsonInfo; + ASSERT_TRUE(toJsonObject.dump() == sourceInfoJson.dump()); +} + +/** + * @tc.number: AbilityInfoJsonSerializer_0200 + * @tc.name: save bundle installation information to persist storage + * @tc.desc: 1.system running normally + * 2.test can catch deserialize error for type error for name prop in AbilityInfo + */ +HWTEST_F(BmsBundleDataStorageTest, AbilityInfoJsonSerializer_0200, Function | SmallTest | Level1) +{ + nlohmann::json typeErrorProps; + typeErrorProps["package"] = NOT_STRING_TYPE; + typeErrorProps["name"] = NOT_STRING_TYPE; + typeErrorProps["bundleName"] = NOT_STRING_TYPE; + typeErrorProps["applicationName"] = NOT_STRING_TYPE; + typeErrorProps["label"] = NOT_STRING_TYPE; + typeErrorProps["description"] = NOT_STRING_TYPE; + typeErrorProps["iconPath"] = NOT_STRING_TYPE; + typeErrorProps["visible"] = NOT_BOOL_TYPE; + typeErrorProps["kind"] = NOT_STRING_TYPE; + typeErrorProps["type"] = NOT_NUMBER_TYPE; + typeErrorProps["orientation"] = NOT_NUMBER_TYPE; + typeErrorProps["launchMode"] = NOT_NUMBER_TYPE; + typeErrorProps["codePath"] = NOT_STRING_TYPE; + typeErrorProps["resourcePath"] = NOT_STRING_TYPE; + typeErrorProps["libPath"] = NOT_STRING_TYPE; + + for (nlohmann::json::iterator iter = typeErrorProps.begin(); iter != typeErrorProps.end(); iter++) { + for (auto valueIter = iter.value().begin(); valueIter != iter.value().end(); valueIter++) { + APP_LOGD("deserialize check prop key = %{public}s, type = %{public}s", + iter.key().c_str(), + valueIter.key().c_str()); + nlohmann::json infoJson = innerBundleInfoJson_.at(BASE_ABILITY_INFO).at(abilityName); + infoJson[iter.key()] = valueIter.value(); + } + } +} + +/** + * @tc.number: ApplicationInfoJsonSerializer_0100 + * @tc.name: save bundle installation information to persist storage + * @tc.desc: 1.system running normally + * 2.successfully serialize and deserialize all right props in ApplicationInfo + */ +HWTEST_F(BmsBundleDataStorageTest, ApplicationInfoJsonSerializer_0100, Function | SmallTest | Level1) +{ + nlohmann::json sourceInfoJson = innerBundleInfoJson_.at(BASE_APPLICATION_INFO); + // deserialize ApplicationInfo from json + ApplicationInfo fromJsonInfo = sourceInfoJson; + // serialize fromJsonInfo to json + nlohmann::json toJsonObject = fromJsonInfo; + + ASSERT_TRUE(toJsonObject.dump() == sourceInfoJson.dump()); +} + +/** + * @tc.number: ApplicationInfoJsonSerializer_0200 + * @tc.name: save bundle installation information to persist storage + * @tc.desc: 1.system running normally + * 2.test can catch deserialize error for type error for name prop in ApplicationInfo + */ +HWTEST_F(BmsBundleDataStorageTest, ApplicationInfoJsonSerializer_0200, Function | SmallTest | Level1) +{ + nlohmann::json typeErrorProps; + typeErrorProps["name"] = NOT_STRING_TYPE; + typeErrorProps["bundleName"] = NOT_STRING_TYPE; + typeErrorProps["sandboxId"] = NOT_NUMBER_TYPE; + typeErrorProps["signatureKey"] = NOT_STRING_TYPE; + + for (nlohmann::json::iterator iter = typeErrorProps.begin(); iter != typeErrorProps.end(); iter++) { + for (auto valueIter = iter.value().begin(); valueIter != iter.value().end(); valueIter++) { + APP_LOGD("deserialize check prop key = %{public}s, type = %{public}s", + iter.key().c_str(), + valueIter.key().c_str()); + nlohmann::json infoJson = innerBundleInfoJson_.at(BASE_APPLICATION_INFO); + infoJson[iter.key()] = valueIter.value(); + } + } +} + +/** + * @tc.number: ModuleInfoJsonSerializer_0100 + * @tc.name: save bundle installation information to persist storage + * @tc.desc: 1.system running normally + * 2.successfully serialize and deserialize all right props in ModuleInfo + */ +HWTEST_F(BmsBundleDataStorageTest, ModuleInfoJsonSerializer_0100, Function | SmallTest | Level1) +{ + nlohmann::json sourceInfoJson = moduleInfoJson_; + // deserialize ModuleInfo from json + ModuleInfo fromJsonInfo = sourceInfoJson; + // serialize fromJsonInfo to json + nlohmann::json toJsonObject = fromJsonInfo; + + ASSERT_TRUE(toJsonObject.dump() == sourceInfoJson.dump()); +} + +/** + * @tc.number: SaveData_0100 + * @tc.name: save bundle installation information to persist storage + * @tc.desc: 1.system running normally and no saved any bundle data + * 2.successfully save a new bundle installation information for the first time + */ +HWTEST_F(BmsBundleDataStorageTest, SaveData_0100, Function | SmallTest | Level0) +{ + InnerBundleInfo innerBundleInfo; + innerBundleInfo.FromJson(innerBundleInfoJson_); + CheckBundleSaved(innerBundleInfo); +} + +/** + * @tc.number: SaveData_0200 + * @tc.name: save bundle installation information to persist storage + * @tc.desc: 1.system running normally + * 2.successfully save a new bundle installation information for not the first time + */ +HWTEST_F(BmsBundleDataStorageTest, SaveData_0200, Function | SmallTest | Level0) +{ + InnerBundleInfo innerBundleInfo; + innerBundleInfo.FromJson(innerBundleInfoJson_); + + ApplicationInfo baseApp = innerBundleInfo.GetBaseApplicationInfo(); + baseApp.name = "com.example.other"; + baseApp.bundleName = baseApp.name; + innerBundleInfo.SetBaseApplicationInfo(baseApp); + + InnerBundleInfo otherInnerBundleInfo = innerBundleInfo; + CheckBundleSaved(otherInnerBundleInfo); +} + +/** + * @tc.number: SaveData_0300 + * @tc.name: save bundle installation information to persist storage + * @tc.desc: 1.system running normally + * 2.successfully update an already exist bundle installation information + */ +HWTEST_F(BmsBundleDataStorageTest, SaveData_0300, Function | SmallTest | Level0) +{ + InnerBundleInfo innerBundleInfo; + innerBundleInfo.FromJson(innerBundleInfoJson_); + CheckBundleSaved(innerBundleInfo); + CheckBundleDeleted(innerBundleInfo); + + BundleInfo bundleInfo = innerBundleInfoJson_.at(BASE_BUNDLE_INFO); + bundleInfo.description = "update test application"; + InnerBundleInfo otherInnerBundleInfo = innerBundleInfo; + otherInnerBundleInfo.SetBaseBundleInfo(bundleInfo); + + CheckBundleSaved(otherInnerBundleInfo); +} + +/** + * @tc.number: SaveData_0400 + * @tc.name: save bundle installation information to persist storage + * @tc.desc: 1.system running normally + * 2.check all props can be serialize and deserialize + */ +HWTEST_F(BmsBundleDataStorageTest, SaveData_0400, Function | SmallTest | Level1) +{ + nlohmann::json sourceInfoJson = innerBundleInfoJson_; + InnerBundleInfo fromJsonInfo; + ASSERT_TRUE(fromJsonInfo.FromJson(innerBundleInfoJson_)); + ASSERT_TRUE(fromJsonInfo.ToString() == sourceInfoJson.dump()); +} + +/** + * @tc.number: LoadAllData_0100 + * @tc.name: load all installed bundle information from persist storage + * @tc.desc: 1.system running normally + * 2.test can successfully load all installed bundle information from persist storage + */ +HWTEST_F(BmsBundleDataStorageTest, LoadAllData_0100, Function | SmallTest | Level0) +{ + BundleDataStorage bundleDataStorage; + int count = 10; + InnerBundleInfo innerBundleInfo; + innerBundleInfo.FromJson(innerBundleInfoJson_); + + ApplicationInfo baseApp = innerBundleInfo.GetBaseApplicationInfo(); + + for (int i = 0; i < count; i++) { + 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)); + } + + std::map> bundleDates; + ASSERT_TRUE(bundleDataStorage.LoadAllData(bundleDates)); + + for (int i = 0; i < count; i++) { + std::string bundleName = NORMAL_BUNDLE_NAME + std::to_string(i); + baseApp.name = NORMAL_BUNDLE_NAME + std::to_string(i); + baseApp.bundleName = baseApp.name; + innerBundleInfo.SetBaseApplicationInfo(baseApp); + + // search allDeviceInfos by bundle name + auto bundleDatesIter = bundleDates.find(bundleName); + ASSERT_TRUE(bundleDatesIter != bundleDates.end()); + // search InnerBundleInfo by device id + auto allDeviceInfos = bundleDatesIter->second; + auto devicesInfosIter = allDeviceInfos.find(deviceId_); + ASSERT_TRUE(devicesInfosIter != allDeviceInfos.end()); + + InnerBundleInfo afterLoadInfo = devicesInfosIter->second; + ASSERT_TRUE(innerBundleInfo.ToString() == afterLoadInfo.ToString()); + } +} + +/** + * @tc.number: DeleteBundleData_0100 + * @tc.name: delete bundle installation information from persist storage + * @tc.desc: 1.system running normally + * 2.successfully delete a saved bundle installation information + */ +HWTEST_F(BmsBundleDataStorageTest, DeleteBundleData_0100, Function | SmallTest | Level0) +{ + InnerBundleInfo innerBundleInfo; + innerBundleInfo.FromJson(innerBundleInfoJson_); + + BundleDataStorage bundleDataStorage; + ASSERT_TRUE(bundleDataStorage.SaveStorageBundleInfo(Constants::CURRENT_DEVICE_ID, innerBundleInfo)); + + CheckBundleDeleted(innerBundleInfo); +} + +/** + * @tc.number: DeleteBundleData_0200 + * @tc.name: delete bundle installation information from persist storage + * @tc.desc: 1.system running normally and no saved the bundle to be deleted + * 2.successfully delete an unsaved bundle installation information + */ +HWTEST_F(BmsBundleDataStorageTest, DeleteBundleData_0200, Function | SmallTest | Level1) +{ + InnerBundleInfo innerBundleInfo; + innerBundleInfo.FromJson(innerBundleInfoJson_); + BundleDataStorage bundleDataStorage; + ASSERT_FALSE(bundleDataStorage.DeleteStorageBundleInfo(Constants::CURRENT_DEVICE_ID, innerBundleInfo)); +} + +/** + * @tc.number: DeleteBundleData_0300 + * @tc.name: delete bundle installation information from persist storage + * @tc.desc: 1.system running normally and no saved the bundle to be deleted + * 2.Unsaved bundle installation information was not removed successfully + */ +HWTEST_F(BmsBundleDataStorageTest, DeleteBundleData_0300, Function | SmallTest | Level1) +{ + ASSERT_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)); + + std::map> bundleDates; + ASSERT_FALSE(bundleDataStorage.SaveStorageBundleInfo(Constants::CURRENT_DEVICE_ID, innerBundleInfo)); + ASSERT_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 new file mode 100644 index 000000000..eb541dc78 --- /dev/null +++ b/services/bundlemgr/test/unittest/bms_bundle_installer_test/BUILD.gn @@ -0,0 +1,79 @@ +# 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") +import( + "//foundation/appexecfwk/standard/services/bundlemgr/appexecfwk_bundlemgr.gni") + +module_output_path = "appexecfwk_standard/bundlemgrservice" + +ohos_unittest("BmsBundleInstallerTest") { + module_out_path = module_output_path + + sources = [ + "${services_path}/bundlemgr/src/bundle_data_mgr.cpp", + "${services_path}/bundlemgr/src/bundle_data_storage.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/installd/installd_host_impl.cpp", + "${services_path}/bundlemgr/src/installd/installd_operator.cpp", + "${services_path}/bundlemgr/src/installd/installd_service.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 + + sources += [ "bms_bundle_installer_test.cpp" ] + + configs = [ + "${libs_path}/libeventhandler:libeventhandler_config", + "${services_path}/bundlemgr/test:bundlemgr_test_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${libs_path}/libeventhandler:libeventhandler_target", + "//base/notification/ces_standard/cesfwk/kits/native:cesfwk_kits", + "//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/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + ] + + deps += bundle_install_deps + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":BmsBundleInstallerTest" ] +} 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 new file mode 100755 index 000000000..2b1a2a8ac --- /dev/null +++ b/services/bundlemgr/test/unittest/bms_bundle_installer_test/bms_bundle_installer_test.cpp @@ -0,0 +1,733 @@ +/* + * 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 "directory_ex.h" +#include "installd/installd_service.h" +#include "installd_client.h" +#include "system_bundle_installer.h" +#include "mock_status_receiver.h" +#include "install_param.h" +#include "bundle_info.h" +#include "bundle_installer_host.h" +#include "bundle_data_storage.h" +#include "bundle_mgr_service.h" + +using namespace testing::ext; +using namespace std::chrono_literals; +using namespace OHOS::AppExecFwk; +using namespace OHOS; +using OHOS::DelayedSingleton; + +namespace { + +const std::string BUNDLE_NAME = "com.example.l3jsdemo"; +const std::string RESOURCE_ROOT_PATH = "/data/test/resource/bms/install_bundle/"; +const std::string INVALID_PATH = "/install_bundle/"; +const std::string RIGHT_BUNDLE = "right.hap"; +const std::string INVALID_BUNDLE = "nonfile.hap"; +const std::string FORMAT_ERROR_BUNDLE = "format_error_profile.hap"; +const std::string WRONG_BUNDLE_NAME = "wrong_bundle_name.ha"; +const std::string ERROR_BUNDLE_PROFILE_FILE = "error_bundle_profile.hap"; +const std::string BUNDLE_DATA_DIR = "/data/accounts/account_0/appdata/com.example.l3jsdemo"; +const std::string BUNDLE_CODE_DIR = "/data/accounts/account_0/applications/com.example.l3jsdemo"; +const std::string ROOT_DIR = "/data/accounts"; +const char *BMSDB_JSON = "/data/bundlemgr/bmsdb.json"; +const int32_t ROOT_UID = 0; +const int32_t USERID = 0; +const std::string INSTALL_THREAD = "TestInstall"; + +} // namespace + +class BmsBundleInstallerTest : public testing::Test { +public: + BmsBundleInstallerTest(); + ~BmsBundleInstallerTest(); + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + bool InstallSystemBundle(const std::string &filePath) const; + ErrCode InstallThirdPartyBundle(const std::string &filePath) const; + ErrCode UpdateThirdPartyBundle(const std::string &filePath) const; + void CheckFileExist() const; + void CheckFileNonExist() const; + void CheckDbExist() const; + void CheckDbNonExist() const; + const std::shared_ptr GetBundleDataMgr() const; + const std::shared_ptr GetBundleInstallerManager() const; + void StopInstalldService() const; + void StopBundleService(); + void CreateInstallerManager(); + void ClearJsonFile() const; + +private: + std::shared_ptr manager_ = nullptr; + std::shared_ptr installdService_ = std::make_shared(); + std::shared_ptr bundleMgrService_ = DelayedSingleton::GetInstance(); +}; + +BmsBundleInstallerTest::BmsBundleInstallerTest() +{} + +BmsBundleInstallerTest::~BmsBundleInstallerTest() +{} + +bool BmsBundleInstallerTest::InstallSystemBundle(const std::string &filePath) const +{ + auto installer = std::make_unique(filePath); + return installer->InstallSystemBundle(Constants::AppType::SYSTEM_APP); +} + +ErrCode BmsBundleInstallerTest::InstallThirdPartyBundle(const std::string &filePath) const +{ + auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); + if (!installer) { + EXPECT_FALSE(true) << "the installer is nullptr"; + return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR; + } + sptr receiver = new (std::nothrow) MockStatusReceiver(); + if (!receiver) { + EXPECT_FALSE(true) << "the receiver is nullptr"; + return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR; + } + InstallParam installParam; + installParam.installFlag = InstallFlag::NORMAL; + bool result = installer->Install(filePath, installParam, receiver); + EXPECT_TRUE(result); + return receiver->GetResultCode(); +} + +ErrCode BmsBundleInstallerTest::UpdateThirdPartyBundle(const std::string &filePath) const +{ + auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); + if (!installer) { + EXPECT_FALSE(true) << "the installer is nullptr"; + return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR; + } + sptr receiver = new (std::nothrow) MockStatusReceiver(); + if (!receiver) { + EXPECT_FALSE(true) << "the receiver is nullptr"; + return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR; + } + InstallParam installParam; + installParam.installFlag = InstallFlag::REPLACE_EXISTING; + bool result = installer->Install(filePath, installParam, receiver); + EXPECT_TRUE(result); + return receiver->GetResultCode(); +} + +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"; + } + if (chown(ROOT_DIR.c_str(), ROOT_UID, ROOT_UID) != 0) { + ASSERT_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"; + } +} + +void BmsBundleInstallerTest::TearDownTestCase() +{} + +void BmsBundleInstallerTest::SetUp() +{ + installdService_->Start(); + if (!bundleMgrService_->IsServiceReady()) { + bundleMgrService_->OnStart(); + } +} + +void BmsBundleInstallerTest::TearDown() +{ + StopInstalldService(); + StopBundleService(); + + // clear files. + ClearJsonFile(); + OHOS::ForceRemoveDirectory(BUNDLE_DATA_DIR); + OHOS::ForceRemoveDirectory(BUNDLE_CODE_DIR); +} + +void BmsBundleInstallerTest::ClearJsonFile() const +{ + std::string fileName = Constants::BUNDLE_DATA_BASE_FILE; + OHOS::RemoveFile(fileName); + std::ofstream o(fileName); + if (!o.is_open()) { + return; + } + o.close(); +} + +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; + + int bundleDataExist = access(BUNDLE_DATA_DIR.c_str(), F_OK); + ASSERT_EQ(bundleDataExist, 0) << "the bundle data dir does not exists: " << BUNDLE_DATA_DIR; +} + +void BmsBundleInstallerTest::CheckDbExist() const +{ + struct stat buf; + stat(BMSDB_JSON, &buf); + int size = buf.st_size; + ASSERT_GT(size, 0) << "the bmsdb file does not exists: " << BMSDB_JSON; +} + +void BmsBundleInstallerTest::CheckDbNonExist() const +{ + struct stat buf; + stat(BMSDB_JSON, &buf); + int size = buf.st_size; + ASSERT_EQ(size, 0) << "the bmsdb file exists: " << BMSDB_JSON; +} + +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; + + int bundleDataExist = access(BUNDLE_DATA_DIR.c_str(), F_OK); + ASSERT_NE(bundleDataExist, 0) << "the bundle data dir exists: " << BUNDLE_DATA_DIR; +} + +const std::shared_ptr BmsBundleInstallerTest::GetBundleDataMgr() const +{ + return bundleMgrService_->GetDataMgr(); +} + +const std::shared_ptr BmsBundleInstallerTest::GetBundleInstallerManager() const +{ + return manager_; +} + +void BmsBundleInstallerTest::StopInstalldService() const +{ + installdService_->Stop(); + InstalldClient::GetInstance()->ResetInstalldProxy(); +} + +void BmsBundleInstallerTest::StopBundleService() +{ + if (bundleMgrService_ == nullptr) { + return; + } + auto dataMgr = bundleMgrService_->GetDataMgr(); + ASSERT_NE(dataMgr, nullptr); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_START); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_SUCCESS); + bundleMgrService_->OnStop(); + bundleMgrService_.reset(); +} + +void BmsBundleInstallerTest::CreateInstallerManager() +{ + if (manager_ != nullptr) { + return; + } + auto installRunner = EventRunner::Create(INSTALL_THREAD); + if (!installRunner) { + return; + } + manager_ = std::make_shared(installRunner); + ASSERT_NE(nullptr, manager_); +} + +/** + * @tc.number: SystemInstall_0100 + * @tc.name: test the right system bundle file can be installed + * @tc.desc: 1.the system bundle file exists + * 2.the system bundle can be installed successfully and can get the bundle info + */ +HWTEST_F(BmsBundleInstallerTest, SystemInstall_0100, Function | SmallTest | Level0) +{ + std::string bundleFile = RESOURCE_ROOT_PATH + RIGHT_BUNDLE; + bool result = InstallSystemBundle(bundleFile); + ASSERT_TRUE(result) << "the bundle file install failed: " << bundleFile; + CheckFileExist(); + CheckDbExist(); +} + +/** + * @tc.number: SystemInstall_0200 + * @tc.name: test the wrong system bundle file can't be installed + * @tc.desc: 1.the system bundle file don't exists + * 2.the system bundle can't be installed and the result is fail + */ +HWTEST_F(BmsBundleInstallerTest, SystemInstall_0200, Function | SmallTest | Level0) +{ + std::string nonExistFile = RESOURCE_ROOT_PATH + INVALID_BUNDLE; + bool result = InstallSystemBundle(nonExistFile); + ASSERT_FALSE(result) << "the bundle file install success: " << nonExistFile; + CheckFileNonExist(); + CheckDbNonExist(); +} + +/** + * @tc.number: SystemInstall_0300 + * @tc.name: test the empty path can't be installed + * @tc.desc: 1.the system bundle file path is empty + * 2.the system bundle can't be installed and the result is fail + */ +HWTEST_F(BmsBundleInstallerTest, SystemInstall_0300, Function | SmallTest | Level0) +{ + bool result = InstallSystemBundle(""); + ASSERT_FALSE(result) << "the empty path install success"; + CheckFileNonExist(); + CheckDbNonExist(); +} + +/** + * @tc.number: SystemInstall_0400 + * @tc.name: test the illegal bundleName file can't be installed + * @tc.desc: 1.the system bundle name is illegal + * 2.the system bundle can't be installed and the result is fail + */ +HWTEST_F(BmsBundleInstallerTest, SystemInstall_0400, Function | SmallTest | Level0) +{ + std::string wrongBundleName = RESOURCE_ROOT_PATH + WRONG_BUNDLE_NAME; + bool result = InstallSystemBundle(wrongBundleName); + ASSERT_FALSE(result) << "the wrong bundle file install success"; + CheckFileNonExist(); + CheckDbNonExist(); +} + +/** + * @tc.number: SystemInstall_0500 + * @tc.name: test the error format bundle file can't be installed + * @tc.desc: 1.the system bundle format is error + * 2.the system bundle can't be installed and the result is fail + */ +HWTEST_F(BmsBundleInstallerTest, SystemInstall_0500, Function | SmallTest | Level0) +{ + std::string errorFormat = RESOURCE_ROOT_PATH + FORMAT_ERROR_BUNDLE; + bool result = InstallSystemBundle(errorFormat); + ASSERT_FALSE(result) << "the wrong format file install success"; + CheckFileNonExist(); + CheckDbNonExist(); +} + +/** + * @tc.number: SystemInstall_0600 + * @tc.name: test the bundle file with invalid path will cause the result of install failure + * @tc.desc: 1.the bundle file has invalid path + * 2.the system bundle can't be installed and the result is fail + */ +HWTEST_F(BmsBundleInstallerTest, SystemInstall_0600, Function | SmallTest | Level0) +{ + std::string bundleFile = INVALID_PATH + RIGHT_BUNDLE; + bool result = InstallSystemBundle(bundleFile); + ASSERT_FALSE(result) << "the invalid path install success"; + CheckFileNonExist(); + CheckDbNonExist(); +} + +/** + * @tc.number: SystemInstall_0700 + * @tc.name: test the install will fail when installd service has error + * @tc.desc: 1.the installd service has error + * 2.the install result is fail + */ +HWTEST_F(BmsBundleInstallerTest, SystemInstall_0700, Function | SmallTest | Level0) +{ + StopInstalldService(); + std::string bundleFile = RESOURCE_ROOT_PATH + RIGHT_BUNDLE; + bool result = InstallSystemBundle(bundleFile); + EXPECT_FALSE(result); +} + +/** + * @tc.number: SystemUpdateData_0100 + * @tc.name: test the right bundle file can be installed and update its info to bms + * @tc.desc: 1.the system bundle is available + * 2.the right bundle can be installed and update its info to bms + */ +HWTEST_F(BmsBundleInstallerTest, SystemUpdateData_0100, Function | SmallTest | Level0) +{ + ApplicationInfo info; + auto dataMgr = GetBundleDataMgr(); + ASSERT_NE(dataMgr, nullptr); + bool result = dataMgr->GetApplicationInfo(BUNDLE_NAME, ApplicationFlag::GET_BASIC_APPLICATION_INFO, USERID, info); + ASSERT_FALSE(result); + std::string bundleFile = RESOURCE_ROOT_PATH + RIGHT_BUNDLE; + bool installResult = InstallSystemBundle(bundleFile); + ASSERT_TRUE(installResult); + result = dataMgr->GetApplicationInfo(BUNDLE_NAME, ApplicationFlag::GET_BASIC_APPLICATION_INFO, USERID, info); + ASSERT_TRUE(result); + EXPECT_EQ(info.name, BUNDLE_NAME); +} + +/** + * @tc.number: SystemUpdateData_0200 + * @tc.name: test the wrong bundle file can't be installed and its info will not updated to bms + * @tc.desc: 1.the system bundle is wrong + * 2.the wrong bundle can't be installed and its info will not updated to bms + */ +HWTEST_F(BmsBundleInstallerTest, SystemUpdateData_0200, Function | SmallTest | Level0) +{ + ApplicationInfo info; + auto dataMgr = GetBundleDataMgr(); + ASSERT_NE(dataMgr, nullptr); + bool result = dataMgr->GetApplicationInfo(BUNDLE_NAME, ApplicationFlag::GET_BASIC_APPLICATION_INFO, USERID, info); + ASSERT_FALSE(result); + std::string wrongBundleName = RESOURCE_ROOT_PATH + WRONG_BUNDLE_NAME; + bool installResult = InstallSystemBundle(wrongBundleName); + ASSERT_FALSE(installResult); + result = dataMgr->GetApplicationInfo(BUNDLE_NAME, ApplicationFlag::GET_BASIC_APPLICATION_INFO, USERID, info); + EXPECT_FALSE(result); +} + +/** + * @tc.number: SystemUpdateData_0300 + * @tc.name: test the already installed bundle can't be reinstalled and update its info to bms + * @tc.desc: 1.the bundle is already installed + * 2.the already installed bundle can't be reinstalled and update its info to bms + */ +HWTEST_F(BmsBundleInstallerTest, SystemUpdateData_0300, Function | SmallTest | Level0) +{ + auto dataMgr = GetBundleDataMgr(); + ASSERT_NE(dataMgr, nullptr); + // prepare already install information. + std::string bundleFile = RESOURCE_ROOT_PATH + RIGHT_BUNDLE; + bool firstInstall = InstallSystemBundle(bundleFile); + ASSERT_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); + bool secondInstall = InstallSystemBundle(bundleFile); + EXPECT_FALSE(secondInstall); +} + +/** + * @tc.number: SystemUpdateData_0400 + * @tc.name: test the already installing bundle can't be reinstalled and update its info to bms + * @tc.desc: 1.the bundle is already installing. + * 2.the already installing bundle can't be reinstalled and update its info to bms + */ +HWTEST_F(BmsBundleInstallerTest, SystemUpdateData_0400, Function | SmallTest | Level0) +{ + // prepare already install information. + auto dataMgr = GetBundleDataMgr(); + ASSERT_NE(dataMgr, nullptr); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); + // begin to reinstall package + std::string bundleFile = RESOURCE_ROOT_PATH + RIGHT_BUNDLE; + bool installResult = InstallSystemBundle(bundleFile); + EXPECT_FALSE(installResult); + // reset the install state + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_FAIL); +} + +/** + * @tc.number: CreateInstallTask_0100 + * @tc.name: test the installer manager can create task + * @tc.desc: 1.the bundle file exists + * 2.the bundle can be installed successfully + */ +HWTEST_F(BmsBundleInstallerTest, CreateInstallTask_0100, Function | SmallTest | Level0) +{ + CreateInstallerManager(); + sptr receiver = new (std::nothrow) MockStatusReceiver(); + ASSERT_NE(receiver, nullptr); + InstallParam installParam; + std::string bundleFile = RESOURCE_ROOT_PATH + RIGHT_BUNDLE; + GetBundleInstallerManager()->CreateInstallTask(bundleFile, installParam, receiver); + ErrCode result = receiver->GetResultCode(); + EXPECT_EQ(ERR_OK, result); +} + +/** + * @tc.number: CreateInstallTask_0200 + * @tc.name: test the installer manager can not create task while bundle invalid + * @tc.desc: 1.the invalid bundle file exists + * 2.install the invalid bundle failed + */ +HWTEST_F(BmsBundleInstallerTest, CreateInstallTask_0200, Function | SmallTest | Level0) +{ + CreateInstallerManager(); + sptr receiver = new (std::nothrow) MockStatusReceiver(); + ASSERT_NE(receiver, nullptr); + InstallParam installParam; + std::string bundleFile = RESOURCE_ROOT_PATH + INVALID_BUNDLE; + GetBundleInstallerManager()->CreateInstallTask(bundleFile, installParam, receiver); + ErrCode result = receiver->GetResultCode(); + EXPECT_NE(ERR_OK, result); +} + +/** + * @tc.number: CreateUninstallTask_0100 + * @tc.name: test the installer manager can create task + * @tc.desc: 1.the bundle file exists + * 2.the bundle can be install and uninstalled successfully + */ +HWTEST_F(BmsBundleInstallerTest, CreateUninstallTask_0100, Function | SmallTest | Level0) +{ + CreateInstallerManager(); + sptr receiver = new (std::nothrow) MockStatusReceiver(); + ASSERT_NE(receiver, nullptr); + InstallParam installParam; + std::string bundleFile = RESOURCE_ROOT_PATH + RIGHT_BUNDLE; + GetBundleInstallerManager()->CreateInstallTask(bundleFile, installParam, receiver); + ErrCode result = receiver->GetResultCode(); + EXPECT_EQ(ERR_OK, result); + + sptr unReceiver = new (std::nothrow) MockStatusReceiver(); + GetBundleInstallerManager()->CreateUninstallTask(BUNDLE_NAME, installParam, unReceiver); + result = unReceiver->GetResultCode(); + EXPECT_EQ(ERR_OK, result); +} + +/** + * @tc.number: CreateUninstallTask_0200 + * @tc.name: test the installer manager can not create task while bundle invalid + * @tc.desc: 1.the invalid bundle file exists + * 2.uninstall the bundle failed + */ +HWTEST_F(BmsBundleInstallerTest, CreateUninstallTask_0200, Function | SmallTest | Level0) +{ + CreateInstallerManager(); + sptr receiver = new (std::nothrow) MockStatusReceiver(); + ASSERT_NE(receiver, nullptr); + InstallParam installParam; + std::string bundleFile = RESOURCE_ROOT_PATH + INVALID_BUNDLE; + GetBundleInstallerManager()->CreateUninstallTask(bundleFile, installParam, receiver); + ErrCode result = receiver->GetResultCode(); + EXPECT_NE(ERR_OK, result); +} + +/** + * @tc.number: ThirdPartyInstall_0100 + * @tc.name: test the right third party bundle file can be installed + * @tc.desc: 1.the third party bundle file exists + * 2.the third party bundle can be installed successfully and can get the bundle info + */ +HWTEST_F(BmsBundleInstallerTest, ThirdPartyInstall_0100, Function | SmallTest | Level0) +{ + std::string bundleFile = RESOURCE_ROOT_PATH + RIGHT_BUNDLE; + ErrCode result = InstallThirdPartyBundle(bundleFile); + ASSERT_EQ(result, ERR_OK); + CheckFileExist(); + CheckDbExist(); +} + +/** + * @tc.number: ThirdPartyInstall_0200 + * @tc.name: test the wrong third party bundle file can't be installed + * @tc.desc: 1.the third party bundle file don't exists + * 2.the third party bundle can't be installed and the result is fail + */ +HWTEST_F(BmsBundleInstallerTest, ThirdPartyInstall_0200, Function | SmallTest | Level0) +{ + std::string nonExistFile = RESOURCE_ROOT_PATH + INVALID_BUNDLE; + ErrCode result = InstallThirdPartyBundle(nonExistFile); + ASSERT_EQ(result, ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID); + CheckFileNonExist(); + CheckDbNonExist(); +} + +/** + * @tc.number: ThirdPartyInstall_0300 + * @tc.name: test the empty path can't be installed + * @tc.desc: 1.the third party bundle file path is empty + * 2.the third party bundle can't be installed and the result is fail + */ +HWTEST_F(BmsBundleInstallerTest, ThirdPartyInstall_0300, Function | SmallTest | Level0) +{ + ErrCode result = InstallThirdPartyBundle(""); + ASSERT_EQ(result, ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID); + CheckFileNonExist(); + CheckDbNonExist(); +} + +/** + * @tc.number: ThirdPartyInstall_0400 + * @tc.name: test the illegal bundleName file can't be installed + * @tc.desc: 1.the third party bundle name is illegal + * 2.the third party bundle can't be installed and the result is fail + */ +HWTEST_F(BmsBundleInstallerTest, ThirdPartyInstall_0400, Function | SmallTest | Level0) +{ + std::string wrongBundleName = RESOURCE_ROOT_PATH + WRONG_BUNDLE_NAME; + ErrCode result = InstallThirdPartyBundle(wrongBundleName); + ASSERT_EQ(result, ERR_APPEXECFWK_INSTALL_INVALID_HAP_NAME); + CheckFileNonExist(); + CheckDbNonExist(); +} + +/** + * @tc.number: ThirdPartyInstall_0500 + * @tc.name: test the error format bundle file can't be installed + * @tc.desc: 1.the third party bundle format is error + * 2.the third party bundle can't be installed and the result is fail + */ +HWTEST_F(BmsBundleInstallerTest, ThirdPartyInstall_0500, Function | SmallTest | Level0) +{ + std::string errorFormat = RESOURCE_ROOT_PATH + FORMAT_ERROR_BUNDLE; + ErrCode result = InstallThirdPartyBundle(errorFormat); + ASSERT_EQ(result, ERR_APPEXECFWK_PARSE_NO_PROFILE); + CheckFileNonExist(); + CheckDbNonExist(); +} + +/** + * @tc.number: ThirdPartyInstall_0600 + * @tc.name: test the bundle file with invalid path will cause the result of install failure + * @tc.desc: 1.the bundle file has invalid path + * 2.the third party bundle can't be installed and the result is fail + */ +HWTEST_F(BmsBundleInstallerTest, ThirdPartyInstall_0600, Function | SmallTest | Level0) +{ + std::string bundleFile = INVALID_PATH + RIGHT_BUNDLE; + ErrCode result = InstallThirdPartyBundle(bundleFile); + ASSERT_EQ(result, ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID); + CheckFileNonExist(); + CheckDbNonExist(); +} + +/** + * @tc.number: ThirdPartyInstall_0700 + * @tc.name: test the install will fail when installd service has error + * @tc.desc: 1.the installd service has error + * 2.the install result is fail + */ +HWTEST_F(BmsBundleInstallerTest, ThirdPartyInstall_0700, Function | SmallTest | Level0) +{ + StopInstalldService(); + std::string bundleFile = RESOURCE_ROOT_PATH + RIGHT_BUNDLE; + ErrCode result = InstallThirdPartyBundle(bundleFile); + ASSERT_EQ(result, ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR); +} + +/** + * @tc.number: ThirdPartyUpdateData_0100 + * @tc.name: test the right bundle file can be installed and update its info to bms + * @tc.desc: 1.the ThirdParty bundle is available + * 2.the right bundle can be installed and update its info to bms + */ +HWTEST_F(BmsBundleInstallerTest, ThirdPartyUpdateData_0100, Function | SmallTest | Level0) +{ + ApplicationInfo info; + auto dataMgr = GetBundleDataMgr(); + ASSERT_NE(dataMgr, nullptr); + bool result = dataMgr->GetApplicationInfo(BUNDLE_NAME, ApplicationFlag::GET_BASIC_APPLICATION_INFO, USERID, info); + ASSERT_FALSE(result); + std::string bundleFile = RESOURCE_ROOT_PATH + RIGHT_BUNDLE; + ErrCode installResult = InstallThirdPartyBundle(bundleFile); + ASSERT_EQ(installResult, ERR_OK); + result = dataMgr->GetApplicationInfo(BUNDLE_NAME, ApplicationFlag::GET_BASIC_APPLICATION_INFO, USERID, info); + ASSERT_TRUE(result); + EXPECT_EQ(info.name, BUNDLE_NAME); +} + +/** + * @tc.number: ThirdPartyUpdateData_0200 + * @tc.name: test the wrong bundle file can't be installed and its info will not updated to bms + * @tc.desc: 1.the ThirdParty bundle is wrong + * 2.the wrong bundle can't be installed and its info will not updated to bms + */ +HWTEST_F(BmsBundleInstallerTest, ThirdPartyUpdateData_0200, Function | SmallTest | Level0) +{ + ApplicationInfo info; + auto dataMgr = GetBundleDataMgr(); + ASSERT_NE(dataMgr, nullptr); + bool result = dataMgr->GetApplicationInfo(BUNDLE_NAME, ApplicationFlag::GET_BASIC_APPLICATION_INFO, USERID, info); + ASSERT_FALSE(result); + std::string wrongBundleName = RESOURCE_ROOT_PATH + WRONG_BUNDLE_NAME; + ErrCode installResult = InstallThirdPartyBundle(wrongBundleName); + ASSERT_EQ(installResult, ERR_APPEXECFWK_INSTALL_INVALID_HAP_NAME); + result = dataMgr->GetApplicationInfo(BUNDLE_NAME, ApplicationFlag::GET_BASIC_APPLICATION_INFO, USERID, info); + EXPECT_FALSE(result); +} + +/** + * @tc.number: ThirdPartyUpdateData_0300 + * @tc.name: test the already installed bundle can't be reinstalled and update its info to bms + * @tc.desc: 1.the bundle is already installed + * 2.the already installed bundle can't be reinstalled and update its info to bms + */ +HWTEST_F(BmsBundleInstallerTest, ThirdPartyUpdateData_0300, Function | SmallTest | Level0) +{ + auto dataMgr = GetBundleDataMgr(); + ASSERT_NE(dataMgr, nullptr); + // prepare already install information. + std::string bundleFile = RESOURCE_ROOT_PATH + RIGHT_BUNDLE; + ErrCode firstInstall = InstallThirdPartyBundle(bundleFile); + ASSERT_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); + ErrCode secondInstall = InstallThirdPartyBundle(bundleFile); + EXPECT_EQ(secondInstall, ERR_APPEXECFWK_INSTALL_ALREADY_EXIST); +} + +/** + * @tc.number: ThirdPartyUpdateData_0400 + * @tc.name: test the already installed bundle can be reinstalled and update its info to bms + * @tc.desc: 1.the bundle is already installed + * 2.the already installed bundle can be reinstalled and update its info to bms + */ +HWTEST_F(BmsBundleInstallerTest, ThirdPartyUpdateData_0400, Function | SmallTest | Level0) +{ + auto dataMgr = GetBundleDataMgr(); + ASSERT_NE(dataMgr, nullptr); + // prepare already install information. + std::string bundleFile = RESOURCE_ROOT_PATH + RIGHT_BUNDLE; + ErrCode firstInstall = InstallThirdPartyBundle(bundleFile); + ASSERT_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); + ErrCode secondInstall = UpdateThirdPartyBundle(bundleFile); + EXPECT_EQ(secondInstall, ERR_OK); +} + +/** + * @tc.number: ThirdPartyUpdateData_0500 + * @tc.name: test the already installing bundle can't be reinstalled and update its info to bms + * @tc.desc: 1.the bundle is already installing + * 2.the already installing bundle can't be reinstalled and update its info to bms + */ +HWTEST_F(BmsBundleInstallerTest, ThirdPartyUpdateData_0500, Function | SmallTest | Level0) +{ + // prepare already install information. + auto dataMgr = GetBundleDataMgr(); + ASSERT_NE(dataMgr, nullptr); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); + // begin to reinstall package + std::string bundleFile = RESOURCE_ROOT_PATH + RIGHT_BUNDLE; + ErrCode installResult = InstallThirdPartyBundle(bundleFile); + EXPECT_EQ(installResult, ERR_APPEXECFWK_INSTALL_STATE_ERROR); + // reset the install state + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_FAIL); +} \ No newline at end of file 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 new file mode 100644 index 000000000..8d06c4fe6 --- /dev/null +++ b/services/bundlemgr/test/unittest/bms_bundle_kit_service_test/BUILD.gn @@ -0,0 +1,84 @@ +# 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") +import( + "//foundation/appexecfwk/standard/services/bundlemgr/appexecfwk_bundlemgr.gni") + +module_output_path = "appexecfwk_standard/bundlemgrservice" + +ohos_unittest("BmsBundleKitServiceTest") { + module_out_path = module_output_path + + sources = [ + "${innerkits_path}/appexecfwk_base/src/ability_info.cpp", + "${innerkits_path}/appexecfwk_base/src/application_info.cpp", + "${innerkits_path}/appexecfwk_base/src/bundle_info.cpp", + "${services_path}/bundlemgr/src/bundle_data_mgr.cpp", + "${services_path}/bundlemgr/src/bundle_data_storage.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/installd/installd_host_impl.cpp", + "${services_path}/bundlemgr/src/installd/installd_operator.cpp", + "${services_path}/bundlemgr/src/installd/installd_service.cpp", + ] + + sources += [ + "${services_path}/bundlemgr/test/mock/src/mock_bundle_status.cpp", + "${services_path}/bundlemgr/test/mock/src/mock_clean_cache.cpp", + "${services_path}/bundlemgr/test/mock/src/system_ability_helper.cpp", + ] + + sources += bundle_install_sources + + sources += [ "bms_bundle_kit_service_test.cpp" ] + + configs = [ + "${services_path}/bundlemgr/test:bundlemgr_test_config", + "${libs_path}/libeventhandler:libeventhandler_config", + "${innerkits_path}/appexecfwk_base:appexecfwk_base_sdk_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${libs_path}/libeventhandler:libeventhandler_target", + "//base/notification/ces_standard/cesfwk/kits/native:cesfwk_kits", + "//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/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/googletest:gtest_main", + ] + + deps += bundle_install_deps + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":BmsBundleKitServiceTest" ] +} 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 new file mode 100755 index 000000000..5aee4c012 --- /dev/null +++ b/services/bundlemgr/test/unittest/bms_bundle_kit_service_test/bms_bundle_kit_service_test.cpp @@ -0,0 +1,1894 @@ +/* + * 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 "directory_ex.h" +#include "bundle_data_mgr.h" +#include "install_param.h" +#include "bundle_mgr_service.h" +#include "bundle_mgr_host.h" +#include "bundle_info.h" +#include "installd/installd_service.h" +#include "installd_client.h" +#include "mock_clean_cache.h" +#include "mock_bundle_status.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; +using OHOS::AAFwk::Want; + +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_TEST = ".Reading"; +const int TEST_UID = 1001; +const std::string BUNDLE_LABEL = "Hello, OHOS"; +const std::string BUNDLE_DESCRIPTION = "example helloworld"; +const std::string BUNDLE_VENDOR = "example"; +const std::string BUNDLE_VERSION_NAME = "1.0.0.1"; +const std::string BUNDLE_MAIN_ABILITY = "com.example.bundlekit.test.entry"; +const int32_t BUNDLE_MAX_SDK_VERSION = 0; +const int32_t BUNDLE_MIN_SDK_VERSION = 0; +const uint32_t BUNDLE_VERSION_CODE = 1001; +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"; +const int DEMO_UID = 30001; +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 DEFAULT_USER_ID = 0; +const std::string LABEL = "hello"; +const std::string DESCRIPTION = "mainEntry"; +const std::string ICON_PATH = "/data/data/icon.png"; +const std::string KIND = "test"; +const std::string ACTION = "action.system.home"; +const std::string ENTITY = "entity.system.home"; +const std::string URI_SCHEME = "fakescheme"; +const std::string URI_HOST = "fakehost"; +const AbilityType ABILITY_TYPE = AbilityType::PAGE; +const DisplayOrientation ORIENTATION = DisplayOrientation::PORTRAIT; +const LaunchMode LAUNCH_MODE = LaunchMode::SINGLETON; +const std::string CODE_PATH = "/data/accounts/account_0/com.example.bundlekit.test/code"; +const std::string RESOURCE_PATH = "/data/accounts/account_0/com.example.bundlekit.test/res"; +const std::string LIB_PATH = "/data/accounts/account_0/com.example.bundlekit.test/lib"; +const std::string BUNDLE_DATA_BASE_DIR = "/data/bundlemgr"; +const std::string BUNDLE_DATA_BASE_FILE = BUNDLE_DATA_BASE_DIR + "/bmsdb.json"; +const bool VISIBLE = true; +const std::string MAIN_ENTRY = "com.example.bundlekit.test.entry"; +const uint32_t ABILITY_SIZE_ZERO = 0; +const uint32_t ABILITY_SIZE_ONE = 1; +const uint32_t PERMISSION_SIZE_ZERO = 0; +const uint32_t PERMISSION_SIZE_TWO = 2; +const std::string EMPTY_STRING = ""; +const int INVALID_UID = -1; +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"; +const std::string HAP_FILE_PATH1 = "/data/test/resource/bms/bundle_kit/test1.hap"; +const std::string ERROR_HAP_FILE_PATH = "/data/test/resource/bms/bundle_kit/error.hap"; +const std::string META_DATA = "name"; +const std::string ERROR_META_DATA = "String"; +const std::string BUNDLE_DATA_DIR = "/data/accounts/account_0/appdata/com.example.bundlekit.test"; +const std::string FILES_DIR = "/data/accounts/account_0/appdata/com.example.bundlekit.test/files"; +const std::string TEST_FILE_DIR = "/data/accounts/account_0/appdata/com.example.bundlekit.test/files/file"; +const std::string DATA_BASE_DIR = "/data/accounts/account_0/appdata/com.example.bundlekit.test/database"; +const std::string TEST_DATA_BASE_DIR = "/data/accounts/account_0/appdata/com.example.bundlekit.test/database/database"; +const std::string CACHE_DIR = "/data/accounts/account_0/appdata/com.example.bundlekit.test/cache"; +const std::string TEST_CACHE_DIR = "/data/accounts/account_0/appdata/com.example.bundlekit.test/cache/cache"; + +} // namespace + +class BmsBundleKitServiceTest : public testing::Test { +public: + using Want = OHOS::AAFwk::Want; + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + std::shared_ptr GetBundleDataMgr() const; + void MockInstallBundle( + const std::string &bundleName, const std::string &moduleName, const std::string &abilityName) const; + void MockUninstallBundle(const std::string &bundleName) const; + AbilityInfo MockAbilityInfo( + const std::string &bundleName, const std::string &module, const std::string &abilityName) const; + void CheckBundleInfo(const std::string &bundleName, const std::string &moduleName, const uint32_t abilitySize, + const BundleInfo &bundleInfo) const; + void CheckBundleList(const std::string &bundleName, const std::vector &bundleList) const; + void CheckApplicationInfo( + const std::string &bundleName, const uint32_t permissionSize, const ApplicationInfo &appInfo) const; + void CheckAbilityInfo( + const std::string &bundleName, const std::string &abilityName, const AbilityInfo &appInfo) const; + void CheckInstalledBundleInfos(const uint32_t abilitySize, const std::vector &bundleInfos) const; + void CheckInstalledApplicationInfos(const uint32_t permsSize, const std::vector &appInfos) const; + void CheckModuleInfo(const HapModuleInfo &hapModuleInfo) const; + void CreateFileDir() const; + void CleanFileDir() const; + void CheckFileExist() const; + void CheckFileNonExist() const; + void CheckCacheExist() const; + void CheckCacheNonExist() const; + +public: + std::shared_ptr bundleMgrService_ = DelayedSingleton::GetInstance(); + std::shared_ptr service_ = std::make_shared(); +}; + +void BmsBundleKitServiceTest::SetUpTestCase() +{ + std::string fileName = Constants::BUNDLE_DATA_BASE_FILE; + std::ofstream o(fileName); + if (!o.is_open()) { + std::cout << "failed to open as out" << fileName << std::endl; + return; + } else { + std::cout << "clear" << fileName << std::endl; + } + o.close(); +} + +void BmsBundleKitServiceTest::TearDownTestCase() +{} + +void BmsBundleKitServiceTest::SetUp() +{ + bundleMgrService_->OnStart(); +} + +void BmsBundleKitServiceTest::TearDown() +{} + +std::shared_ptr BmsBundleKitServiceTest::GetBundleDataMgr() const +{ + return bundleMgrService_->GetDataMgr(); +} + +void BmsBundleKitServiceTest::MockInstallBundle( + const std::string &bundleName, const std::string &moduleName, const std::string &abilityName) const +{ + InnerBundleInfo innerBundleInfo; + ApplicationInfo appInfo; + appInfo.bundleName = bundleName; + appInfo.name = bundleName; + appInfo.deviceId = DEVICE_ID; + appInfo.process = PROCESS_TEST; + appInfo.label = BUNDLE_LABEL; + appInfo.description = BUNDLE_DESCRIPTION; + appInfo.codePath = CODE_PATH; + appInfo.dataDir = FILES_DIR; + appInfo.dataBaseDir = DATA_BASE_DIR; + appInfo.cacheDir = CACHE_DIR; + + BundleInfo bundleInfo; + bundleInfo.name = bundleName; + bundleInfo.label = BUNDLE_LABEL; + bundleInfo.description = BUNDLE_DESCRIPTION; + bundleInfo.vendor = BUNDLE_VENDOR; + bundleInfo.versionCode = BUNDLE_VERSION_CODE; + bundleInfo.versionName = BUNDLE_VERSION_NAME; + bundleInfo.minSdkVersion = BUNDLE_MIN_SDK_VERSION; + bundleInfo.maxSdkVersion = BUNDLE_MAX_SDK_VERSION; + bundleInfo.mainEntry = MAIN_ENTRY; + bundleInfo.isKeepAlive = true; + + InnerModuleInfo moduleInfo; + ReqPermission reqPermission1 = {.name = "permission1"}; + ReqPermission reqPermission2 = {.name = "permission1"}; + moduleInfo.reqPermissions = {reqPermission1, reqPermission2}; + moduleInfo.modulePackage = PACKAGE_NAME; + moduleInfo.moduleName = PACKAGE_NAME; + moduleInfo.description = BUNDLE_DESCRIPTION; + + AppExecFwk::Parameters parameters{"description", "name", "type"}; + AppExecFwk::Results results{"description", "name", "type"}; + AppExecFwk::CustomizeData customizeData{"name", "value", "extra"}; + MetaData metaData{{parameters}, {results}, {customizeData}}; + moduleInfo.metaData = metaData; + + AbilityInfo abilityInfo = MockAbilityInfo(bundleName, moduleName, abilityName); + innerBundleInfo.SetBaseApplicationInfo(appInfo); + innerBundleInfo.SetBaseBundleInfo(bundleInfo); + innerBundleInfo.InsertInnerModuleInfo(moduleName, moduleInfo); + std::string keyName = bundleName + moduleName + abilityName; + innerBundleInfo.InsertAbilitiesInfo(keyName, abilityInfo); + innerBundleInfo.SetUid((bundleName == BUNDLE_NAME_TEST) ? TEST_UID : DEMO_UID); + // for launch ability + if (bundleName == BUNDLE_NAME_TEST) { + AppExecFwk::SkillUri uri{URI_SCHEME, URI_HOST}; + Skill skill{{ACTION}, {ENTITY}, {uri}}; + std::vector skills; + skills.emplace_back(skill); + innerBundleInfo.SetMainAbility(keyName); + innerBundleInfo.InsertSkillInfo(keyName, skills); + } + + auto dataMgr = GetBundleDataMgr(); + ASSERT_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); +} + +void BmsBundleKitServiceTest::MockUninstallBundle(const std::string &bundleName) const +{ + auto dataMgr = GetBundleDataMgr(); + ASSERT_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); +} + +AbilityInfo BmsBundleKitServiceTest::MockAbilityInfo( + const std::string &bundleName, const std::string &moduleName, const std::string &abilityName) const +{ + AbilityInfo abilityInfo; + abilityInfo.package = PACKAGE_NAME; + abilityInfo.name = abilityName; + abilityInfo.bundleName = bundleName; + abilityInfo.moduleName = moduleName; + abilityInfo.deviceId = DEVICE_ID; + abilityInfo.label = LABEL; + abilityInfo.description = DESCRIPTION; + abilityInfo.iconPath = ICON_PATH; + abilityInfo.visible = VISIBLE; + abilityInfo.kind = KIND; + abilityInfo.type = ABILITY_TYPE; + abilityInfo.orientation = ORIENTATION; + abilityInfo.launchMode = LAUNCH_MODE; + abilityInfo.codePath = CODE_PATH; + abilityInfo.resourcePath = RESOURCE_PATH; + abilityInfo.libPath = LIB_PATH; + abilityInfo.uri = URI; + return abilityInfo; +} + +void BmsBundleKitServiceTest::CheckBundleInfo(const std::string &bundleName, const std::string &moduleName, + const uint32_t abilitySize, const BundleInfo &bundleInfo) const +{ + EXPECT_EQ(bundleName, bundleInfo.name); + EXPECT_EQ(BUNDLE_LABEL, bundleInfo.label); + EXPECT_EQ(BUNDLE_DESCRIPTION, bundleInfo.description); + EXPECT_EQ(BUNDLE_VENDOR, bundleInfo.vendor); + EXPECT_EQ(BUNDLE_VERSION_CODE, bundleInfo.versionCode); + EXPECT_EQ(BUNDLE_VERSION_NAME, bundleInfo.versionName); + EXPECT_EQ(BUNDLE_MIN_SDK_VERSION, bundleInfo.minSdkVersion); + EXPECT_EQ(BUNDLE_MAX_SDK_VERSION, bundleInfo.maxSdkVersion); + EXPECT_EQ(BUNDLE_MAIN_ABILITY, bundleInfo.mainEntry); + EXPECT_EQ(bundleName, bundleInfo.applicationInfo.name); + EXPECT_EQ(bundleName, bundleInfo.applicationInfo.bundleName); + EXPECT_EQ(abilitySize, static_cast(bundleInfo.abilityInfos.size())); +} + +void BmsBundleKitServiceTest::CheckBundleList( + const std::string &bundleName, const std::vector &bundleList) const +{ + EXPECT_TRUE(std::find(bundleList.begin(), bundleList.end(), bundleName) != bundleList.end()); +} + +void BmsBundleKitServiceTest::CheckApplicationInfo( + const std::string &bundleName, const uint32_t permissionSize, const ApplicationInfo &appInfo) const +{ + EXPECT_EQ(bundleName, appInfo.name); + EXPECT_EQ(bundleName, appInfo.bundleName); + EXPECT_EQ(BUNDLE_LABEL, appInfo.label); + EXPECT_EQ(BUNDLE_DESCRIPTION, appInfo.description); + EXPECT_EQ(DEVICE_ID, appInfo.deviceId); + EXPECT_EQ(PROCESS_TEST, appInfo.process); + EXPECT_EQ(CODE_PATH, appInfo.codePath); + EXPECT_EQ(permissionSize, static_cast(appInfo.permissions.size())); +} + +void BmsBundleKitServiceTest::CheckAbilityInfo( + const std::string &bundleName, const std::string &abilityName, const AbilityInfo &abilityInfo) const +{ + EXPECT_EQ(abilityName, abilityInfo.name); + EXPECT_EQ(bundleName, abilityInfo.bundleName); + EXPECT_EQ(LABEL, abilityInfo.label); + EXPECT_EQ(DESCRIPTION, abilityInfo.description); + EXPECT_EQ(DEVICE_ID, abilityInfo.deviceId); + EXPECT_EQ(ICON_PATH, abilityInfo.iconPath); + EXPECT_EQ(CODE_PATH, abilityInfo.codePath); + EXPECT_EQ(ORIENTATION, abilityInfo.orientation); + EXPECT_EQ(LAUNCH_MODE, abilityInfo.launchMode); + EXPECT_EQ(URI, abilityInfo.uri); +} + +void BmsBundleKitServiceTest::CheckModuleInfo(const HapModuleInfo &hapModuleInfo) const +{ + EXPECT_EQ(MODULE_NAME_TEST, hapModuleInfo.name); + EXPECT_EQ(MODULE_NAME_TEST, hapModuleInfo.moduleName); + EXPECT_EQ(BUNDLE_DESCRIPTION, hapModuleInfo.description); + EXPECT_EQ(ICON_PATH, hapModuleInfo.iconPath); + EXPECT_EQ(LABEL, hapModuleInfo.label); +} + +void BmsBundleKitServiceTest::CheckInstalledBundleInfos( + const uint32_t abilitySize, const std::vector &bundleInfos) const +{ + bool isContainsDemoBundle = false; + bool isContainsTestBundle = false; + bool checkDemoAppNameRet = false; + bool checkTestAppNameRet = false; + bool checkDemoAbilitySizeRet = false; + bool checkTestAbilitySizeRet = false; + for (auto item : bundleInfos) { + if (item.name == BUNDLE_NAME_DEMO) { + isContainsDemoBundle = true; + checkDemoAppNameRet = item.applicationInfo.name == BUNDLE_NAME_DEMO; + uint32_t num = static_cast(item.abilityInfos.size()); + checkDemoAbilitySizeRet = num == abilitySize; + } + if (item.name == BUNDLE_NAME_TEST) { + isContainsTestBundle = true; + checkTestAppNameRet = item.applicationInfo.name == BUNDLE_NAME_TEST; + uint32_t num = static_cast(item.abilityInfos.size()); + checkTestAbilitySizeRet = num == abilitySize; + } + } + EXPECT_TRUE(isContainsDemoBundle); + EXPECT_TRUE(isContainsTestBundle); + EXPECT_TRUE(checkDemoAppNameRet); + EXPECT_TRUE(checkTestAppNameRet); + EXPECT_TRUE(checkDemoAbilitySizeRet); + EXPECT_TRUE(checkTestAbilitySizeRet); +} + +void BmsBundleKitServiceTest::CheckInstalledApplicationInfos( + const uint32_t permsSize, const std::vector &appInfos) const +{ + bool isContainsDemoBundle = false; + bool isContainsTestBundle = false; + bool checkDemoAppNameRet = false; + bool checkTestAppNameRet = false; + bool checkDemoAbilitySizeRet = false; + bool checkTestAbilitySizeRet = false; + for (auto item : appInfos) { + if (item.name == BUNDLE_NAME_DEMO) { + isContainsDemoBundle = true; + checkDemoAppNameRet = item.bundleName == BUNDLE_NAME_DEMO; + uint32_t num = static_cast(item.permissions.size()); + checkDemoAbilitySizeRet = num == permsSize; + } + if (item.name == BUNDLE_NAME_TEST) { + isContainsTestBundle = true; + checkTestAppNameRet = item.bundleName == BUNDLE_NAME_TEST; + uint32_t num = static_cast(item.permissions.size()); + checkTestAbilitySizeRet = num == permsSize; + } + } + EXPECT_TRUE(isContainsDemoBundle); + EXPECT_TRUE(isContainsTestBundle); + EXPECT_TRUE(checkDemoAppNameRet); + EXPECT_TRUE(checkTestAppNameRet); + EXPECT_TRUE(checkDemoAbilitySizeRet); + EXPECT_TRUE(checkTestAbilitySizeRet); +} + +void BmsBundleKitServiceTest::CreateFileDir() const +{ + if (!service_->IsServiceReady()) { + service_->Start(); + } + + 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"; + } + + 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"; + } +} + +void BmsBundleKitServiceTest::CleanFileDir() const +{ + service_->Stop(); + InstalldClient::GetInstance()->ResetInstalldProxy(); + + OHOS::ForceRemoveDirectory(BUNDLE_DATA_DIR); +} + +void BmsBundleKitServiceTest::CheckFileExist() const +{ + int dataExist = access(TEST_FILE_DIR.c_str(), F_OK); + ASSERT_EQ(dataExist, 0); +} + +void BmsBundleKitServiceTest::CheckFileNonExist() const +{ + int dataExist = access(TEST_FILE_DIR.c_str(), F_OK); + ASSERT_NE(dataExist, 0); +} + +void BmsBundleKitServiceTest::CheckCacheExist() const +{ + int dataExist = access(TEST_CACHE_DIR.c_str(), F_OK); + ASSERT_EQ(dataExist, 0); +} + +void BmsBundleKitServiceTest::CheckCacheNonExist() const +{ + int dataExist = access(TEST_CACHE_DIR.c_str(), F_OK); + ASSERT_NE(dataExist, 0); +} + +/** + * @tc.number: GetBundleInfo_0100 + * @tc.name: test can get the bundleName's bundle info + * @tc.desc: 1.system run normal + * 2.get bundle info successfully + */ +HWTEST_F(BmsBundleKitServiceTest, GetBundleInfo_0100, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + MockInstallBundle(BUNDLE_NAME_DEMO, MODULE_NAME_DEMO, ABILITY_NAME_DEMO); + + BundleInfo testResult; + bool testRet = GetBundleDataMgr()->GetBundleInfo(BUNDLE_NAME_TEST, BundleFlag::GET_BUNDLE_DEFAULT, testResult); + EXPECT_TRUE(testRet); + CheckBundleInfo(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_SIZE_ZERO, testResult); + + BundleInfo demoResult; + bool demoRet = + GetBundleDataMgr()->GetBundleInfo(BUNDLE_NAME_DEMO, BundleFlag::GET_BUNDLE_WITH_ABILITIES, demoResult); + EXPECT_TRUE(demoRet); + CheckBundleInfo(BUNDLE_NAME_DEMO, MODULE_NAME_DEMO, ABILITY_SIZE_ONE, demoResult); + + MockUninstallBundle(BUNDLE_NAME_TEST); + MockUninstallBundle(BUNDLE_NAME_DEMO); +} + +/** + * @tc.number: GetBundleInfo_0200 + * @tc.name: test can not get the bundleName's bundle info which not exist in system + * @tc.desc: 1.system run normal + * 2.get bundle info failed + */ +HWTEST_F(BmsBundleKitServiceTest, GetBundleInfo_0200, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + BundleInfo result; + bool ret = GetBundleDataMgr()->GetBundleInfo(BUNDLE_NAME_DEMO, BundleFlag::GET_BUNDLE_DEFAULT, result); + EXPECT_FALSE(ret); + EXPECT_EQ(EMPTY_STRING, result.label); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: GetBundleInfo_0300 + * @tc.name: test can not get bundle info with empty bundle name + * @tc.desc: 1.system run normal + * 2.get bundle info failed with empty bundle name + */ +HWTEST_F(BmsBundleKitServiceTest, GetBundleInfo_0300, Function | SmallTest | Level0) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + BundleInfo result; + bool ret = GetBundleDataMgr()->GetBundleInfo(EMPTY_STRING, BundleFlag::GET_BUNDLE_DEFAULT, result); + EXPECT_FALSE(ret); + EXPECT_EQ(EMPTY_STRING, result.name); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: GetBundleInfo_0400 + * @tc.name: test can not get the bundleName's bundle info with no bundle in system + * @tc.desc: 1.system run normally and without any bundle + * 2.get bundle info failed with no bundle in system + */ +HWTEST_F(BmsBundleKitServiceTest, GetBundleInfo_0400, Function | SmallTest | Level0) +{ + BundleInfo bundleInfo; + bool ret = GetBundleDataMgr()->GetBundleInfo(BUNDLE_NAME_TEST, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); + ASSERT_FALSE(ret); + EXPECT_EQ(EMPTY_STRING, bundleInfo.name); + EXPECT_EQ(EMPTY_STRING, bundleInfo.label); +} + +/** + * @tc.number: GetBundleInfo_0500 + * @tc.name: test can parceable bundle info + * @tc.desc: 1.system run normally + * 2.get bundle info successfully + */ +HWTEST_F(BmsBundleKitServiceTest, GetBundleInfo_0500, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + BundleInfo bundleInfo; + bool ret = GetBundleDataMgr()->GetBundleInfo(BUNDLE_NAME_TEST, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); + EXPECT_TRUE(ret); + Parcel parcel; + parcel.WriteParcelable(&bundleInfo); + std::unique_ptr bundleInfoTest; + bundleInfoTest.reset(parcel.ReadParcelable()); + EXPECT_EQ(bundleInfo.name, bundleInfoTest->name); + EXPECT_EQ(bundleInfo.label, bundleInfoTest->label); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: GetBundleInfos_0100 + * @tc.name: test can get the installed bundles's bundle info with nomal flag + * @tc.desc: 1.system run normally + * 2.get all installed bundle info successfully + */ +HWTEST_F(BmsBundleKitServiceTest, GetBundleInfos_0100, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_DEMO, MODULE_NAME_DEMO, ABILITY_NAME_DEMO); + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + std::vector bundleInfos; + bool ret = GetBundleDataMgr()->GetBundleInfos(BundleFlag::GET_BUNDLE_DEFAULT, bundleInfos); + ASSERT_TRUE(ret); + CheckInstalledBundleInfos(ABILITY_SIZE_ZERO, bundleInfos); + + MockUninstallBundle(BUNDLE_NAME_TEST); + MockUninstallBundle(BUNDLE_NAME_DEMO); +} + +/** + * @tc.number: GetBundleInfos_0200 + * @tc.name: test can get the installed bundles's bundle info with abilities + * @tc.desc: 1.system run normally + * 2.get all installed bundle info successfully + */ +HWTEST_F(BmsBundleKitServiceTest, GetBundleInfos_0200, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_DEMO, MODULE_NAME_DEMO, ABILITY_NAME_DEMO); + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + std::vector bundleInfos; + bool ret = GetBundleDataMgr()->GetBundleInfos(BundleFlag::GET_BUNDLE_WITH_ABILITIES, bundleInfos); + ASSERT_TRUE(ret); + CheckInstalledBundleInfos(ABILITY_SIZE_ONE, bundleInfos); + + MockUninstallBundle(BUNDLE_NAME_TEST); + MockUninstallBundle(BUNDLE_NAME_DEMO); +} + +/** + * @tc.number: GetBundleInfos_0300 + * @tc.name: test can not get the installed bundles's bundle info with no bundle + * @tc.desc: 1.system run normally + * 2.get all installed bundle info failed + */ +HWTEST_F(BmsBundleKitServiceTest, GetBundleInfos_0300, Function | SmallTest | Level1) +{ + std::vector bundleInfos; + bool ret = GetBundleDataMgr()->GetBundleInfos(BundleFlag::GET_BUNDLE_WITH_ABILITIES, bundleInfos); + ASSERT_FALSE(ret); +} + +/** + * @tc.number: GetApplicationInfo_0100 + * @tc.name: test can get the appName's application info + * @tc.desc: 1.system run normally + * 2.get application info successfully + */ +HWTEST_F(BmsBundleKitServiceTest, GetApplicationInfo_0100, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + MockInstallBundle(BUNDLE_NAME_DEMO, MODULE_NAME_DEMO, ABILITY_NAME_DEMO); + + ApplicationInfo testResult; + bool testRet = GetBundleDataMgr()->GetApplicationInfo( + BUNDLE_NAME_TEST, ApplicationFlag::GET_BASIC_APPLICATION_INFO, DEFAULT_USER_ID, 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); + EXPECT_TRUE(demoRet); + CheckApplicationInfo(BUNDLE_NAME_DEMO, PERMISSION_SIZE_TWO, demoResult); + + MockUninstallBundle(BUNDLE_NAME_TEST); + MockUninstallBundle(BUNDLE_NAME_DEMO); +} + +/** + * @tc.number: GetApplicationInfo_0200 + * @tc.name: test can not get the appName's application info which not exist in system + * @tc.desc: 1.system run normally + * 2.get application info failed + */ +HWTEST_F(BmsBundleKitServiceTest, GetApplicationInfo_0200, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + ApplicationInfo result; + bool ret = GetBundleDataMgr()->GetApplicationInfo( + BUNDLE_NAME_DEMO, ApplicationFlag::GET_BASIC_APPLICATION_INFO, DEFAULT_USER_ID, result); + EXPECT_FALSE(ret); + EXPECT_EQ(EMPTY_STRING, result.name); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: GetApplicationInfo_0300 + * @tc.name: test can not get application info with empty appName + * @tc.desc: 1.system run normally + * 2.get application info failed with empty appName + */ +HWTEST_F(BmsBundleKitServiceTest, GetApplicationInfo_0300, Function | SmallTest | Level0) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + ApplicationInfo result; + bool ret = GetBundleDataMgr()->GetApplicationInfo( + EMPTY_STRING, ApplicationFlag::GET_BASIC_APPLICATION_INFO, DEFAULT_USER_ID, result); + EXPECT_FALSE(ret); + EXPECT_EQ(EMPTY_STRING, result.name); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: GetApplicationInfo_0400 + * @tc.name: test can not get the appName's application info with no bundle in system + * @tc.desc: 1.system run normally + * 2.get application info failed with no bundle in system + */ +HWTEST_F(BmsBundleKitServiceTest, GetApplicationInfo_0400, Function | SmallTest | Level0) +{ + ApplicationInfo result; + bool ret = GetBundleDataMgr()->GetApplicationInfo( + BUNDLE_NAME_TEST, ApplicationFlag::GET_BASIC_APPLICATION_INFO, DEFAULT_USER_ID, result); + ASSERT_FALSE(ret); + EXPECT_EQ(EMPTY_STRING, result.name); + EXPECT_EQ(EMPTY_STRING, result.label); +} + +/** + * @tc.number: GetApplicationInfo_0500 + * @tc.name: test can parceable application info + * @tc.desc: 1.system run normally + * 2.get application info successfully + */ +HWTEST_F(BmsBundleKitServiceTest, GetApplicationInfo_0500, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + ApplicationInfo result; + bool ret = GetBundleDataMgr()->GetApplicationInfo( + BUNDLE_NAME_TEST, ApplicationFlag::GET_BASIC_APPLICATION_INFO, DEFAULT_USER_ID, result); + EXPECT_TRUE(ret); + Parcel parcel; + parcel.WriteParcelable(&result); + std::unique_ptr appInfoTest; + appInfoTest.reset(parcel.ReadParcelable()); + EXPECT_EQ(result.name, appInfoTest->name); + EXPECT_EQ(result.label, appInfoTest->label); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: GetApplicationInfos_0100 + * @tc.name: test can get the installed bundles's application info with basic info flag + * @tc.desc: 1.system run normally + * 2.get all installed application info successfully + */ +HWTEST_F(BmsBundleKitServiceTest, GetApplicationInfos_0100, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_DEMO, MODULE_NAME_DEMO, ABILITY_NAME_DEMO); + 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); + CheckInstalledApplicationInfos(PERMISSION_SIZE_ZERO, appInfos); + + MockUninstallBundle(BUNDLE_NAME_TEST); + MockUninstallBundle(BUNDLE_NAME_DEMO); +} + +/** + * @tc.number: GetApplicationInfos_0200 + * @tc.name: test can get the installed bundles's application info with permissions + * @tc.desc: 1.system run normally + * 2.get all installed application info successfully + */ +HWTEST_F(BmsBundleKitServiceTest, GetApplicationInfos_0200, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_DEMO, MODULE_NAME_DEMO, ABILITY_NAME_DEMO); + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + std::vector appInfos; + bool ret = GetBundleDataMgr()->GetApplicationInfos( + ApplicationFlag::GET_APPLICATION_INFO_WITH_PERMS, DEFAULT_USER_ID, appInfos); + ASSERT_TRUE(ret); + CheckInstalledApplicationInfos(PERMISSION_SIZE_TWO, appInfos); + + MockUninstallBundle(BUNDLE_NAME_TEST); + MockUninstallBundle(BUNDLE_NAME_DEMO); +} + +/** + * @tc.number: GetApplicationInfos_0300 + * @tc.name: test can not get the installed bundles's bundle info with no bundle + * @tc.desc: 1.system run normally + * 2.get all installed bundle info failed + */ +HWTEST_F(BmsBundleKitServiceTest, GetApplicationInfos_0300, Function | SmallTest | Level1) +{ + std::vector appInfos; + bool ret = GetBundleDataMgr()->GetApplicationInfos( + ApplicationFlag::GET_APPLICATION_INFO_WITH_PERMS, DEFAULT_USER_ID, appInfos); + ASSERT_FALSE(ret); +} + +/** + * @tc.number: GetAbilityLabel_0100 + * @tc.name: test can get the ability's label by bundleName and abilityName + * @tc.desc: 1.system run normally + * 2.get ability label successfully + */ +HWTEST_F(BmsBundleKitServiceTest, GetAbilityLabel_0100, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + std::string testRet = GetBundleDataMgr()->GetAbilityLabel(BUNDLE_NAME_TEST, ABILITY_NAME_TEST); + EXPECT_EQ(LABEL, testRet); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: GetAbilityLabel_0200 + * @tc.name: test can not get the ability's label if bundle doesn't install + * @tc.desc: 1.system run normally + * 2.get empty ability label + */ +HWTEST_F(BmsBundleKitServiceTest, GetAbilityLabel_0200, Function | SmallTest | Level1) +{ + std::string testRet = GetBundleDataMgr()->GetAbilityLabel(BUNDLE_NAME_TEST, ABILITY_NAME_TEST); + EXPECT_EQ(EMPTY_STRING, testRet); +} + +/** + * @tc.number: GetAbilityLabel_0300 + * @tc.name: test can not get the ability's label if bundle doesn't exist + * @tc.desc: 1.system run normally + * 2.get empty ability label + */ +HWTEST_F(BmsBundleKitServiceTest, GetAbilityLabel_0300, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + std::string testRet = GetBundleDataMgr()->GetAbilityLabel(BUNDLE_NAME_DEMO, ABILITY_NAME_TEST); + EXPECT_EQ(EMPTY_STRING, testRet); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: GetAbilityLabel_0400 + * @tc.name: test can not get the ability's label if ability doesn't exist + * @tc.desc: 1.system run normally + * 2.get empty ability label + */ +HWTEST_F(BmsBundleKitServiceTest, GetAbilityLabel_0400, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + std::string testRet = GetBundleDataMgr()->GetAbilityLabel(BUNDLE_NAME_TEST, ABILITY_NAME_DEMO); + EXPECT_EQ(EMPTY_STRING, testRet); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: QueryAbilityInfo_0100 + * @tc.name: test can get the ability info by want + * @tc.desc: 1.system run normally + * 2.get ability info successfully + */ +HWTEST_F(BmsBundleKitServiceTest, QueryAbilityInfo_0100, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + Want want; + want.SetElementName(BUNDLE_NAME_TEST, ABILITY_NAME_TEST); + AbilityInfo result; + bool testRet = GetBundleDataMgr()->QueryAbilityInfo(want, result); + EXPECT_EQ(true, testRet); + CheckAbilityInfo(BUNDLE_NAME_TEST, ABILITY_NAME_TEST, result); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: QueryAbilityInfo_0200 + * @tc.name: test can not get the ability info by want in which element name is wrong + * @tc.desc: 1.system run normally + * 2.get ability info failed + */ +HWTEST_F(BmsBundleKitServiceTest, QueryAbilityInfo_0200, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + Want want; + want.SetElementName(BUNDLE_NAME_DEMO, ABILITY_NAME_TEST); + AbilityInfo result; + bool testRet = GetBundleDataMgr()->QueryAbilityInfo(want, result); + EXPECT_EQ(false, testRet); + + want.SetElementName(BUNDLE_NAME_TEST, ABILITY_NAME_DEMO); + testRet = GetBundleDataMgr()->QueryAbilityInfo(want, result); + EXPECT_EQ(false, testRet); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: QueryAbilityInfo_0300 + * @tc.name: test can not get the ability info by want which bundle doesn't exist + * @tc.desc: 1.system run normally + * 2.get ability info failed + */ +HWTEST_F(BmsBundleKitServiceTest, QueryAbilityInfo_0300, Function | SmallTest | Level1) +{ + Want want; + want.SetElementName(BUNDLE_NAME_TEST, ABILITY_NAME_TEST); + AbilityInfo result; + bool testRet = GetBundleDataMgr()->QueryAbilityInfo(want, result); + EXPECT_EQ(false, testRet); +} + +/** + * @tc.number: GetLaunchWantForBundle_0100 + * @tc.name: test can get the launch want of a bundle + * @tc.desc: 1.system run normally + * 2.get launch want successfully + */ +HWTEST_F(BmsBundleKitServiceTest, GetLaunchWantForBundle_0100, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + Want want; + bool testRet = GetBundleDataMgr()->GetLaunchWantForBundle(BUNDLE_NAME_TEST, want); + EXPECT_EQ(true, testRet); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: GetLaunchWantForBundle_0200 + * @tc.name: test can not get the launch want of a bundle which is not exist + * @tc.desc: 1.system run normally + * 2.get launch want failed + */ +HWTEST_F(BmsBundleKitServiceTest, GetLaunchWantForBundle_0200, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + Want want; + bool testRet = GetBundleDataMgr()->GetLaunchWantForBundle(BUNDLE_NAME_DEMO, want); + EXPECT_EQ(false, testRet); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: GetLaunchWantForBundle_0300 + * @tc.name: test can not get the launch want of a bundle which its mainability is not exist + * @tc.desc: 1.system run normally + * 2.get launch want failed + */ +HWTEST_F(BmsBundleKitServiceTest, GetLaunchWantForBundle_0300, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_DEMO, MODULE_NAME_DEMO, ABILITY_NAME_DEMO); + Want want; + bool testRet = GetBundleDataMgr()->GetLaunchWantForBundle(BUNDLE_NAME_DEMO, want); + EXPECT_EQ(false, testRet); + + MockUninstallBundle(BUNDLE_NAME_DEMO); +} + +/** + * @tc.number: GetLaunchWantForBundle_0400 + * @tc.name: test can not get the launch want of empty name + * @tc.desc: 1.system run normally + * 2.get launch want failed + */ +HWTEST_F(BmsBundleKitServiceTest, GetLaunchWantForBundle_0400, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_DEMO, MODULE_NAME_DEMO, ABILITY_NAME_DEMO); + Want want; + bool testRet = GetBundleDataMgr()->GetLaunchWantForBundle(EMPTY_STRING, want); + EXPECT_EQ(false, testRet); + + MockUninstallBundle(BUNDLE_NAME_DEMO); +} + +/** + * @tc.number: GetLaunchWantForBundle_0500 + * @tc.name: test can not get the launch want when no bundle installed + * @tc.desc: 1.system run normally + * 2.get launch want failed + */ +HWTEST_F(BmsBundleKitServiceTest, GetLaunchWantForBundle_0500, Function | SmallTest | Level1) +{ + Want want; + bool testRet = GetBundleDataMgr()->GetLaunchWantForBundle(BUNDLE_NAME_TEST, want); + EXPECT_EQ(false, testRet); +} + +/** + * @tc.number: GetBundleList_0100 + * @tc.name: test can get all installed bundle names + * @tc.desc: 1.system run normally + * 2.get installed bundle names successfully with correct names + */ +HWTEST_F(BmsBundleKitServiceTest, GetBundleList_0100, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + MockInstallBundle(BUNDLE_NAME_DEMO, MODULE_NAME_DEMO, ABILITY_NAME_DEMO); + + std::vector testResult; + bool testRet = GetBundleDataMgr()->GetBundleList(testResult); + EXPECT_TRUE(testRet); + CheckBundleList(BUNDLE_NAME_TEST, testResult); + CheckBundleList(BUNDLE_NAME_DEMO, testResult); + + MockUninstallBundle(BUNDLE_NAME_TEST); + MockUninstallBundle(BUNDLE_NAME_DEMO); +} + +/** + * @tc.number: GetBundleList_0200 + * @tc.name: test can get the no bundle names with no bundle installed + * @tc.desc: 1.system run normally + * 2.get installed bundle names failed + */ +HWTEST_F(BmsBundleKitServiceTest, GetBundleList_0200, Function | SmallTest | Level1) +{ + std::vector testResult; + bool testRet = GetBundleDataMgr()->GetBundleList(testResult); + EXPECT_FALSE(testRet); +} + +/** + * @tc.number: GetBundleNameForUid_0100 + * @tc.name: test can get the no bundle names with no bundle installed + * @tc.desc: 1.system run normally + * 2.get installed bundle names successfully + */ +HWTEST_F(BmsBundleKitServiceTest, GetBundleNameForUid_0100, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + std::string testResult; + bool testRet = GetBundleDataMgr()->GetBundleNameForUid(TEST_UID, testResult); + EXPECT_TRUE(testRet); + EXPECT_EQ(BUNDLE_NAME_TEST, testResult); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: GetBundleNameForUid_0200 + * @tc.name: test can not get not installed bundle name + * @tc.desc: 1.system run normally + * 2.get installed bundle name by uid failed + */ +HWTEST_F(BmsBundleKitServiceTest, GetBundleNameForUid_0200, Function | SmallTest | Level1) +{ + std::string testResult; + bool testRet = GetBundleDataMgr()->GetBundleNameForUid(TEST_UID, testResult); + EXPECT_FALSE(testRet); + EXPECT_NE(BUNDLE_NAME_TEST, testResult); +} + +/** + * @tc.number: GetBundleNameForUid_0300 + * @tc.name: test can not get installed bundle name by incorrect uid + * @tc.desc: 1.system run normally + * 2.get installed bundle name by uid failed + */ +HWTEST_F(BmsBundleKitServiceTest, GetBundleNameForUid_0300, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + std::string testResult; + bool testRet = GetBundleDataMgr()->GetBundleNameForUid(DEMO_UID, testResult); + EXPECT_FALSE(testRet); + EXPECT_NE(BUNDLE_NAME_TEST, testResult); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: GetBundleNameForUid_0400 + * @tc.name: test can not get installed bundle name by invalid uid + * @tc.desc: 1.system run normally + * 2.get installed bundle name by uid failed + */ +HWTEST_F(BmsBundleKitServiceTest, GetBundleNameForUid_0400, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + MockInstallBundle(BUNDLE_NAME_DEMO, MODULE_NAME_DEMO, ABILITY_NAME_DEMO); + + std::string testResult; + bool testRet = GetBundleDataMgr()->GetBundleNameForUid(INVALID_UID, testResult); + EXPECT_FALSE(testRet); + EXPECT_NE(BUNDLE_NAME_TEST, testResult); + EXPECT_NE(BUNDLE_NAME_DEMO, testResult); + + MockUninstallBundle(BUNDLE_NAME_TEST); + MockUninstallBundle(BUNDLE_NAME_DEMO); +} + +/** + * @tc.number: CheckIsSystemAppByUid_0100 + * @tc.name: test can check the installed bundle whether system app or not by uid + * @tc.desc: 1.system run normally + * 2.check the installed bundle successfully + */ +HWTEST_F(BmsBundleKitServiceTest, CheckIsSystemAppByUid_0100, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + MockInstallBundle(BUNDLE_NAME_DEMO, MODULE_NAME_DEMO, ABILITY_NAME_DEMO); + + bool testRet = GetBundleDataMgr()->CheckIsSystemAppByUid(TEST_UID); + EXPECT_TRUE(testRet); + + testRet = GetBundleDataMgr()->CheckIsSystemAppByUid(DEMO_UID); + EXPECT_FALSE(testRet); + + MockUninstallBundle(BUNDLE_NAME_TEST); + MockUninstallBundle(BUNDLE_NAME_DEMO); +} + +/** + * @tc.number: CheckIsSystemAppByUid_0200 + * @tc.name: test can check the installed bundle whether system app or not by uid + * @tc.desc: 1.system run normally + * 2.check the installed bundle successfully + */ +HWTEST_F(BmsBundleKitServiceTest, CheckIsSystemAppByUid_0200, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + bool testRet = GetBundleDataMgr()->CheckIsSystemAppByUid(INVALID_UID); + EXPECT_FALSE(testRet); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: DUMP_0100 + * @tc.name: Dump bundlelist, all bundle info, bundle info for bundleName + * @tc.desc: 1.system run normally + * 2.dump info with one mock installed bundles + */ +HWTEST_F(BmsBundleKitServiceTest, DUMP_0100, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + auto hostImpl = std::make_unique(); + std::string allInfoResult; + bool allInfoRet = hostImpl->DumpInfos(DumpFlag::DUMP_ALL_BUNDLE_INFO, EMPTY_STRING, allInfoResult); + EXPECT_TRUE(allInfoRet); + EXPECT_NE(std::string::npos, allInfoResult.find(BUNDLE_NAME_TEST)); + EXPECT_NE(std::string::npos, allInfoResult.find(MODULE_NAME_TEST)); + EXPECT_NE(std::string::npos, allInfoResult.find(ABILITY_NAME_TEST)); + + std::string infoResult; + bool infoRet = hostImpl->DumpInfos(DumpFlag::DUMP_BUNDLE_INFO, BUNDLE_NAME_TEST, infoResult); + EXPECT_TRUE(infoRet); + EXPECT_NE(std::string::npos, infoResult.find(BUNDLE_NAME_TEST)); + EXPECT_NE(std::string::npos, infoResult.find(MODULE_NAME_TEST)); + EXPECT_NE(std::string::npos, infoResult.find(ABILITY_NAME_TEST)); + + std::string bundleNames; + bool listRet = hostImpl->DumpInfos(DumpFlag::DUMP_BUNDLE_LIST, EMPTY_STRING, bundleNames); + EXPECT_TRUE(listRet); + EXPECT_NE(std::string::npos, bundleNames.find(BUNDLE_NAME_TEST)); + + MockUninstallBundle(BUNDLE_NAME_TEST); + MockInstallBundle(BUNDLE_NAME_DEMO, MODULE_NAME_TEST, ABILITY_NAME_DEMO); + + std::string names; + bool namesRet = hostImpl->DumpInfos(DumpFlag::DUMP_BUNDLE_LIST, EMPTY_STRING, names); + EXPECT_TRUE(namesRet); + EXPECT_NE(std::string::npos, names.find(BUNDLE_NAME_DEMO)); + + MockUninstallBundle(BUNDLE_NAME_DEMO); +} + +/** + * @tc.number: DUMP_0200 + * @tc.name: Dump empty bundle info for empty bundle name + * @tc.desc: 1.system run normally + * 2.dump with empty bundle name + */ +HWTEST_F(BmsBundleKitServiceTest, DUMP_0200, Function | SmallTest | Level0) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + auto hostImpl = std::make_unique(); + std::string emptyResult; + bool emptyRet = hostImpl->DumpInfos(DumpFlag::DUMP_BUNDLE_INFO, EMPTY_STRING, emptyResult); + EXPECT_FALSE(emptyRet); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: DUMP_0300 + * @tc.name: Dump bundlelist, all bundle info, bundle info for bundleName + * @tc.desc: 1.system run normally + * 2.dump info with 2 installed bundles + */ +HWTEST_F(BmsBundleKitServiceTest, DUMP_0300, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + MockInstallBundle(BUNDLE_NAME_DEMO, MODULE_NAME_DEMO, ABILITY_NAME_DEMO); + + auto hostImpl = std::make_unique(); + std::string bundleNames; + bool listRet = hostImpl->DumpInfos(DumpFlag::DUMP_BUNDLE_LIST, EMPTY_STRING, bundleNames); + EXPECT_TRUE(listRet); + EXPECT_NE(std::string::npos, bundleNames.find(BUNDLE_NAME_DEMO)); + EXPECT_NE(std::string::npos, bundleNames.find(BUNDLE_NAME_TEST)); + + std::string allBundleInfos; + bool allInfoRet = hostImpl->DumpInfos(DumpFlag::DUMP_ALL_BUNDLE_INFO, EMPTY_STRING, allBundleInfos); + EXPECT_TRUE(allInfoRet); + EXPECT_NE(std::string::npos, allBundleInfos.find(BUNDLE_NAME_TEST)); + EXPECT_NE(std::string::npos, allBundleInfos.find(BUNDLE_NAME_DEMO)); + EXPECT_NE(std::string::npos, allBundleInfos.find(MODULE_NAME_TEST)); + EXPECT_NE(std::string::npos, allBundleInfos.find(MODULE_NAME_DEMO)); + EXPECT_NE(std::string::npos, allBundleInfos.find(ABILITY_NAME_TEST)); + EXPECT_NE(std::string::npos, allBundleInfos.find(ABILITY_NAME_DEMO)); + + std::string bundleInfo; + bool infoRet = hostImpl->DumpInfos(DumpFlag::DUMP_BUNDLE_INFO, BUNDLE_NAME_TEST, bundleInfo); + EXPECT_TRUE(infoRet); + EXPECT_NE(std::string::npos, allBundleInfos.find(BUNDLE_NAME_TEST)); + EXPECT_NE(std::string::npos, allBundleInfos.find(BUNDLE_NAME_DEMO)); + + MockUninstallBundle(BUNDLE_NAME_TEST); + MockUninstallBundle(BUNDLE_NAME_DEMO); +} + +/** + * @tc.number: DUMP_0400 + * @tc.name: Dump with no bundle in system + * @tc.desc: 1.system run normally + * 2.dump empty message with the dump command + */ +HWTEST_F(BmsBundleKitServiceTest, DUMP_0400, Function | SmallTest | Level0) +{ + auto hostImpl = std::make_unique(); + std::string allBundleInfos; + bool infoRet = hostImpl->DumpInfos(DumpFlag::DUMP_ALL_BUNDLE_INFO, EMPTY_STRING, allBundleInfos); + EXPECT_FALSE(infoRet); + EXPECT_EQ(std::string::npos, allBundleInfos.find(BUNDLE_NAME_TEST)); + + std::string bundleInfo; + bool infoRet1 = hostImpl->DumpInfos(DumpFlag::DUMP_BUNDLE_INFO, BUNDLE_NAME_TEST, bundleInfo); + EXPECT_FALSE(infoRet1); + EXPECT_EQ(EMPTY_STRING, bundleInfo); + + std::string emptyInfo; + bool emptyRet = hostImpl->DumpInfos(DumpFlag::DUMP_BUNDLE_INFO, EMPTY_STRING, emptyInfo); + EXPECT_FALSE(emptyRet); + EXPECT_EQ(EMPTY_STRING, emptyInfo); +} + +/** + * @tc.number: QueryAbilityInfoByUri_0100 + * @tc.name: test can get the ability info by uri + * @tc.desc: 1.system run normally + * 2.get ability info successfully + */ +HWTEST_F(BmsBundleKitServiceTest, QueryAbilityInfoByUri_0100, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + AbilityInfo result; + bool testRet = GetBundleDataMgr()->QueryAbilityInfoByUri(URI, result); + EXPECT_EQ(true, testRet); + EXPECT_EQ(ABILITY_NAME_TEST, result.name); + EXPECT_NE(ABILITY_NAME_DEMO, result.name); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: QueryAbilityInfoByUri_0200 + * @tc.name: test can get the ability infos by uri + * @tc.desc: 1.system run normally + * 2.get ability info successfully + */ +HWTEST_F(BmsBundleKitServiceTest, QueryAbilityInfoByUri_0200, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + MockInstallBundle(BUNDLE_NAME_DEMO, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + AbilityInfo result; + bool testRet = GetBundleDataMgr()->QueryAbilityInfoByUri(URI, result); + EXPECT_EQ(true, testRet); + EXPECT_EQ(ABILITY_NAME_TEST, result.name); + EXPECT_NE(ABILITY_NAME_DEMO, result.name); + + MockUninstallBundle(BUNDLE_NAME_TEST); + MockUninstallBundle(BUNDLE_NAME_DEMO); +} + +/** + * @tc.number: QueryAbilityInfoByUri_0300 + * @tc.name: test can not get the ability info by uri which bundle doesn't exist + * @tc.desc: 1.system run normally + * 2.get ability info failed + */ + +HWTEST_F(BmsBundleKitServiceTest, QueryAbilityInfoByUri_0300, Function | SmallTest | Level1) +{ + AbilityInfo result; + bool testRet = GetBundleDataMgr()->QueryAbilityInfoByUri(URI, result); + EXPECT_EQ(false, testRet); +} + +/** + * @tc.number: QueryAbilityInfoByUri_0400 + * @tc.name: test can not get the ability info by empty uri + * @tc.desc: 1.system run normally + * 2.get ability info failed + */ +HWTEST_F(BmsBundleKitServiceTest, QueryAbilityInfoByUri_0400, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + AbilityInfo result; + bool testRet = GetBundleDataMgr()->QueryAbilityInfoByUri("", result); + EXPECT_EQ(false, testRet); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: QueryAbilityInfoByUri_0500 + * @tc.name: test can not get the ability info by error uri + * @tc.desc: 1.system run normally + * 2.get ability info failed + */ +HWTEST_F(BmsBundleKitServiceTest, QueryAbilityInfoByUri_0500, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + AbilityInfo result; + bool testRet = GetBundleDataMgr()->QueryAbilityInfoByUri(ERROR_URI, result); + EXPECT_EQ(false, testRet); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: QueryKeepAliveBundleInfos_0100 + * @tc.name: test can get the keep alive bundle infos + * @tc.desc: 1.system run normally + * 2.get all keep alive bundle infos successfully + */ +HWTEST_F(BmsBundleKitServiceTest, QueryKeepAliveBundleInfos_0100, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_DEMO, MODULE_NAME_DEMO, ABILITY_NAME_DEMO); + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + std::vector bundleInfos; + bool ret = GetBundleDataMgr()->QueryKeepAliveBundleInfos(bundleInfos); + EXPECT_EQ(true, ret); + CheckInstalledBundleInfos(ABILITY_SIZE_ONE, bundleInfos); + + MockUninstallBundle(BUNDLE_NAME_TEST); + MockUninstallBundle(BUNDLE_NAME_DEMO); +} + +/** + * @tc.number: QueryKeepAliveBundleInfos_0200 + * @tc.name: test can not get the keep alive bundle info which bundle doesn't exist + * @tc.desc: 1.system run normally + * 2.get bundle info failed + */ +HWTEST_F(BmsBundleKitServiceTest, QueryKeepAliveBundleInfos_0200, Function | SmallTest | Level1) +{ + std::vector bundleInfos; + bool ret = GetBundleDataMgr()->QueryKeepAliveBundleInfos(bundleInfos); + EXPECT_EQ(false, ret); +} + +/** + * @tc.number: GetBundleArchiveInfo_0100 + * @tc.name: test can get the bundle archive info + * @tc.desc: 1.system run normally + * 2.get the bundle archive info successfully + */ +HWTEST_F(BmsBundleKitServiceTest, GetBundleArchiveInfo_0100, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + auto hostImpl = std::make_unique(); + BundleInfo testResult; + bool listRet = hostImpl->GetBundleArchiveInfo(HAP_FILE_PATH, BundleFlag::GET_BUNDLE_DEFAULT, testResult); + EXPECT_TRUE(listRet); + CheckBundleInfo(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_SIZE_ZERO, testResult); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: GetBundleArchiveInfo_0200 + * @tc.name: test can not get the bundle archive info by empty hap file path + * @tc.desc: 1.system run normally + * 2.get the bundle archive info failed + */ +HWTEST_F(BmsBundleKitServiceTest, GetBundleArchiveInfo_0200, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + auto hostImpl = std::make_unique(); + BundleInfo testResult; + bool listRet = hostImpl->GetBundleArchiveInfo("", BundleFlag::GET_BUNDLE_DEFAULT, testResult); + EXPECT_FALSE(listRet); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: GetBundleArchiveInfo_0300 + * @tc.name: test can not get the bundle archive info by no exist hap file path + * @tc.desc: 1.system run normally + * 2.get the bundle archive info failed + */ +HWTEST_F(BmsBundleKitServiceTest, GetBundleArchiveInfo_0300, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + auto hostImpl = std::make_unique(); + BundleInfo testResult; + bool listRet = hostImpl->GetBundleArchiveInfo(ERROR_HAP_FILE_PATH, BundleFlag::GET_BUNDLE_DEFAULT, testResult); + EXPECT_FALSE(listRet); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: GetBundleArchiveInfo_0400 + * @tc.name: test can get the bundle archive info + * @tc.desc: 1.system run normally + * 2.get the bundle archive info successfully for GET_BUNDLE_WITH_ABILITIES + */ +HWTEST_F(BmsBundleKitServiceTest, GetBundleArchiveInfo_0400, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + auto hostImpl = std::make_unique(); + BundleInfo testResult; + bool listRet = hostImpl->GetBundleArchiveInfo(HAP_FILE_PATH, BundleFlag::GET_BUNDLE_WITH_ABILITIES, testResult); + EXPECT_TRUE(listRet); + CheckBundleInfo(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_SIZE_ONE, testResult); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: GetHapModuleInfo_0100 + * @tc.name: test can get the hap module info + * @tc.desc: 1.system run normally + * 2.get the hap module info successfully + */ +HWTEST_F(BmsBundleKitServiceTest, GetHapModuleInfo_0100, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + AbilityInfo abilityInfo; + abilityInfo.bundleName = BUNDLE_NAME_TEST; + abilityInfo.package = PACKAGE_NAME; + + HapModuleInfo hapModuleInfo; + bool ret = GetBundleDataMgr()->GetHapModuleInfo(abilityInfo, hapModuleInfo); + EXPECT_EQ(true, ret); + CheckModuleInfo(hapModuleInfo); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: GetHapModuleInfo_0200 + * @tc.name: test can not get the hap module info by no exist bundleName + * @tc.desc: 1.system run normally + * 2.get the hap module info failed + */ +HWTEST_F(BmsBundleKitServiceTest, GetHapModuleInfo_0200, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + AbilityInfo abilityInfo; + abilityInfo.bundleName = BUNDLE_NAME_DEMO; + abilityInfo.package = PACKAGE_NAME; + + HapModuleInfo hapModuleInfo; + bool ret = GetBundleDataMgr()->GetHapModuleInfo(abilityInfo, hapModuleInfo); + EXPECT_EQ(false, ret); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: GetHapModuleInfo_0300 + * @tc.name: test can not get the hap module info by no exist package + * @tc.desc: 1.system run normally + * 2.get the hap module info failed + */ +HWTEST_F(BmsBundleKitServiceTest, GetHapModuleInfo_0300, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + AbilityInfo abilityInfo; + abilityInfo.bundleName = BUNDLE_NAME_TEST; + abilityInfo.package = BUNDLE_NAME_DEMO; + + HapModuleInfo hapModuleInfo; + bool ret = GetBundleDataMgr()->GetHapModuleInfo(abilityInfo, hapModuleInfo); + EXPECT_EQ(false, ret); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: CheckApplicationEnabled_0100 + * @tc.name: test can check bundle status is enable by no setting + * @tc.desc: 1.system run normally + * 2.check the bundle status successfully + */ +HWTEST_F(BmsBundleKitServiceTest, CheckApplicationEnabled_0100, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + bool testRet = GetBundleDataMgr()->IsApplicationEnabled(BUNDLE_NAME_TEST); + EXPECT_TRUE(testRet); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: CheckApplicationEnabled_0200 + * @tc.name: test can check bundle status is enable by setting + * @tc.desc: 1.system run normally + * 2.check the bundle status successfully + */ +HWTEST_F(BmsBundleKitServiceTest, CheckApplicationEnabled_0200, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + bool testRet = GetBundleDataMgr()->SetApplicationEnabled(BUNDLE_NAME_TEST, true); + EXPECT_TRUE(testRet); + bool testRet1 = GetBundleDataMgr()->IsApplicationEnabled(BUNDLE_NAME_TEST); + EXPECT_TRUE(testRet1); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: CheckApplicationEnabled_0300 + * @tc.name: test can check bundle status is disable by setting + * @tc.desc: 1.system run normally + * 2.check the bundle status successfully + */ +HWTEST_F(BmsBundleKitServiceTest, CheckApplicationEnabled_0300, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + bool testRet = GetBundleDataMgr()->SetApplicationEnabled(BUNDLE_NAME_TEST, false); + EXPECT_TRUE(testRet); + bool testRet1 = GetBundleDataMgr()->IsApplicationEnabled(BUNDLE_NAME_TEST); + EXPECT_FALSE(testRet1); + + BundleInfo bundleInfo; + bool testRet2 = GetBundleDataMgr()->GetBundleInfo(BUNDLE_NAME_TEST, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); + EXPECT_FALSE(testRet2); + + ApplicationInfo applicationInfo; + bool testRet3 = GetBundleDataMgr()->GetApplicationInfo( + BUNDLE_NAME_TEST, ApplicationFlag::GET_BASIC_APPLICATION_INFO, DEFAULT_USER_ID, applicationInfo); + EXPECT_FALSE(testRet3); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: CheckApplicationEnabled_0400 + * @tc.name: test can check bundle status is disable by no install + * @tc.desc: 1.system run normally + * 2.check the bundle status failed + */ +HWTEST_F(BmsBundleKitServiceTest, CheckApplicationEnabled_0400, Function | SmallTest | Level1) +{ + bool testRet = GetBundleDataMgr()->IsApplicationEnabled(BUNDLE_NAME_TEST); + EXPECT_FALSE(testRet); +} + +/** + * @tc.number: CheckApplicationEnabled_0500 + * @tc.name: test can check bundle status is able by empty bundle name + * @tc.desc: 1.system run normally + * 2.check the bundle status successfully + */ +HWTEST_F(BmsBundleKitServiceTest, CheckApplicationEnabled_0500, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + bool testRet = GetBundleDataMgr()->SetApplicationEnabled("", true); + EXPECT_FALSE(testRet); + bool testRet1 = GetBundleDataMgr()->IsApplicationEnabled(BUNDLE_NAME_TEST); + EXPECT_TRUE(testRet1); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: CheckApplicationEnabled_0600 + * @tc.name: test can check bundle status is disable by empty bundle name + * @tc.desc: 1.system run normally + * 2.check the bundle status failed + */ +HWTEST_F(BmsBundleKitServiceTest, CheckApplicationEnabled_0600, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + bool testRet = GetBundleDataMgr()->SetApplicationEnabled(BUNDLE_NAME_TEST, true); + EXPECT_TRUE(testRet); + bool testRet1 = GetBundleDataMgr()->IsApplicationEnabled(""); + EXPECT_FALSE(testRet1); + + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: GetBundleInfosByMetaData_0100 + * @tc.name: test can get the bundle infos by metadata + * @tc.desc: 1.system run normally + * 2.get bundle infos successfully + */ +HWTEST_F(BmsBundleKitServiceTest, GetBundleInfosByMetaData_0100, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_DEMO, MODULE_NAME_DEMO, ABILITY_NAME_DEMO); + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + std::vector bundleInfos; + bool testRet = GetBundleDataMgr()->GetBundleInfosByMetaData(META_DATA, bundleInfos); + EXPECT_EQ(true, testRet); + CheckInstalledBundleInfos(ABILITY_SIZE_ONE, bundleInfos); + + MockUninstallBundle(BUNDLE_NAME_TEST); + MockUninstallBundle(BUNDLE_NAME_DEMO); +} + +/** + * @tc.number: GetBundleInfosByMetaData_0200 + * @tc.name: test can not get the bundle infos by empty metadata + * @tc.desc: 1.system run normally + * 2.get bundle infos failed + */ +HWTEST_F(BmsBundleKitServiceTest, GetBundleInfosByMetaData_0200, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_DEMO, MODULE_NAME_DEMO, ABILITY_NAME_DEMO); + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + std::vector bundleInfos; + bool testRet = GetBundleDataMgr()->GetBundleInfosByMetaData("", bundleInfos); + EXPECT_EQ(false, testRet); + + MockUninstallBundle(BUNDLE_NAME_TEST); + MockUninstallBundle(BUNDLE_NAME_DEMO); +} + +/** + * @tc.number: GetBundleInfosByMetaData_0300 + * @tc.name: test can not get the bundle infos by no exist metadata + * @tc.desc: 1.system run normally + * 2.get bundle infos failed + */ +HWTEST_F(BmsBundleKitServiceTest, GetBundleInfosByMetaData_0300, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_DEMO, MODULE_NAME_DEMO, ABILITY_NAME_DEMO); + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + + std::vector bundleInfos; + bool testRet = GetBundleDataMgr()->GetBundleInfosByMetaData(ERROR_META_DATA, bundleInfos); + EXPECT_EQ(false, testRet); + + MockUninstallBundle(BUNDLE_NAME_TEST); + MockUninstallBundle(BUNDLE_NAME_DEMO); +} + +/** + * @tc.number: CleanBundleDataFiles_0100 + * @tc.name: test can clean the bundle data files by bundle name + * @tc.desc: 1.system run normally + * 2.clean the bundle data files successfully + */ +HWTEST_F(BmsBundleKitServiceTest, CleanBundleDataFiles_0100, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + CreateFileDir(); + + auto hostImpl = std::make_unique(); + bool testRet = hostImpl->CleanBundleDataFiles(BUNDLE_NAME_TEST); + EXPECT_TRUE(testRet); + CheckFileNonExist(); + + CleanFileDir(); + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: CleanBundleDataFiles_0200 + * @tc.name: test can clean the bundle data files by empty bundle name + * @tc.desc: 1.system run normally + * 2.clean the bundle data files failed + */ +HWTEST_F(BmsBundleKitServiceTest, CleanBundleDataFiles_0200, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + CreateFileDir(); + + auto hostImpl = std::make_unique(); + bool testRet = hostImpl->CleanBundleDataFiles(""); + EXPECT_FALSE(testRet); + CheckFileExist(); + + CleanFileDir(); + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: CleanBundleDataFiles_0300 + * @tc.name: test can clean the bundle data files by no exist bundle name + * @tc.desc: 1.system run normally + * 2.clean the bundle data files failed + */ +HWTEST_F(BmsBundleKitServiceTest, CleanBundleDataFiles_0300, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + CreateFileDir(); + + auto hostImpl = std::make_unique(); + bool testRet = hostImpl->CleanBundleDataFiles(BUNDLE_NAME_DEMO); + EXPECT_FALSE(testRet); + CheckFileExist(); + + CleanFileDir(); + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: CleanCache_0100 + * @tc.name: test can clean the cache files by bundle name + * @tc.desc: 1.system run normally + * 2.clean the cache files successfully + */ +HWTEST_F(BmsBundleKitServiceTest, CleanCache_0100, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + CreateFileDir(); + + sptr cleanCache = new (std::nothrow) MockCleanCache(); + auto hostImpl = std::make_unique(); + bool result = hostImpl->CleanBundleCacheFiles(BUNDLE_NAME_TEST, cleanCache); + EXPECT_TRUE(result); + bool callbackResult = cleanCache->GetResultCode(); + CheckCacheNonExist(); + EXPECT_TRUE(callbackResult); + + CleanFileDir(); + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: CleanCache_0200 + * @tc.name: test can clean the cache files by empty bundle name + * @tc.desc: 1.system run normally + * 2.clean the cache files failed + */ +HWTEST_F(BmsBundleKitServiceTest, CleanCache_0200, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + CreateFileDir(); + + sptr cleanCache = new (std::nothrow) MockCleanCache(); + auto hostImpl = std::make_unique(); + bool result = hostImpl->CleanBundleCacheFiles("", cleanCache); + EXPECT_FALSE(result); + CheckCacheExist(); + + CleanFileDir(); + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: CleanCache_0300 + * @tc.name: test can clean the cache files by no exist bundle name + * @tc.desc: 1.system run normally + * 2.clean the cache files failed + */ +HWTEST_F(BmsBundleKitServiceTest, CleanCache_0300, Function | SmallTest | Level1) +{ + MockInstallBundle(BUNDLE_NAME_TEST, MODULE_NAME_TEST, ABILITY_NAME_TEST); + CreateFileDir(); + + sptr cleanCache = new (std::nothrow) MockCleanCache(); + auto hostImpl = std::make_unique(); + bool result = hostImpl->CleanBundleCacheFiles(BUNDLE_NAME_DEMO, cleanCache); + EXPECT_FALSE(result); + CheckCacheExist(); + + CleanFileDir(); + MockUninstallBundle(BUNDLE_NAME_TEST); +} + +/** + * @tc.number: RegisterBundleStatus_0100 + * @tc.name: test can register the bundle status by bundle name + * @tc.desc: 1.system run normally + * 2.bundle status callback successfully + */ +HWTEST_F(BmsBundleKitServiceTest, RegisterBundleStatus_0100, Function | SmallTest | Level1) +{ + sptr bundleStatusCallback = new (std::nothrow) MockBundleStatus(); + bundleStatusCallback->SetBundleName(HAP_FILE_PATH); + bool result = GetBundleDataMgr()->RegisterBundleStatusCallback(bundleStatusCallback); + EXPECT_TRUE(result); + + bool resultNotify = GetBundleDataMgr()->NotifyBundleStatus( + HAP_FILE_PATH, HAP_FILE_PATH, ABILITY_NAME_DEMO, ERR_OK, NotifyType::INSTALL); + EXPECT_TRUE(resultNotify); + + int32_t callbackResult = bundleStatusCallback->GetResultCode(); + EXPECT_EQ(callbackResult, ERR_OK); +} + +/** + * @tc.number: RegisterBundleStatus_0200 + * @tc.name: test can register the bundle status by bundle name + * @tc.desc: 1.system run normally + * 2.bundle status callback failed by empty bundle name + */ +HWTEST_F(BmsBundleKitServiceTest, RegisterBundleStatus_0200, Function | SmallTest | Level1) +{ + sptr bundleStatusCallback = new (std::nothrow) MockBundleStatus(); + bundleStatusCallback->SetBundleName(HAP_FILE_PATH); + bool result = GetBundleDataMgr()->RegisterBundleStatusCallback(bundleStatusCallback); + EXPECT_TRUE(result); + + bool resultNotify = + GetBundleDataMgr()->NotifyBundleStatus("", HAP_FILE_PATH, ABILITY_NAME_DEMO, ERR_OK, NotifyType::INSTALL); + EXPECT_TRUE(resultNotify); + + int32_t callbackResult = bundleStatusCallback->GetResultCode(); + EXPECT_EQ(callbackResult, ERR_TIMED_OUT); +} + +/** + * @tc.number: RegisterBundleStatus_0300 + * @tc.name: test can register the bundle status by bundle name + * @tc.desc: 1.system run normally + * 2.bundle status callback failed by no exist bundle name + */ +HWTEST_F(BmsBundleKitServiceTest, RegisterBundleStatus_0300, Function | SmallTest | Level1) +{ + sptr bundleStatusCallback = new (std::nothrow) MockBundleStatus(); + bundleStatusCallback->SetBundleName(HAP_FILE_PATH); + bool result = GetBundleDataMgr()->RegisterBundleStatusCallback(bundleStatusCallback); + EXPECT_TRUE(result); + + bool resultNotify = GetBundleDataMgr()->NotifyBundleStatus( + ERROR_HAP_FILE_PATH, HAP_FILE_PATH, ABILITY_NAME_DEMO, ERR_OK, NotifyType::INSTALL); + EXPECT_TRUE(resultNotify); + + int32_t callbackResult = bundleStatusCallback->GetResultCode(); + EXPECT_EQ(callbackResult, ERR_TIMED_OUT); +} + +/** + * @tc.number: ClearBundleStatus_0100 + * @tc.name: test can clear the bundle status by bundle name + * @tc.desc: 1.system run normally + * 2.bundle status callback failed by cleared bundle name + */ +HWTEST_F(BmsBundleKitServiceTest, ClearBundleStatus_0100, Function | SmallTest | Level1) +{ + sptr bundleStatusCallback1 = new (std::nothrow) MockBundleStatus(); + bundleStatusCallback1->SetBundleName(HAP_FILE_PATH1); + bool result1 = GetBundleDataMgr()->RegisterBundleStatusCallback(bundleStatusCallback1); + EXPECT_TRUE(result1); + + bool result2 = GetBundleDataMgr()->ClearBundleStatusCallback(bundleStatusCallback1); + EXPECT_TRUE(result2); + + sptr bundleStatusCallback = new (std::nothrow) MockBundleStatus(); + bundleStatusCallback->SetBundleName(HAP_FILE_PATH); + bool result = GetBundleDataMgr()->RegisterBundleStatusCallback(bundleStatusCallback); + EXPECT_TRUE(result); + + bool resultNotify = GetBundleDataMgr()->NotifyBundleStatus( + HAP_FILE_PATH, HAP_FILE_PATH, ABILITY_NAME_DEMO, ERR_OK, NotifyType::INSTALL); + 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); + EXPECT_TRUE(resultNotify1); + + int32_t callbackResult1 = bundleStatusCallback1->GetResultCode(); + EXPECT_EQ(callbackResult1, ERR_TIMED_OUT); +} + +/** + * @tc.number: UnregisterBundleStatus_0100 + * @tc.name: test can unregister the bundle status by bundle name + * @tc.desc: 1.system run normally + * 2.bundle status callback failed by unregister bundle name + */ +HWTEST_F(BmsBundleKitServiceTest, UnregisterBundleStatus_0100, Function | SmallTest | Level1) +{ + sptr bundleStatusCallback = new (std::nothrow) MockBundleStatus(); + bundleStatusCallback->SetBundleName(HAP_FILE_PATH); + bool result = GetBundleDataMgr()->RegisterBundleStatusCallback(bundleStatusCallback); + EXPECT_TRUE(result); + + sptr bundleStatusCallback1 = new (std::nothrow) MockBundleStatus(); + bundleStatusCallback1->SetBundleName(HAP_FILE_PATH1); + bool result1 = GetBundleDataMgr()->RegisterBundleStatusCallback(bundleStatusCallback1); + EXPECT_TRUE(result1); + + bool result2 = GetBundleDataMgr()->UnregisterBundleStatusCallback(); + EXPECT_TRUE(result2); + + bool resultNotify = GetBundleDataMgr()->NotifyBundleStatus( + HAP_FILE_PATH, HAP_FILE_PATH, ABILITY_NAME_DEMO, ERR_OK, NotifyType::INSTALL); + 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); + EXPECT_TRUE(resultNotify1); + + int32_t callbackResult1 = bundleStatusCallback1->GetResultCode(); + EXPECT_EQ(callbackResult1, ERR_TIMED_OUT); +} \ No newline at end of file diff --git a/services/bundlemgr/test/unittest/bms_bundle_parser_test/BUILD.gn b/services/bundlemgr/test/unittest/bms_bundle_parser_test/BUILD.gn new file mode 100644 index 000000000..4d9a13e14 --- /dev/null +++ b/services/bundlemgr/test/unittest/bms_bundle_parser_test/BUILD.gn @@ -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. + +import("//build/test.gni") +import("//foundation/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/bundlemgrservice" + +config("bundlemgr_parse_test_config") { + include_dirs = [ + "${services_path}/bundlemgr/include", + "${services_path}/bundlemgr/test/mock/include", + ] +} + +ohos_unittest("BmsBundleParserTest") { + module_out_path = module_output_path + + sources = [ + "${services_path}/bundlemgr/src/inner_bundle_info.cpp", + "bms_bundle_parser_test.cpp", + ] + + configs = [ + "${services_path}/bundlemgr/test:bundlemgr_test_config", + ":bundlemgr_parse_test_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${common_path}:libappexecfwk_common", + "${services_path}/bundlemgr:bundle_parser", + "${services_path}/bundlemgr:parser_common", + "//third_party/googletest:gtest_main", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + deps = [ ":BmsBundleParserTest" ] +} 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 new file mode 100755 index 000000000..28ff16c70 --- /dev/null +++ b/services/bundlemgr/test/unittest/bms_bundle_parser_test/bms_bundle_parser_test.cpp @@ -0,0 +1,913 @@ +/* + * 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 "common_profile.h" +#include "json_constants.h" +#include "bundle_extractor.h" +#include "bundle_constants.h" +#include "bundle_parser.h" +#include "bundle_profile.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; +using namespace OHOS::AppExecFwk::Constants; +using namespace OHOS::AppExecFwk::ProfileReader; + +namespace { + +const std::string RESOURCE_ROOT_PATH = "/data/test/resource/bms/parse_bundle/"; +const std::string NEW_APP = "new"; +const std::string BREAK_ZIP = "break_zip"; +const std::string NO_PROFILE = "no_profile"; +const std::string EMPTY_CONFIG = "empty_config"; +const std::string NOTHING_CONFIG = "nothing_config"; +const std::string FORMAT_ERROR_PROFILE = "format_error_profile"; +const std::string FORMAT_MISSING_PROFILE = "format_missing_profile"; +const std::string UNKOWN_PATH = "unknown_path"; +const nlohmann::json CONFIG_JSON = R"( + { + "app": { + "bundleName": "com.example.hiworld.himusic", + "vendor": "example", + "version": { + "code": 2, + "name": "2.0" + }, + "apiVersion": { + "compatible": 3, + "target": 3, + "releaseType": "Beta1" + } + }, + "deviceConfig": { + "default": { + } + }, + "module": { + "package": "com.example.hiworld.himusic.entry", + "name": ".MainApplication", + "supportedModes": [ + "drive" + ], + "distro": { + "moduleType": "entry", + "deliveryWithInstall": true, + "moduleName": "hap-car" + }, + "deviceType": [ + "car" + ], + "abilities": [ + { + "name": ".MainAbility", + "description": "himusic main ability", + "icon": "$media:ic_launcher", + "label": "HiMusic", + "launchType": "standard", + "orientation": "unspecified", + "visible": true, + "skills": [ + { + "actions": [ + "action.system.home" + ], + "entities": [ + "entity.system.home" + ] + } + ], + "type": "page", + "formEnabled": false + }, + { + "name": ".PlayService", + "description": "himusic play ability", + "icon": "$media:ic_launcher", + "label": "HiMusic", + "launchType": "standard", + "orientation": "unspecified", + "visible": false, + "skills": [ + { + "actions": [ + "action.play.music", + "action.stop.music" + ], + "entities": [ + "entity.audio" + ] + } + ], + "type": "service", + "backgroundModes": [ + "audioPlayback" + ] + }, + { + "name": ".UserADataAbility", + "type": "data", + "uri": "dataability://com.example.hiworld.himusic.UserADataAbility", + "visible": true + } + ], + "reqPermissions": [ + { + "name": "ohos.permission.DISTRIBUTED_DATASYNC", + "reason": "", + "usedScene": { + "ability": [ + "com.example.hiworld.himusic.entry.MainAbility", + "com.example.hiworld.himusic.entry.PlayService" + ], + "when": "inuse" + } + } + ] + } + } +)"_json; + +} // namespace + +class BmsBundleParserTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + +protected: + void GetProfileTypeErrorProps(nlohmann::json &typeErrorProps) const; + void CheckNoPropProfileParseApp(const std::string &propKey, const ErrCode expectCode) const; + void CheckNoPropProfileParseDeviceConfig(const std::string &propKey, const ErrCode expectCode) const; + void CheckNoPropProfileParseModule(const std::string &propKey, const ErrCode expectCode) const; + void CheckProfilePermission(const nlohmann::json &checkedProfileJson) const; + +protected: + std::ostringstream pathStream_; +}; + +void BmsBundleParserTest::SetUpTestCase() +{} + +void BmsBundleParserTest::TearDownTestCase() +{} + +void BmsBundleParserTest::SetUp() +{} + +void BmsBundleParserTest::TearDown() +{ + pathStream_.clear(); +} + +void BmsBundleParserTest::GetProfileTypeErrorProps(nlohmann::json &typeErrorProps) const +{ + typeErrorProps[PROFILE_KEY_NAME] = JsonConstants::NOT_STRING_TYPE; + typeErrorProps[PROFILE_KEY_LABEL] = JsonConstants::NOT_STRING_TYPE; + typeErrorProps[PROFILE_KEY_DESCRIPTION] = JsonConstants::NOT_STRING_TYPE; + typeErrorProps[PROFILE_KEY_TYPE] = JsonConstants::NOT_STRING_TYPE; + // bundle profile tag + typeErrorProps[BUNDLE_PROFILE_KEY_APP] = JsonConstants::NOT_OBJECT_TYPE; + typeErrorProps[BUNDLE_PROFILE_KEY_DEVICE_CONFIG] = JsonConstants::NOT_STRING_TYPE; + typeErrorProps[BUNDLE_PROFILE_KEY_MODULE] = JsonConstants::NOT_OBJECT_TYPE; + // sub BUNDLE_PROFILE_KEY_APP + typeErrorProps[BUNDLE_APP_PROFILE_KEY_BUNDLE_NAME] = JsonConstants::NOT_STRING_TYPE; + typeErrorProps[BUNDLE_APP_PROFILE_KEY_VENDOR] = JsonConstants::NOT_STRING_TYPE; + typeErrorProps[BUNDLE_APP_PROFILE_KEY_VERSION] = JsonConstants::NOT_OBJECT_TYPE; + typeErrorProps[BUNDLE_APP_PROFILE_KEY_API_VERSION] = JsonConstants::NOT_OBJECT_TYPE; + // BUNDLE_APP_PROFILE_KEY_VERSION + typeErrorProps[BUNDLE_APP_PROFILE_KEY_CODE] = JsonConstants::NOT_NUMBER_TYPE; + // BUNDLE_APP_PROFILE_KEY_API_VERSION + typeErrorProps[BUNDLE_APP_PROFILE_KEY_COMPATIBLE] = JsonConstants::NOT_NUMBER_TYPE; + typeErrorProps[BUNDLE_APP_PROFILE_KEY_TARGET] = JsonConstants::NOT_NUMBER_TYPE; + typeErrorProps[BUNDLE_APP_PROFILE_KEY_RELEASE_TYPE] = JsonConstants::NOT_STRING_TYPE; + // sub BUNDLE_PROFILE_KEY_DEVICE_CONFIG + typeErrorProps[BUNDLE_DEVICE_CONFIG_PROFILE_KEY_DEFAULT] = JsonConstants::NOT_OBJECT_TYPE; + typeErrorProps[BUNDLE_DEVICE_CONFIG_PROFILE_KEY_PHONE] = JsonConstants::NOT_OBJECT_TYPE; + typeErrorProps[BUNDLE_DEVICE_CONFIG_PROFILE_KEY_TABLET] = JsonConstants::NOT_OBJECT_TYPE; + typeErrorProps[BUNDLE_DEVICE_CONFIG_PROFILE_KEY_TV] = JsonConstants::NOT_OBJECT_TYPE; + typeErrorProps[BUNDLE_DEVICE_CONFIG_PROFILE_KEY_CAR] = JsonConstants::NOT_OBJECT_TYPE; + typeErrorProps[BUNDLE_DEVICE_CONFIG_PROFILE_KEY_WEARABLE] = JsonConstants::NOT_OBJECT_TYPE; + typeErrorProps[BUNDLE_DEVICE_CONFIG_PROFILE_KEY_LITE_WEARABLE] = JsonConstants::NOT_OBJECT_TYPE; + typeErrorProps[BUNDLE_DEVICE_CONFIG_PROFILE_KEY_SMART_VISION] = JsonConstants::NOT_OBJECT_TYPE; + // BUNDLE_DEVICE_CONFIG_PROFILE_KEY_DEFAULT + typeErrorProps[BUNDLE_DEVICE_CONFIG_PROFILE_KEY_PROCESS] = JsonConstants::NOT_STRING_TYPE; + typeErrorProps[BUNDLE_DEVICE_CONFIG_PROFILE_KEY_DIRECT_LAUNCH] = JsonConstants::NOT_BOOL_TYPE; + typeErrorProps[BUNDLE_DEVICE_CONFIG_PROFILE_KEY_SUPPORT_BACKUP] = JsonConstants::NOT_BOOL_TYPE; + typeErrorProps[BUNDLE_DEVICE_CONFIG_PROFILE_KEY_COMPRESS_NATIVE_LIBS] = JsonConstants::NOT_BOOL_TYPE; + typeErrorProps[BUNDLE_DEVICE_CONFIG_PROFILE_KEY_NETWORK] = JsonConstants::NOT_OBJECT_TYPE; + // BUNDLE_DEVICE_CONFIG_PROFILE_KEY_NETWORK + typeErrorProps[BUNDLE_DEVICE_CONFIG_PROFILE_KEY_USES_CLEAR_TEXT] = JsonConstants::NOT_BOOL_TYPE; + typeErrorProps[BUNDLE_DEVICE_CONFIG_PROFILE_KEY_SECURITY_CONFIG] = JsonConstants::NOT_OBJECT_TYPE; + // BUNDLE_DEVICE_CONFIG_PROFILE_KEY_SECURITY_CONFIG + typeErrorProps[BUNDLE_DEVICE_CONFIG_PROFILE_KEY_DOMAIN_SETTINGS] = JsonConstants::NOT_OBJECT_TYPE; + // BUNDLE_DEVICE_CONFIG_PROFILE_KEY_DOMAIN_SETTINGS + typeErrorProps[BUNDLE_DEVICE_CONFIG_PROFILE_KEY_CLEAR_TEXT_PERMITTED] = JsonConstants::NOT_BOOL_TYPE; + typeErrorProps[BUNDLE_DEVICE_CONFIG_PROFILE_KEY_DOMAINS] = JsonConstants::NOT_ARRAY_TYPE; + // BUNDLE_DEVICE_CONFIG_PROFILE_KEY_DOMAINS + typeErrorProps[BUNDLE_DEVICE_CONFIG_PROFILE_KEY_SUB_DOMAINS] = JsonConstants::NOT_ARRAY_TYPE; + // sub BUNDLE_PROFILE_KEY_MODULE + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_PACKAGE] = JsonConstants::NOT_STRING_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_SUPPORTED_MODES] = JsonConstants::NOT_ARRAY_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_DEVICE_TYPE] = JsonConstants::NOT_ARRAY_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_DISTRO] = JsonConstants::NOT_OBJECT_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_ABILITIES] = JsonConstants::NOT_ARRAY_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_JS] = JsonConstants::NOT_OBJECT_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_SHORTCUTS] = JsonConstants::NOT_ARRAY_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS] = JsonConstants::NOT_ARRAY_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_REQ_PERMISSIONS] = JsonConstants::NOT_ARRAY_TYPE; + // BUNDLE_MODULE_PROFILE_KEY_DISTRO + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_DELIVERY_WITH_INSTALL] = JsonConstants::NOT_BOOL_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_MODULE_NAME] = JsonConstants::NOT_STRING_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_MODULE_TYPE] = JsonConstants::NOT_STRING_TYPE; + // BUNDLE_MODULE_PROFILE_KEY_ABILITIES + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_ICON] = JsonConstants::NOT_STRING_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_URI] = JsonConstants::NOT_STRING_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_LAUNCH_TYPE] = JsonConstants::NOT_STRING_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_VISIBLE] = JsonConstants::NOT_BOOL_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_PERMISSIONS] = JsonConstants::NOT_ARRAY_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_SKILLS] = JsonConstants::NOT_ARRAY_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_DEVICE_CAP_ABILITY] = JsonConstants::NOT_ARRAY_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_ORIENTATION] = JsonConstants::NOT_STRING_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_BACKGROUND_MODES] = JsonConstants::NOT_ARRAY_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_READ_PERMISSION] = JsonConstants::NOT_STRING_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_WRITE_PERMISSION] = JsonConstants::NOT_STRING_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_DIRECT_LAUNCH] = JsonConstants::NOT_BOOL_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_CONFIG_CHANGES] = JsonConstants::NOT_ARRAY_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_MISSION] = JsonConstants::NOT_STRING_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_TARGET_ABILITY] = JsonConstants::NOT_STRING_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_MULTIUSER_SHARED] = JsonConstants::NOT_BOOL_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_SUPPORT_PIP_MODE] = JsonConstants::NOT_BOOL_TYPE; + // BUNDLE_MODULE_PROFILE_KEY_SKILLS + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_ACTIONS] = JsonConstants::NOT_ARRAY_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_ENTITIES] = JsonConstants::NOT_ARRAY_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_URIS] = JsonConstants::NOT_ARRAY_TYPE; + // BUNDLE_MODULE_PROFILE_KEY_URIS + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_SCHEME] = JsonConstants::NOT_STRING_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_HOST] = JsonConstants::NOT_STRING_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_PORT] = JsonConstants::NOT_STRING_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_PATH] = JsonConstants::NOT_STRING_TYPE; + // BUNDLE_MODULE_PROFILE_KEY_JS + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_PAGES] = JsonConstants::NOT_ARRAY_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_WINDOW] = JsonConstants::NOT_OBJECT_TYPE; + // BUNDLE_MODULE_PROFILE_KEY_WINDOW + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_DESIGN_WIDTH] = JsonConstants::NOT_NUMBER_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_AUTO_DESIGN_WIDTH] = JsonConstants::NOT_BOOL_TYPE; + // BUNDLE_MODULE_PROFILE_KEY_SHORTCUTS + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_SHORTCUT_ID] = JsonConstants::NOT_STRING_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_SHORTCUT_INTENTS] = JsonConstants::NOT_STRING_TYPE; + // BUNDLE_MODULE_PROFILE_KEY_SHORTCUT_INTENTS + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_TARGET_CLASS] = JsonConstants::NOT_STRING_TYPE; + typeErrorProps[BUNDLE_MODULE_PROFILE_KEY_TARGET_BUNDLE] = JsonConstants::NOT_STRING_TYPE; +} + +void BmsBundleParserTest::CheckNoPropProfileParseApp(const std::string &propKey, const ErrCode expectCode) const +{ + BundleProfile bundleProfile; + InnerBundleInfo innerBundleInfo; + std::ostringstream profileFileBuffer; + + nlohmann::json errorProfileJson = CONFIG_JSON; + errorProfileJson[BUNDLE_PROFILE_KEY_APP].erase(propKey); + profileFileBuffer << errorProfileJson.dump(); + + ErrCode result = bundleProfile.TransformTo(profileFileBuffer, innerBundleInfo); + EXPECT_EQ(result, expectCode); +} + +void BmsBundleParserTest::CheckNoPropProfileParseDeviceConfig( + const std::string &propKey, const ErrCode expectCode) const +{ + BundleProfile bundleProfile; + InnerBundleInfo innerBundleInfo; + std::ostringstream profileFileBuffer; + + nlohmann::json errorProfileJson = CONFIG_JSON; + errorProfileJson[BUNDLE_PROFILE_KEY_DEVICE_CONFIG].erase(propKey); + profileFileBuffer << errorProfileJson.dump(); + + ErrCode result = bundleProfile.TransformTo(profileFileBuffer, innerBundleInfo); + EXPECT_EQ(result, expectCode); +} + +void BmsBundleParserTest::CheckNoPropProfileParseModule(const std::string &propKey, const ErrCode expectCode) const +{ + BundleProfile bundleProfile; + InnerBundleInfo innerBundleInfo; + std::ostringstream profileFileBuffer; + + nlohmann::json errorProfileJson = CONFIG_JSON; + errorProfileJson[BUNDLE_PROFILE_KEY_MODULE].erase(propKey); + profileFileBuffer << errorProfileJson.dump(); + + ErrCode result = bundleProfile.TransformTo(profileFileBuffer, innerBundleInfo); + EXPECT_EQ(result, expectCode); +} + +void BmsBundleParserTest::CheckProfilePermission(const nlohmann::json &checkedProfileJson) const +{ + BundleProfile bundleProfile; + InnerBundleInfo innerBundleInfo; + std::ostringstream profileFileBuffer; + + profileFileBuffer << checkedProfileJson.dump(); + + ErrCode result = bundleProfile.TransformTo(profileFileBuffer, innerBundleInfo); + EXPECT_EQ(result, 0) << profileFileBuffer.str(); +} + +/** + * @tc.number: BmsBundleParser + * Function: BundleParser + * @tc.name: parse bundle package by config.json + * @tc.desc: 1. system running normally + * 2. test bundle package can be parse to InnerBundleInfo successfully + */ +HWTEST_F(BmsBundleParserTest, TestParse_0100, Function | SmallTest | Level0) +{ + BundleParser bundleParser; + InnerBundleInfo innerBundleInfo; + pathStream_ << RESOURCE_ROOT_PATH << NEW_APP << INSTALL_FILE_SUFFIX; + ErrCode result = bundleParser.Parse(pathStream_.str(), innerBundleInfo); + BundleInfo bundleInfo = innerBundleInfo.GetBaseBundleInfo(); + EXPECT_EQ(result, ERR_OK); + EXPECT_EQ(bundleInfo.name, "com.example.hiworld.himusic"); + EXPECT_EQ(bundleInfo.label, "HiMusic"); + EXPECT_EQ(bundleInfo.description, ""); + EXPECT_EQ(bundleInfo.vendor, "example"); + uint32_t versionCode = 2; + EXPECT_EQ(bundleInfo.versionCode, versionCode); + EXPECT_EQ(bundleInfo.versionName, "2.0"); + EXPECT_EQ(bundleInfo.minSdkVersion, 0); + EXPECT_EQ(bundleInfo.maxSdkVersion, 0); + EXPECT_EQ(bundleInfo.mainEntry, ""); +} + +/** + * @tc.number: TestParse_0200 + * @tc.name: parse bundle package by config.json + * @tc.desc: 1. system running normally + * 2. test parse bundle failed when file is not exist by the input pathName + */ +HWTEST_F(BmsBundleParserTest, TestParse_0200, Function | SmallTest | Level0) +{ + BundleParser bundleParser; + InnerBundleInfo innerBundleInfo; + pathStream_ << RESOURCE_ROOT_PATH << UNKOWN_PATH << INSTALL_FILE_SUFFIX; + ErrCode result = bundleParser.Parse(pathStream_.str(), innerBundleInfo); + EXPECT_EQ(result, ERR_APPEXECFWK_PARSE_UNEXPECTED); +} + +/** + * @tc.number: TestParse_0300 + * @tc.name: parse bundle package by config.json + * @tc.desc: 1. system running normally + * 2. test parse bundle failed when the file is a break zip + */ +HWTEST_F(BmsBundleParserTest, TestParse_0300, Function | SmallTest | Level0) +{ + BundleParser bundleParser; + InnerBundleInfo innerBundleInfo; + pathStream_ << RESOURCE_ROOT_PATH << BREAK_ZIP << INSTALL_FILE_SUFFIX; + ErrCode result = bundleParser.Parse(pathStream_.str(), innerBundleInfo); + EXPECT_EQ(result, ERR_APPEXECFWK_PARSE_NO_PROFILE); +} + +/** + * @tc.number: TestParse_0400 + * @tc.name: parse bundle package by config.json + * @tc.desc: 1. test parse bundle failed when the config.json is not exist in the zip + */ +HWTEST_F(BmsBundleParserTest, TestParse_0400, Function | SmallTest | Level0) +{ + BundleParser bundleParser; + InnerBundleInfo innerBundleInfo; + pathStream_ << RESOURCE_ROOT_PATH << NO_PROFILE << INSTALL_FILE_SUFFIX; + ErrCode result = bundleParser.Parse(pathStream_.str(), innerBundleInfo); + EXPECT_EQ(result, ERR_APPEXECFWK_PARSE_NO_PROFILE); +} + +/** + * @tc.number: TestParse_0500 + * @tc.name: parse bundle package by config.json + * @tc.desc: 1. system running normally + * 2. test parse bundle failed when the config.json has format error + */ +HWTEST_F(BmsBundleParserTest, TestParse_0500, Function | SmallTest | Level0) +{ + BundleParser bundleParser; + InnerBundleInfo innerBundleInfo; + pathStream_ << RESOURCE_ROOT_PATH << FORMAT_ERROR_PROFILE << INSTALL_FILE_SUFFIX; + ErrCode result = bundleParser.Parse(pathStream_.str(), innerBundleInfo); + EXPECT_EQ(result, ERR_APPEXECFWK_PARSE_BAD_PROFILE); +} + +/** + * @tc.number: TestParse_0600 + * @tc.name: parse bundle package by config.json + * @tc.desc: 1. system running normally + * 2. test parse bundle failed when prop(APP_notMustPropKeys) is not exist in the config.json + */ +HWTEST_F(BmsBundleParserTest, TestParse_0600, Function | SmallTest | Level0) +{ + std::vector notMustPropKeys = { + PROFILE_KEY_DESCRIPTION, + PROFILE_KEY_LABEL, + // sub BUNDLE_APP_PROFILE_KEY_API_VERSION + BUNDLE_APP_PROFILE_KEY_VENDOR, + BUNDLE_APP_PROFILE_KEY_TARGET, + BUNDLE_APP_PROFILE_KEY_RELEASE_TYPE, + }; + + for (const auto &propKey : notMustPropKeys) { + APP_LOGD("test not must prop %{public}s not exist", propKey.c_str()); + CheckNoPropProfileParseApp(propKey, ERR_OK); + } +} + +/** + * @tc.number: TestParse_0700 + * @tc.name: parse bundle package by config.json + * @tc.desc: 1. system running normally + * 2. test parse bundle failed when prop(deviceConfig_notMustPropKeys) is not exist in the config.json + */ +HWTEST_F(BmsBundleParserTest, TestParse_0700, Function | SmallTest | Level0) +{ + std::vector notMustPropKeys = { + PROFILE_KEY_DESCRIPTION, + PROFILE_KEY_LABEL, + // sub BUNDLE_PROFILE_KEY_DEVICE_CONFIG + BUNDLE_DEVICE_CONFIG_PROFILE_KEY_PHONE, + BUNDLE_DEVICE_CONFIG_PROFILE_KEY_TABLET, + BUNDLE_DEVICE_CONFIG_PROFILE_KEY_TV, + BUNDLE_DEVICE_CONFIG_PROFILE_KEY_CAR, + BUNDLE_DEVICE_CONFIG_PROFILE_KEY_WEARABLE, + BUNDLE_DEVICE_CONFIG_PROFILE_KEY_LITE_WEARABLE, + BUNDLE_DEVICE_CONFIG_PROFILE_KEY_SMART_VISION, + // sub BUNDLE_DEVICE_CONFIG_PROFILE_KEY_DEFAULT + BUNDLE_DEVICE_CONFIG_PROFILE_KEY_PROCESS, + BUNDLE_DEVICE_CONFIG_PROFILE_KEY_DIRECT_LAUNCH, + BUNDLE_DEVICE_CONFIG_PROFILE_KEY_SUPPORT_BACKUP, + BUNDLE_DEVICE_CONFIG_PROFILE_KEY_COMPRESS_NATIVE_LIBS, + BUNDLE_DEVICE_CONFIG_PROFILE_KEY_NETWORK, + // sub BUNDLE_DEVICE_CONFIG_PROFILE_KEY_NETWORK + BUNDLE_DEVICE_CONFIG_PROFILE_KEY_USES_CLEAR_TEXT, + BUNDLE_DEVICE_CONFIG_PROFILE_KEY_SECURITY_CONFIG, + // sub BUNDLE_DEVICE_CONFIG_PROFILE_KEY_SECURITY_CONFIG + BUNDLE_DEVICE_CONFIG_PROFILE_KEY_DOMAIN_SETTINGS, + }; + + for (const auto &propKey : notMustPropKeys) { + APP_LOGD("test not must prop %{public}s not exist", propKey.c_str()); + CheckNoPropProfileParseDeviceConfig(propKey, ERR_OK); + } +} + +/** + * @tc.number: TestParse_0800 + * @tc.name: parse bundle package by config.json + * @tc.desc: 1. system running normally + * 2. test parse bundle failed when prop(module_notMustPropKeys) is not exist in the config.json + */ +HWTEST_F(BmsBundleParserTest, TestParse_0800, Function | SmallTest | Level0) +{ + std::vector notMustPropKeys = { + PROFILE_KEY_DESCRIPTION, + PROFILE_KEY_LABEL, + // sub BUNDLE_PROFILE_KEY_MODULE + BUNDLE_MODULE_PROFILE_KEY_SUPPORTED_MODES, + BUNDLE_MODULE_PROFILE_KEY_ABILITIES, + BUNDLE_MODULE_PROFILE_KEY_JS, + BUNDLE_MODULE_PROFILE_KEY_SHORTCUTS, + BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS, + BUNDLE_MODULE_PROFILE_KEY_REQ_PERMISSIONS, + // sub BUNDLE_MODULE_PROFILE_KEY_ABILITIES + BUNDLE_MODULE_PROFILE_KEY_PROCESS, + BUNDLE_MODULE_PROFILE_KEY_ICON, + BUNDLE_MODULE_PROFILE_KEY_URI, + BUNDLE_MODULE_PROFILE_KEY_LAUNCH_TYPE, + BUNDLE_MODULE_PROFILE_KEY_VISIBLE, + BUNDLE_MODULE_PROFILE_KEY_PERMISSIONS, + BUNDLE_MODULE_PROFILE_KEY_SKILLS, + BUNDLE_MODULE_PROFILE_KEY_DEVICE_CAP_ABILITY, + BUNDLE_MODULE_PROFILE_KEY_ORIENTATION, + BUNDLE_MODULE_PROFILE_KEY_BACKGROUND_MODES, + BUNDLE_MODULE_PROFILE_KEY_READ_PERMISSION, + BUNDLE_MODULE_PROFILE_KEY_WRITE_PERMISSION, + BUNDLE_MODULE_PROFILE_KEY_DIRECT_LAUNCH, + BUNDLE_MODULE_PROFILE_KEY_CONFIG_CHANGES, + BUNDLE_MODULE_PROFILE_KEY_MISSION, + BUNDLE_MODULE_PROFILE_KEY_TARGET_ABILITY, + BUNDLE_MODULE_PROFILE_KEY_MULTIUSER_SHARED, + BUNDLE_MODULE_PROFILE_KEY_SUPPORT_PIP_MODE, + // sub BUNDLE_MODULE_PROFILE_KEY_JS + BUNDLE_MODULE_PROFILE_KEY_WINDOW, + // sub BUNDLE_MODULE_PROFILE_KEY_WINDOW + BUNDLE_MODULE_PROFILE_KEY_DESIGN_WIDTH, + BUNDLE_MODULE_PROFILE_KEY_AUTO_DESIGN_WIDTH, + // sub BUNDLE_MODULE_PROFILE_KEY_SHORTCUTS + BUNDLE_MODULE_PROFILE_KEY_SHORTCUT_INTENTS, + // sub BUNDLE_MODULE_PROFILE_KEY_SHORTCUT_INTENTS + BUNDLE_MODULE_PROFILE_KEY_TARGET_CLASS, + BUNDLE_MODULE_PROFILE_KEY_TARGET_BUNDLE, + }; + + for (const auto &propKey : notMustPropKeys) { + APP_LOGD("test not must prop %{public}s not exist", propKey.c_str()); + CheckNoPropProfileParseModule(propKey, ERR_OK); + } +} + +/** + * @tc.number: TestParse_0900 + * @tc.name: parse bundle package by config.json + * @tc.desc: 1. system running normally + * 2. test parse bundle failed when prop(configJson.app.bundleName) is not exist in the config.json + */ +HWTEST_F(BmsBundleParserTest, TestParse_0900, Function | SmallTest | Level0) +{ + std::vector mustPropKeys = { + BUNDLE_APP_PROFILE_KEY_BUNDLE_NAME, + }; + + for (const auto &propKey : mustPropKeys) { + APP_LOGD("test must prop %{public}s not exist", propKey.c_str()); + CheckNoPropProfileParseApp(propKey, ERR_APPEXECFWK_PARSE_BAD_PROFILE); + } +} + +/** + * @tc.number: TestParse_1000 + * @tc.name: parse bundle package by config.json + * @tc.desc: 1. system running normally + * 2. test parse bundle failed when prop(configJson.module.package,deviceType) is not exist in the + * config.json + */ +HWTEST_F(BmsBundleParserTest, TestParse_1000, Function | SmallTest | Level0) +{ + std::vector mustPropKeys = { + BUNDLE_MODULE_PROFILE_KEY_PACKAGE, + BUNDLE_MODULE_PROFILE_KEY_DEVICE_TYPE, + }; + + for (const auto &propKey : mustPropKeys) { + APP_LOGD("test must prop %{public}s not exist", propKey.c_str()); + CheckNoPropProfileParseModule(propKey, ERR_APPEXECFWK_PARSE_BAD_PROFILE); + } +} + +/** + * @tc.number: TestParse_1100 + * @tc.name: parse bundle package by config.json + * @tc.desc: 1. system running normally + * 2. test parse bundle failed when prop(configJson.module.distro.moduleName) is not exist in the + * config.json + */ +HWTEST_F(BmsBundleParserTest, TestParse_1100, Function | SmallTest | Level0) +{ + std::vector mustPropKeys = { + BUNDLE_MODULE_PROFILE_KEY_DISTRO, + }; + + for (const auto &propKey : mustPropKeys) { + APP_LOGD("test must prop %{public}s not exist", propKey.c_str()); + CheckNoPropProfileParseModule(propKey, ERR_APPEXECFWK_PARSE_BAD_PROFILE); + } +} + +/** + * @tc.number: TestParse_1200 + * @tc.name: parse bundle package by config.json + * @tc.desc: 1. system running normally + * 2. test parse bundle failed when prop(module.abilities.name) is not exist in the config.json + */ +HWTEST_F(BmsBundleParserTest, TestParse_1200, Function | SmallTest | Level0) +{ + std::vector mustPropKeys = { + PROFILE_KEY_NAME, + }; + + for (const auto &propKey : mustPropKeys) { + APP_LOGD("test must prop %{public}s not exist", propKey.c_str()); + CheckNoPropProfileParseModule(propKey, ERR_APPEXECFWK_PARSE_BAD_PROFILE); + } +} + +/** + * @tc.number: TestParse_1300 + * @tc.name: parse bundle package by config.json + * @tc.desc: 1. system running normally + * 2. test parse bundle failed when the config.json is empty json + */ +HWTEST_F(BmsBundleParserTest, TestParse_1300, Function | SmallTest | Level0) +{ + BundleParser bundleParser; + InnerBundleInfo innerBundleInfo; + pathStream_ << RESOURCE_ROOT_PATH << EMPTY_CONFIG << INSTALL_FILE_SUFFIX; + ErrCode result = bundleParser.Parse(pathStream_.str(), innerBundleInfo); + EXPECT_EQ(result, ERR_APPEXECFWK_PARSE_UNEXPECTED); +} + +/** + * @tc.number: TestParse_1400 + * @tc.name: parse bundle package by config.json + * @tc.desc: 1. system running normally + * 2. test parse bundle failed when the config.json has format MISSING + */ +HWTEST_F(BmsBundleParserTest, TestParse_1400, Function | SmallTest | Level0) +{ + BundleParser bundleParser; + InnerBundleInfo innerBundleInfo; + pathStream_ << RESOURCE_ROOT_PATH << FORMAT_MISSING_PROFILE << INSTALL_FILE_SUFFIX; + ErrCode result = bundleParser.Parse(pathStream_.str(), innerBundleInfo); + EXPECT_EQ(result, ERR_APPEXECFWK_PARSE_BAD_PROFILE); +} + +/** + * @tc.number: TestParse_1500 + * @tc.name: parse bundle package by config.json + * @tc.desc: 1. system running normally + * 2. test parse bundle failed when the config.json is nothing json + */ +HWTEST_F(BmsBundleParserTest, TestParse_1500, Function | SmallTest | Level0) +{ + BundleParser bundleParser; + InnerBundleInfo innerBundleInfo; + pathStream_ << RESOURCE_ROOT_PATH << NOTHING_CONFIG << INSTALL_FILE_SUFFIX; + ErrCode result = bundleParser.Parse(pathStream_.str(), innerBundleInfo); + EXPECT_EQ(result, ERR_APPEXECFWK_PARSE_BAD_PROFILE); +} + +/** + * @tc.number: TestParse_1600 + * @tc.name: parse bundle package by config.json + * @tc.desc: 1. system running normally + * 2. test parsing failed when an ability packet with an incorrect type in the file path + */ +HWTEST_F(BmsBundleParserTest, TestParse_1600, Function | SmallTest | Level0) +{ + BundleParser bundleParser; + InnerBundleInfo innerBundleInfo; + pathStream_ << RESOURCE_ROOT_PATH << "demo.error_type"; + ErrCode result = bundleParser.Parse(pathStream_.str(), innerBundleInfo); + EXPECT_EQ(result, ERR_APPEXECFWK_PARSE_UNEXPECTED); + + pathStream_.str(""); + pathStream_ << RESOURCE_ROOT_PATH << "demo."; + result = bundleParser.Parse(pathStream_.str(), innerBundleInfo); + EXPECT_EQ(result, ERR_APPEXECFWK_PARSE_UNEXPECTED); + + pathStream_.str(""); + pathStream_ << RESOURCE_ROOT_PATH << "bundle_suffix_test.BUNDLE"; + result = bundleParser.Parse(pathStream_.str(), innerBundleInfo); + EXPECT_EQ(result, ERR_APPEXECFWK_PARSE_UNEXPECTED); +} + +/** + * @tc.number: TestParse_1700 + * @tc.name: parse bundle package by config.json + * @tc.desc: 1. system running normally + * 2. test parsing failed when an bundle packet with a deep file path depth + */ +HWTEST_F(BmsBundleParserTest, TestParse_1700, Function | SmallTest | Level1) +{ + BundleParser bundleParser; + InnerBundleInfo innerBundleInfo; + pathStream_ << RESOURCE_ROOT_PATH; + int maxDeep = 100; + for (int i = 0; i < maxDeep; i++) { + pathStream_ << "test/"; + } + pathStream_ << NEW_APP << INSTALL_FILE_SUFFIX; + ErrCode result = bundleParser.Parse(pathStream_.str(), innerBundleInfo); + EXPECT_EQ(result, ERR_APPEXECFWK_PARSE_UNEXPECTED) << pathStream_.str(); +} + +/** + * @tc.number: TestParse_1800 + * @tc.name: parse bundle package by config.json + * @tc.desc: 1. system running normally + * 2. test parsing failed when an bundle packet with a long path + */ +HWTEST_F(BmsBundleParserTest, TestParse_1800, Function | SmallTest | Level1) +{ + BundleParser bundleParser; + InnerBundleInfo innerBundleInfo; + pathStream_ << RESOURCE_ROOT_PATH; + int maxLength = 256; + for (int i = 0; i < maxLength; i++) { + pathStream_ << "test/"; + } + pathStream_ << NEW_APP << INSTALL_FILE_SUFFIX; + ErrCode result = bundleParser.Parse(pathStream_.str(), innerBundleInfo); + EXPECT_EQ(result, ERR_APPEXECFWK_PARSE_UNEXPECTED); +} + +/** + * @tc.number: TestParse_1900 + * @tc.name: parse bundle package by config.json + * @tc.desc: 1. system running normally + * 2. test parsing failed when an bundle packet with special character in the file path + */ +HWTEST_F(BmsBundleParserTest, TestParse_1900, Function | SmallTest | Level1) +{ + BundleParser bundleParser; + InnerBundleInfo innerBundleInfo; + pathStream_ << RESOURCE_ROOT_PATH; + std::string specialChars = "~!@#$%^&*(){}[]:;'?<>,.|`/./+_-"; + pathStream_ << specialChars << "new" << INSTALL_FILE_SUFFIX; + + ErrCode result = bundleParser.Parse(pathStream_.str(), innerBundleInfo); + EXPECT_EQ(result, ERR_APPEXECFWK_PARSE_UNEXPECTED); +} + +/** + * @tc.number: TestParse_2000 + * @tc.name: parse bundle package by config.json + * @tc.desc: 1. system running normally + * 2. test parsing failed when def-permission prop has error in the config.json + */ +HWTEST_F(BmsBundleParserTest, TestParse_2000, Function | SmallTest | Level1) +{ + nlohmann::json errorDefPermJson = CONFIG_JSON; + errorDefPermJson[BUNDLE_PROFILE_KEY_MODULE][BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS] = R"( + [{ + "name": "~!@#$%^&*(){}[]:;'?<>,.|`/./+_-", + "reason": "~!@#$%^&*(){}[]:;'?<>,.|`/./+_-", + "when": "~!@#$%^&*(){}[]:;'?<>,.|`/./+_-" + }] + )"_json; + CheckProfilePermission(errorDefPermJson); +} + +/** + * @tc.number: TestParse_2100 + * @tc.name: parse bundle package by config.json + * @tc.desc: 1. system running normally + * 2. test parsing failed when req-permission prop has error in the config.json + */ +HWTEST_F(BmsBundleParserTest, TestParse_2100, Function | SmallTest | Level1) +{ + nlohmann::json errorReqPermJson = CONFIG_JSON; + errorReqPermJson[BUNDLE_PROFILE_KEY_MODULE][BUNDLE_MODULE_PROFILE_KEY_REQ_PERMISSIONS] = R"( + [{ + "name": "~!@#$%^&*(){}[]:;'?<>,.|`/./+_-", + "reason": "~!@#$%^&*(){}[]:;'?<>,.|`/./+_-", + "when": "~!@#$%^&*(){}[]:;'?<>,.|`/./+_-" + }] + )"_json; + CheckProfilePermission(errorReqPermJson); +} + +/** + * @tc.number: TestParse_2200 + * @tc.name: parse bundle package by config.json + * @tc.desc: 1. system running normally + * 2. test parsing failed when def-permission prop has empty in the config.json + */ +HWTEST_F(BmsBundleParserTest, TestParse_2200, Function | SmallTest | Level1) +{ + nlohmann::json errorDefPermJson = CONFIG_JSON; + errorDefPermJson[BUNDLE_PROFILE_KEY_MODULE][BUNDLE_MODULE_PROFILE_KEY_DEF_PERMISSIONS] = R"( + [{ + + }] + )"_json; + CheckProfilePermission(errorDefPermJson); +} + +/** + * @tc.number: TestParse_2300 + * @tc.name: parse bundle package by config.json + * @tc.desc: 1. system running normally + * 2. test parsing failed when req-permission prop has empty in the config.json + */ +HWTEST_F(BmsBundleParserTest, TestParse_2300, Function | SmallTest | Level1) +{ + nlohmann::json errorReqPermJson = CONFIG_JSON; + errorReqPermJson[BUNDLE_PROFILE_KEY_MODULE][BUNDLE_MODULE_PROFILE_KEY_REQ_PERMISSIONS] = R"( + [{ + + }] + )"_json; + CheckProfilePermission(errorReqPermJson); +} + +/** + * @tc.number: TestExtractByName_0100 + * @tc.name: extract file stream by file name from package + * @tc.desc: 1. system running normally + * 2. test extract file from is not exist bundle or ability package + */ +HWTEST_F(BmsBundleParserTest, TestExtractByName_0100, Function | SmallTest | Level0) +{ + pathStream_ << RESOURCE_ROOT_PATH << UNKOWN_PATH << INSTALL_FILE_SUFFIX; + std::string fileInBundle = ""; + std::ostringstream fileBuffer; + + BundleExtractor bundleExtractor(pathStream_.str()); + bool result = bundleExtractor.ExtractByName(fileInBundle, fileBuffer); + ASSERT_FALSE(result); +} + +/** + * @tc.number: TestExtractByName_0200 + * @tc.name: extract file stream by file name from package + * @tc.desc: 1. system running normally + * 2. test extract is not exist file from bundle or ability package + */ +HWTEST_F(BmsBundleParserTest, TestExtractByName_0200, Function | SmallTest | Level0) +{ + pathStream_ << RESOURCE_ROOT_PATH << NEW_APP << INSTALL_FILE_SUFFIX; + std::string fileInBundle = "unknown"; + std::ostringstream fileBuffer; + + BundleExtractor bundleExtractor(pathStream_.str()); + bool result = bundleExtractor.ExtractByName(fileInBundle, fileBuffer); + ASSERT_FALSE(result); +} + +/** + * @tc.number: TestExtractByName_0300 + * @tc.name: extract file stream by file name from package + * @tc.desc: 1. system running normally + * 2. test failed to extract files from a package with a deep file path depth + */ +HWTEST_F(BmsBundleParserTest, TestExtractByName_0300, Function | SmallTest | Level1) +{ + pathStream_ << RESOURCE_ROOT_PATH; + int maxDeep = 100; + for (int i = 0; i < maxDeep; i++) { + pathStream_ << "test/"; + } + pathStream_ << "app" << INSTALL_FILE_SUFFIX; + + std::string fileInBundle = "config.json"; + std::ostringstream fileBuffer; + + BundleExtractor bundleExtractor(pathStream_.str()); + bool result = bundleExtractor.ExtractByName(fileInBundle, fileBuffer); + ASSERT_FALSE(result); +} + +/** + * @tc.number: TestExtractByName_0400 + * @tc.name: extract file stream by file name from package + * @tc.desc: 1. system running normally + * 2. test failed to extract files from a file with a long path + */ +HWTEST_F(BmsBundleParserTest, TestExtractByName_0400, Function | SmallTest | Level1) +{ + pathStream_ << RESOURCE_ROOT_PATH; + int maxLength = 256; + for (int i = 0; i < maxLength; i++) { + pathStream_ << "test"; + } + pathStream_ << "new" << INSTALL_FILE_SUFFIX; + + std::string fileInBundle = "config.json"; + std::ostringstream fileBuffer; + + BundleExtractor bundleExtractor(pathStream_.str()); + bool result = bundleExtractor.ExtractByName(fileInBundle, fileBuffer); + ASSERT_FALSE(result); +} + +/** + * @tc.number: TestExtractByName_0500 + * @tc.name: extract file stream by file name from package + * @tc.desc: 1. system running normally + * 2. test failed to extract files from a package with special character in the file path + */ +HWTEST_F(BmsBundleParserTest, TestExtractByName_0500, Function | SmallTest | Level1) +{ + pathStream_ << RESOURCE_ROOT_PATH; + std::string specialChars = "~!@#$%^&*(){}[]:;'?<>,.|`/./+_-"; + pathStream_ << specialChars << "new" << INSTALL_FILE_SUFFIX; + + std::string fileInBundle = "config.json"; + std::ostringstream fileBuffer; + + BundleExtractor bundleExtractor(pathStream_.str()); + bool result = bundleExtractor.ExtractByName(fileInBundle, fileBuffer); + ASSERT_FALSE(result); +} \ No newline at end of file diff --git a/services/bundlemgr/test/unittest/bms_bundle_uninstaller_test/BUILD.gn b/services/bundlemgr/test/unittest/bms_bundle_uninstaller_test/BUILD.gn new file mode 100644 index 000000000..62ef8f22a --- /dev/null +++ b/services/bundlemgr/test/unittest/bms_bundle_uninstaller_test/BUILD.gn @@ -0,0 +1,84 @@ +# 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") +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("BmsBundleUninstallerTest") { + module_out_path = module_output_path + + sources = [ + "${services_path}/bundlemgr/src/bundle_data_mgr.cpp", + "${services_path}/bundlemgr/src/bundle_data_storage.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/installd/installd_host_impl.cpp", + "${services_path}/bundlemgr/src/installd/installd_operator.cpp", + "${services_path}/bundlemgr/src/installd/installd_service.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 + + sources += [ "bms_bundle_uninstaller_test.cpp" ] + + configs = [ + ":private_config", + "${libs_path}/libeventhandler:libeventhandler_config", + "${services_path}/bundlemgr/test:bundlemgr_test_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${libs_path}/libeventhandler:libeventhandler_target", + "//base/notification/ces_standard/cesfwk/kits/native:cesfwk_kits", + "//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/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + ] + + deps += bundle_install_deps + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":BmsBundleUninstallerTest" ] +} 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 new file mode 100755 index 000000000..542d5d2d5 --- /dev/null +++ b/services/bundlemgr/test/unittest/bms_bundle_uninstaller_test/bms_bundle_uninstaller_test.cpp @@ -0,0 +1,648 @@ +/* + * 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 "directory_ex.h" +#include "appexecfwk_errors.h" +#include "bundle_info.h" +#include "bundle_installer_host.h" +#include "bundle_mgr_service.h" +#include "installd/installd_service.h" +#include "installd_client.h" +#include "mock_status_receiver.h" +#include "install_param.h" +#include "system_bundle_installer.h" + +using namespace testing::ext; +using namespace std::chrono_literals; +using namespace OHOS; +using namespace OHOS::AppExecFwk; + +namespace { + +const std::string BUNDLE_NAME = "com.example.l3jsdemo"; +const std::string MODULE_PACKAGE = "com.example.l3jsdemo"; +const std::string MODULE_PACKAGE1 = "com.example.l3jsdemo1"; +const std::string ERROR_BUNDLE_NAME = "com.example.bundle.uninstall.error"; +const std::string ERROR_MODULE_PACKAGE_NAME = "com.example.module.uninstall.error"; +const std::string BUNDLE_FILE_PATH = "/data/test/resource/bms/uninstall_bundle/right.hap"; +const std::string BUNDLE_FILE_PATH1 = "/data/test/resource/bms/uninstall_bundle/right1.hap"; +const std::string BUNDLE_DATA_DIR = "/data/accounts/account_0/appdata/com.example.l3jsdemo"; +const std::string BUNDLE_CODE_DIR = "/data/accounts/account_0/applications/com.example.l3jsdemo"; +const std::string MODULE_DATA_DIR = "/data/accounts/account_0/appdata/com.example.l3jsdemo/com.example.l3jsdemo"; +const std::string MODULE_CODE_DIR = "/data/accounts/account_0/applications/com.example.l3jsdemo/com.example.l3jsdemo"; +const std::string MODULE_DATA_DIR1 = "/data/accounts/account_0/appdata/com.example.l3jsdemo/com.example.l3jsdemo1"; +const std::string MODULE_CODE_DIR1 = "/data/accounts/account_0/applications/com.example.l3jsdemo/com.example.l3jsdemo1"; +const std::string ROOT_DIR = "/data/accounts"; +const std::string DB_FILE_PATH = "/data/bundlemgr"; +const int32_t ROOT_UID = 0; + +} // namespace + +class BmsBundleUninstallerTest : public testing::Test { +public: + BmsBundleUninstallerTest(); + ~BmsBundleUninstallerTest(); + + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + + ErrCode InstallBundle(const std::string &bundlePath) const; + ErrCode UninstallBundle(const std::string &bundleName) const; + ErrCode UninstallModule(const std::string &bundleName, const std::string &modulePackage) const; + void CheckFileExist() const; + void CheckModuleFileExist() const; + void CheckModuleFileExist1() const; + void CheckFileNonExist() const; + void CheckModuleFileNonExist() const; + void StopInstalldService() const; + void StartInstalldService() const; + void StartBundleService(); + void StopBundleService(); + void CheckBundleInfoExist() const; + void CheckBundleInfoNonExist() const; + void ClearJsonFile() const; + const std::shared_ptr GetBundleMgrService() const; + void DeleteInstallFiles(); + +private: + std::shared_ptr installdService_ = std::make_unique(); + std::shared_ptr bundleMgrService_ = DelayedSingleton::GetInstance(); +}; + +BmsBundleUninstallerTest::BmsBundleUninstallerTest() +{} + +BmsBundleUninstallerTest::~BmsBundleUninstallerTest() +{} + +void BmsBundleUninstallerTest::SetUpTestCase() +{ + if (access(ROOT_DIR.c_str(), F_OK) != 0) { + bool result = OHOS::ForceCreateDirectory(ROOT_DIR); + ASSERT_TRUE(result); + } + if (chown(ROOT_DIR.c_str(), ROOT_UID, ROOT_UID) != 0) { + ASSERT_TRUE(false); + } + if (chmod(ROOT_DIR.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) { + ASSERT_TRUE(false); + } +} + +void BmsBundleUninstallerTest::TearDownTestCase() +{} + +void BmsBundleUninstallerTest::SetUp() +{ + StartBundleService(); + StartInstalldService(); +} + +void BmsBundleUninstallerTest::TearDown() +{ + StopInstalldService(); + StopBundleService(); +} + +void BmsBundleUninstallerTest::ClearJsonFile() const +{ + OHOS::RemoveFile(Constants::BUNDLE_DATA_BASE_FILE); + std::fstream o(Constants::BUNDLE_DATA_BASE_FILE); + if (!o.is_open()) { + return; + } + o.close(); +} + +ErrCode BmsBundleUninstallerTest::InstallBundle(const std::string &bundlePath) const +{ + if (!bundleMgrService_) { + return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR; + } + auto installer = bundleMgrService_->GetBundleInstaller(); + if (!installer) { + EXPECT_FALSE(true) << "the installer is nullptr"; + return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR; + } + sptr receiver = new (std::nothrow) MockStatusReceiver(); + if (!receiver) { + EXPECT_FALSE(true) << "the receiver is nullptr"; + return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR; + } + InstallParam installParam; + installParam.installFlag = InstallFlag::NORMAL; + bool result = installer->Install(bundlePath, installParam, receiver); + EXPECT_TRUE(result); + return receiver->GetResultCode(); +} + +ErrCode BmsBundleUninstallerTest::UninstallBundle(const std::string &bundleName) const +{ + if (!bundleMgrService_) { + return ERR_APPEXECFWK_UNINSTALL_BUNDLE_MGR_SERVICE_ERROR; + } + auto installer = bundleMgrService_->GetBundleInstaller(); + if (!installer) { + EXPECT_FALSE(true) << "the installer is nullptr"; + return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR; + } + sptr receiver = new (std::nothrow) MockStatusReceiver(); + if (!receiver) { + EXPECT_FALSE(true) << "the receiver is nullptr"; + return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR; + } + InstallParam installParam; + installParam.installFlag = InstallFlag::NORMAL; + bool result = installer->Uninstall(bundleName, installParam, receiver); + EXPECT_TRUE(result); + return receiver->GetResultCode(); +} + +ErrCode BmsBundleUninstallerTest::UninstallModule(const std::string &bundleName, const std::string &modulePackage) const +{ + if (!bundleMgrService_) { + return ERR_APPEXECFWK_UNINSTALL_BUNDLE_MGR_SERVICE_ERROR; + } + auto installer = bundleMgrService_->GetBundleInstaller(); + if (!installer) { + EXPECT_FALSE(true) << "the installer is nullptr"; + return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR; + } + sptr receiver = new (std::nothrow) MockStatusReceiver(); + if (!receiver) { + EXPECT_FALSE(true) << "the receiver is nullptr"; + return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR; + } + InstallParam installParam; + installParam.installFlag = InstallFlag::NORMAL; + bool result = installer->Uninstall(bundleName, modulePackage, installParam, receiver); + EXPECT_TRUE(result); + return receiver->GetResultCode(); +} + +void BmsBundleUninstallerTest::CheckFileExist() const +{ + int bundleDataExist = access(BUNDLE_DATA_DIR.c_str(), F_OK); + ASSERT_EQ(bundleDataExist, 0); + + int bundleCodeExist = access(BUNDLE_CODE_DIR.c_str(), F_OK); + ASSERT_EQ(bundleCodeExist, 0); +} + +void BmsBundleUninstallerTest::CheckModuleFileExist() const +{ + int moduleDataExist = access(MODULE_DATA_DIR.c_str(), F_OK); + ASSERT_EQ(moduleDataExist, 0); + + int moduleCodeExist = access(MODULE_CODE_DIR.c_str(), F_OK); + ASSERT_EQ(moduleCodeExist, 0); +} + +void BmsBundleUninstallerTest::CheckModuleFileExist1() const +{ + int moduleDataExist1 = access(MODULE_DATA_DIR1.c_str(), F_OK); + ASSERT_EQ(moduleDataExist1, 0); + + int moduleCodeExist1 = access(MODULE_CODE_DIR1.c_str(), F_OK); + ASSERT_EQ(moduleCodeExist1, 0); +} + +void BmsBundleUninstallerTest::CheckFileNonExist() const +{ + int bundleDataExist = access(BUNDLE_DATA_DIR.c_str(), F_OK); + ASSERT_NE(bundleDataExist, 0); + + int bundleCodeExist = access(BUNDLE_CODE_DIR.c_str(), F_OK); + ASSERT_NE(bundleCodeExist, 0); +} + +void BmsBundleUninstallerTest::CheckModuleFileNonExist() const +{ + int moduleDataExist = access(MODULE_DATA_DIR.c_str(), F_OK); + ASSERT_NE(moduleDataExist, 0); + + int moduleCodeExist = access(MODULE_CODE_DIR.c_str(), F_OK); + ASSERT_NE(moduleCodeExist, 0); +} + +void BmsBundleUninstallerTest::StopInstalldService() const +{ + installdService_->Stop(); + InstalldClient::GetInstance()->ResetInstalldProxy(); +} + +void BmsBundleUninstallerTest::StartInstalldService() const +{ + installdService_->Start(); +} + +void BmsBundleUninstallerTest::StartBundleService() +{ + if (!bundleMgrService_) { + bundleMgrService_ = DelayedSingleton::GetInstance(); + } + if (bundleMgrService_) { + bundleMgrService_->OnStart(); + } +} + +void BmsBundleUninstallerTest::StopBundleService() +{ + if (bundleMgrService_) { + bundleMgrService_->OnStop(); + bundleMgrService_ = nullptr; + } +} + +void BmsBundleUninstallerTest::CheckBundleInfoExist() const +{ + ASSERT_NE(bundleMgrService_, nullptr); + auto dataMgr = bundleMgrService_->GetDataMgr(); + ASSERT_NE(dataMgr, nullptr); + BundleInfo info; + bool isBundleExist = dataMgr->GetBundleInfo(BUNDLE_NAME, BundleFlag::GET_BUNDLE_DEFAULT, info); + ASSERT_TRUE(isBundleExist); +} + +void BmsBundleUninstallerTest::CheckBundleInfoNonExist() const +{ + ASSERT_NE(bundleMgrService_, nullptr); + auto dataMgr = bundleMgrService_->GetDataMgr(); + ASSERT_NE(dataMgr, nullptr); + BundleInfo info; + bool isBundleExist = dataMgr->GetBundleInfo(BUNDLE_NAME, BundleFlag::GET_BUNDLE_DEFAULT, info); + ASSERT_FALSE(isBundleExist); +} + +const std::shared_ptr BmsBundleUninstallerTest::GetBundleMgrService() const +{ + return bundleMgrService_; +} + +void BmsBundleUninstallerTest::DeleteInstallFiles() +{ + DelayedSingleton::DestroyInstance(); + // clear files. + ClearJsonFile(); + OHOS::ForceRemoveDirectory(BUNDLE_DATA_DIR); + OHOS::ForceRemoveDirectory(BUNDLE_CODE_DIR); + bundleMgrService_ = DelayedSingleton::GetInstance(); +} + +/** + * @tc.number: Bundle_Uninstall_0100 + * @tc.name: test the installed bundle can be uninstalled + * @tc.desc: 1. the bundle is already installed + * 2. the installed bundle can be uninstalled successfully + */ +HWTEST_F(BmsBundleUninstallerTest, Bundle_Uninstall_0100, Function | SmallTest | Level0) +{ + ErrCode installResult = InstallBundle(BUNDLE_FILE_PATH); + ASSERT_EQ(installResult, ERR_OK); + CheckBundleInfoExist(); + CheckFileExist(); + + ErrCode uninstallResult = UninstallBundle(BUNDLE_NAME); + ASSERT_EQ(uninstallResult, ERR_OK); + CheckFileNonExist(); + CheckBundleInfoNonExist(); +} + +/** + * @tc.number: Bundle_Uninstall_0200 + * @tc.name: test the empty bundle name will return fail + * @tc.desc: 1. the bundle name is empty + * 2. the empty bundle name will return fail + */ +HWTEST_F(BmsBundleUninstallerTest, Bundle_Uninstall_0200, Function | SmallTest | Level0) +{ + ErrCode result = UninstallBundle(""); + EXPECT_EQ(result, ERR_APPEXECFWK_UNINSTALL_INVALID_NAME); +} + +/** + * @tc.number: Bundle_Uninstall_0300 + * @tc.name: test the error bundle name will return fail + * @tc.desc: 1. the bundle name is error + * 2. the error bundle name will return fail + */ +HWTEST_F(BmsBundleUninstallerTest, Bundle_Uninstall_0300, Function | SmallTest | Level0) +{ + ErrCode result = UninstallBundle(ERROR_BUNDLE_NAME); + EXPECT_EQ(result, ERR_APPEXECFWK_UNINSTALL_MISSING_INSTALLED_BUNDLE); +} + +/** + * @tc.number: Bundle_Uninstall_0400 + * @tc.name: test the bundle mgr service error case + * @tc.desc: 1. the bundle mgr service error + * 2. the uninstall operation will return fail and the next uninstall operation will success after restart + * bundle mgr service + */ +HWTEST_F(BmsBundleUninstallerTest, Bundle_Uninstall_0400, Function | SmallTest | Level0) +{ + ErrCode installResult = InstallBundle(BUNDLE_FILE_PATH); + ASSERT_EQ(installResult, ERR_OK); + CheckFileExist(); + CheckBundleInfoExist(); + + StopBundleService(); + ErrCode secondResult = UninstallBundle(BUNDLE_NAME); + ASSERT_EQ(secondResult, ERR_APPEXECFWK_UNINSTALL_BUNDLE_MGR_SERVICE_ERROR); + CheckFileExist(); + StartBundleService(); + CheckBundleInfoExist(); + + ErrCode thirdResult = UninstallBundle(BUNDLE_NAME); + ASSERT_EQ(thirdResult, ERR_OK); + CheckFileNonExist(); + CheckBundleInfoNonExist(); +} + +/** + * @tc.number: Bundle_Uninstall_0500 + * @tc.name: test the installd service error + * @tc.desc: 1. the installd service error + * 2. the uninstall operation will return fail. + */ +HWTEST_F(BmsBundleUninstallerTest, Bundle_Uninstall_0500, Function | SmallTest | Level0) +{ + ErrCode installResult = InstallBundle(BUNDLE_FILE_PATH); + ASSERT_EQ(installResult, ERR_OK); + CheckFileExist(); + CheckBundleInfoExist(); + + StopInstalldService(); + ErrCode uninstallResult = UninstallBundle(BUNDLE_NAME); + ASSERT_EQ(uninstallResult, ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR); + CheckFileExist(); + + StartInstalldService(); + CheckFileExist(); + DeleteInstallFiles(); +} + +/** + * @tc.number: Bundle_Uninstall_0600 + * @tc.name: test when status receiver is null will not uninstall bundle + * @tc.desc: 1. the status receiver is null + * 2. the uninstall bundle operation will not execute when status receiver is null + */ +HWTEST_F(BmsBundleUninstallerTest, Bundle_Uninstall_0600, Function | SmallTest | Level1) +{ + ErrCode installResult = InstallBundle(BUNDLE_FILE_PATH); + ASSERT_EQ(installResult, ERR_OK); + CheckFileExist(); + CheckBundleInfoExist(); + + InstallParam installParam; + installParam.installFlag = InstallFlag::NORMAL; + auto bms = GetBundleMgrService(); + ASSERT_NE(bms, nullptr); + auto installer = bms->GetBundleInstaller(); + ASSERT_NE(installer, nullptr); + bool result = installer->Uninstall(BUNDLE_NAME, installParam, nullptr); + EXPECT_FALSE(result); + + std::this_thread::sleep_for(100ms); + CheckFileExist(); + CheckBundleInfoExist(); + DeleteInstallFiles(); +} + +/** + * @tc.number: Bundle_Uninstall_0700 + * @tc.name: test the installed system bundle can't be uninstalled + * @tc.desc: 1. the system bundle is already installed + * 2. the installed system bundle can't be uninstalled + */ +HWTEST_F(BmsBundleUninstallerTest, Bundle_Uninstall_0700, Function | SmallTest | Level0) +{ + auto installer = std::make_unique(BUNDLE_FILE_PATH); + ASSERT_NE(installer, nullptr); + bool installResult = installer->InstallSystemBundle(Constants::AppType::SYSTEM_APP); + ASSERT_EQ(installResult, true); + CheckFileExist(); + CheckBundleInfoExist(); + + ErrCode uninstallResult = UninstallBundle(BUNDLE_NAME); + ASSERT_EQ(uninstallResult, ERR_APPEXECFWK_UNINSTALL_SYSTEM_APP_ERROR); + CheckFileExist(); + CheckBundleInfoExist(); + DeleteInstallFiles(); +} + +/** + * @tc.number: Module_Uninstall_0100 + * @tc.name: test the installed Module can be uninstalled + * @tc.desc: 1. the Module is already installed + * 2. the installed Module can be uninstalled successfully + */ +HWTEST_F(BmsBundleUninstallerTest, Module_Uninstall_0100, Function | SmallTest | Level0) +{ + ErrCode installResult = InstallBundle(BUNDLE_FILE_PATH); + ASSERT_EQ(installResult, ERR_OK); + CheckBundleInfoExist(); + CheckFileExist(); + + ErrCode uninstallResult = UninstallModule(BUNDLE_NAME, MODULE_PACKAGE); + ASSERT_EQ(uninstallResult, ERR_OK); + CheckFileNonExist(); + CheckBundleInfoNonExist(); +} + +/** + * @tc.number: Module_Uninstall_0200 + * @tc.name: test the installed Module can be uninstalled + * @tc.desc: 1. the Module name is empty + * 2. the empty Module name will return fail + */ +HWTEST_F(BmsBundleUninstallerTest, Module_Uninstall_0200, Function | SmallTest | Level0) +{ + ErrCode result = UninstallModule(BUNDLE_NAME, ""); + EXPECT_EQ(result, ERR_APPEXECFWK_UNINSTALL_INVALID_NAME); +} + +/** + * @tc.number: Module_Uninstall_0300 + * @tc.name: test the error Module name will return fail. + * @tc.desc: 1. the Module name is error. + * 2. the error Module name will return fail. + */ +HWTEST_F(BmsBundleUninstallerTest, Module_Uninstall_0300, Function | SmallTest | Level0) +{ + ErrCode result = UninstallModule(BUNDLE_NAME, ERROR_MODULE_PACKAGE_NAME); + EXPECT_EQ(result, ERR_APPEXECFWK_UNINSTALL_MISSING_INSTALLED_BUNDLE); +} + +/** + * @tc.number: Module_Uninstall_0400 + * @tc.name: test the bundle mgr service error case. + * @tc.desc: 1. the bundle mgr service error. + * 2. the uninstall operation will return fail and the next uninstall operation will success after + * restart bundle mgr service. + */ +HWTEST_F(BmsBundleUninstallerTest, Module_Uninstall_0400, Function | SmallTest | Level0) +{ + ErrCode installResult = InstallBundle(BUNDLE_FILE_PATH); + ASSERT_EQ(installResult, ERR_OK); + CheckFileExist(); + CheckBundleInfoExist(); + + StopBundleService(); + ErrCode secondResult = UninstallModule(BUNDLE_NAME, MODULE_PACKAGE); + ASSERT_EQ(secondResult, ERR_APPEXECFWK_UNINSTALL_BUNDLE_MGR_SERVICE_ERROR); + CheckFileExist(); + StartBundleService(); + CheckBundleInfoExist(); + + ErrCode thirdResult = UninstallModule(BUNDLE_NAME, MODULE_PACKAGE); + ASSERT_EQ(thirdResult, ERR_OK); + CheckFileNonExist(); + CheckBundleInfoNonExist(); +} + +/** + * @tc.number: Module_Uninstall_0500 + * @tc.name: test the installd service error case. + * @tc.desc: 1. the installd service error. + * 2. the uninstall module operation will return fail. + */ +HWTEST_F(BmsBundleUninstallerTest, Module_Uninstall_0500, Function | SmallTest | Level0) +{ + ErrCode installResult = InstallBundle(BUNDLE_FILE_PATH); + ASSERT_EQ(installResult, ERR_OK); + CheckFileExist(); + CheckBundleInfoExist(); + + StopInstalldService(); + ErrCode uninstallResult = UninstallModule(BUNDLE_NAME, MODULE_PACKAGE); + ASSERT_EQ(uninstallResult, ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR); + CheckFileExist(); + + StartInstalldService(); + CheckFileExist(); + DeleteInstallFiles(); +} + +/** + * @tc.number: Module_Uninstall_0600 + * @tc.name: test when status receiver is null will not uninstall Module. + * @tc.desc: 1. the status receiver is null. + * 2. the uninstall Module operation will not execute when status receiver is null. + */ +HWTEST_F(BmsBundleUninstallerTest, Module_Uninstall_0600, Function | SmallTest | Level1) +{ + ErrCode installResult = InstallBundle(BUNDLE_FILE_PATH); + ASSERT_EQ(installResult, ERR_OK); + CheckFileExist(); + CheckBundleInfoExist(); + + InstallParam installParam; + installParam.installFlag = InstallFlag::NORMAL; + auto bms = GetBundleMgrService(); + ASSERT_NE(bms, nullptr); + auto installer = bms->GetBundleInstaller(); + ASSERT_NE(installer, nullptr); + bool result = installer->Uninstall(BUNDLE_NAME, MODULE_PACKAGE, installParam, nullptr); + EXPECT_FALSE(result); + + std::this_thread::sleep_for(100ms); + CheckFileExist(); + CheckBundleInfoExist(); + DeleteInstallFiles(); +} + +/** + * @tc.number: Module_Uninstall_0700 + * @tc.name: test the installed system bundle can't be uninstalled. + * @tc.desc: 1. the system bundle is already installed. + * 2. the installed system bundle can't be uninstalled. + */ +HWTEST_F(BmsBundleUninstallerTest, Module_Uninstall_0700, Function | SmallTest | Level0) +{ + auto installer = std::make_unique(BUNDLE_FILE_PATH); + ASSERT_NE(installer, nullptr); + bool installResult = installer->InstallSystemBundle(Constants::AppType::SYSTEM_APP); + ASSERT_EQ(installResult, true); + CheckFileExist(); + CheckBundleInfoExist(); + + ErrCode uninstallResult = UninstallModule(BUNDLE_NAME, MODULE_PACKAGE); + ASSERT_EQ(uninstallResult, ERR_APPEXECFWK_UNINSTALL_SYSTEM_APP_ERROR); + CheckFileExist(); + CheckBundleInfoExist(); + DeleteInstallFiles(); +} + +/** + * @tc.number: Module_Uninstall_0800 + * @tc.name: test the installed Module can be uninstalled. + * @tc.desc: 1. the two Module is already installed. + * 2. the installed one Module can be uninstalled successfully. + */ +HWTEST_F(BmsBundleUninstallerTest, Module_Uninstall_0800, Function | SmallTest | Level0) +{ + ErrCode installResult = InstallBundle(BUNDLE_FILE_PATH); + ASSERT_EQ(installResult, ERR_OK); + ErrCode installResult1 = InstallBundle(BUNDLE_FILE_PATH1); + ASSERT_EQ(installResult1, ERR_OK); + CheckBundleInfoExist(); + CheckFileExist(); + CheckModuleFileExist(); + CheckModuleFileExist1(); + + ErrCode uninstallResult = UninstallModule(BUNDLE_NAME, MODULE_PACKAGE); + ASSERT_EQ(uninstallResult, ERR_OK); + CheckModuleFileNonExist(); + CheckModuleFileExist1(); + CheckBundleInfoExist(); + DeleteInstallFiles(); +} + +/** + * @tc.number: Module_Uninstall_0900 + * @tc.name: test the installed Module can be uninstalled. + * @tc.desc: 1. the two Module is already installed. + * 2. the installed two Module can be uninstalled successfully. + */ +HWTEST_F(BmsBundleUninstallerTest, Module_Uninstall_0900, Function | SmallTest | Level0) +{ + ErrCode installResult = InstallBundle(BUNDLE_FILE_PATH); + ASSERT_EQ(installResult, ERR_OK); + ErrCode installResult1 = InstallBundle(BUNDLE_FILE_PATH1); + ASSERT_EQ(installResult1, ERR_OK); + CheckBundleInfoExist(); + CheckFileExist(); + CheckModuleFileExist(); + CheckModuleFileExist1(); + + ErrCode uninstallResult = UninstallModule(BUNDLE_NAME, MODULE_PACKAGE); + ASSERT_EQ(uninstallResult, ERR_OK); + ErrCode uninstallResult1 = UninstallModule(BUNDLE_NAME, MODULE_PACKAGE1); + ASSERT_EQ(uninstallResult1, ERR_OK); + CheckFileNonExist(); + CheckBundleInfoNonExist(); + DeleteInstallFiles(); +} \ No newline at end of file diff --git a/services/bundlemgr/test/unittest/bms_bundle_updater_test/BUILD.gn b/services/bundlemgr/test/unittest/bms_bundle_updater_test/BUILD.gn new file mode 100644 index 000000000..d0df6ee69 --- /dev/null +++ b/services/bundlemgr/test/unittest/bms_bundle_updater_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") +import( + "//foundation/appexecfwk/standard/services/bundlemgr/appexecfwk_bundlemgr.gni") + +config("private_config") { + include_dirs = [ + "${services_path}/bundlemgr/test/mock/include", + "${services_path}/test/moduletest/utils/include", + ] +} + +module_output_path = "appexecfwk_standard/bundlemgrservice" + +ohos_unittest("BmsBundleUpdaterTest") { + module_out_path = module_output_path + + sources = [ + "${services_path}/bundlemgr/src/bundle_data_mgr.cpp", + "${services_path}/bundlemgr/src/bundle_data_storage.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/installd/installd_host_impl.cpp", + "${services_path}/bundlemgr/src/installd/installd_operator.cpp", + "${services_path}/bundlemgr/src/installd/installd_service.cpp", + ] + + sources += [ + "${services_path}/bundlemgr/test/mock/src/mock_status_receiver.cpp", + "${services_path}/bundlemgr/test/mock/src/system_ability_helper.cpp", + "${services_path}/test/moduletest/utils/src/common_tool.cpp", + ] + + sources += bundle_install_sources + + sources += [ "bms_bundle_updater_test.cpp" ] + + configs = [ + ":private_config", + "${libs_path}/libeventhandler:libeventhandler_config", + "${services_path}/bundlemgr/test:bundlemgr_test_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${libs_path}/libeventhandler:libeventhandler_target", + "//base/notification/ces_standard/cesfwk/kits/native:cesfwk_kits", + "//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/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + ] + + deps += bundle_install_deps + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":BmsBundleUpdaterTest" ] +} 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 new file mode 100755 index 000000000..b66b20638 --- /dev/null +++ b/services/bundlemgr/test/unittest/bms_bundle_updater_test/bms_bundle_updater_test.cpp @@ -0,0 +1,532 @@ +/* + * 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 "directory_ex.h" +#include "appexecfwk_errors.h" +#include "common_tool.h" +#include "bundle_info.h" +#include "bundle_installer_host.h" +#include "bundle_mgr_service.h" +#include "installd/installd_service.h" +#include "installd_client.h" +#include "mock_status_receiver.h" + +using namespace testing::ext; +using namespace std::chrono_literals; +using namespace OHOS; +using namespace OHOS::AppExecFwk; + +namespace { + +const std::string PACKAGE_NAME = "com.example.l3jsdemo"; +const std::string BUNDLE_NAME = "com.example.l3jsdemo"; +const std::string ERROR_BUNDLE_NAME = "com.example.bundle.update.error"; +const std::string BUNDLE_FILE_DIR = "/data/test/resource/bms/update_bundle/"; +const std::string V1_BUNDLE = "version1.hap"; +const std::string V2_BUNDLE = "version2.hap"; +const std::string V3_BUNDLE = "version3.hap"; +const std::string ERROR_FORMART_BUNDLE = "format_error_profile.hap"; +const std::string BUNDLE_DATA_DIR = "/data/accounts/account_0/appdata/com.example.l3jsdemo"; +const std::string BUNDLE_CODE_DIR = "/data/accounts/account_0/applications/com.example.l3jsdemo"; +const std::string ROOT_DIR = "/data/accounts"; +const std::string PROFILE_FILE = "config.json"; +const std::string SEPARATOR = "/"; +const std::chrono::seconds SLEEP_TIME {2}; +const int32_t ROOT_UID = 0; +const int32_t USERID = 0; +const uint32_t VERSION_1 = 1; +const uint32_t VERSION_2 = 2; +const uint32_t VERSION_3 = 3; +const int32_t MAX_TRY_TIMES = 1000; + +} // namespace + +class BmsBundleUpdaterTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + + const std::shared_ptr GetBundleDataMgr() const; + ErrCode InstallBundle(const std::string &bundlePath) const; + ErrCode UninstallBundle(const std::string &bundleName) const; + ErrCode UpdateBundle(const std::string &bundlePath) const; + ErrCode UpdateBundle(const std::string &bundlePath, const bool needCheckInfo) const; + + void StopInstalldService() const; + void StartInstalldService() const; + void StopBundleService() const; + + void CheckFileExist() const; + bool CheckApplicationInfo() const; + bool CheckBundleInfo(const uint32_t versionCode, const bool needCheckVersion) const; + +private: + std::shared_ptr installdService_ = std::make_unique(); + std::shared_ptr bundleMgrService_ = DelayedSingleton::GetInstance(); +}; + +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"; + } + if (chown(ROOT_DIR.c_str(), ROOT_UID, ROOT_UID) != 0) { + ASSERT_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"; + } +} + +void BmsBundleUpdaterTest::TearDownTestCase() +{} + +void BmsBundleUpdaterTest::SetUp() +{ + installdService_->Start(); + if (!DelayedSingleton::GetInstance()->IsServiceReady()) { + DelayedSingleton::GetInstance()->OnStart(); + } +} + +void BmsBundleUpdaterTest::TearDown() +{ + // reset the case. + UninstallBundle(BUNDLE_NAME); + + StopInstalldService(); + StopBundleService(); + + // clear files. + OHOS::ForceRemoveDirectory(BUNDLE_DATA_DIR); + OHOS::ForceRemoveDirectory(BUNDLE_CODE_DIR); +} + +const std::shared_ptr BmsBundleUpdaterTest::GetBundleDataMgr() const +{ + return bundleMgrService_->GetDataMgr(); +} + +ErrCode BmsBundleUpdaterTest::InstallBundle(const std::string &bundlePath) const +{ + auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); + if (!installer) { + EXPECT_FALSE(true) << "the installer is nullptr"; + return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR; + } + + sptr receiver = new (std::nothrow) MockStatusReceiver(); + if (!receiver) { + EXPECT_FALSE(true) << "the receiver is nullptr"; + return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR; + } + InstallParam installParam; + installParam.installFlag = InstallFlag::NORMAL; + bool result = installer->Install(bundlePath, installParam, receiver); + EXPECT_TRUE(result); + return receiver->GetResultCode(); +} + +ErrCode BmsBundleUpdaterTest::UninstallBundle(const std::string &bundleName) const +{ + auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); + if (!installer) { + EXPECT_FALSE(true) << "the installer is nullptr"; + return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR; + } + + sptr receiver = new (std::nothrow) MockStatusReceiver(); + if (!receiver) { + EXPECT_FALSE(true) << "the receiver is nullptr"; + return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR; + } + InstallParam installParam; + installParam.installFlag = InstallFlag::NORMAL; + bool result = installer->Uninstall(bundleName, installParam, receiver); + EXPECT_TRUE(result); + return receiver->GetResultCode(); +} + +ErrCode BmsBundleUpdaterTest::UpdateBundle(const std::string &bundlePath) const +{ + auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); + if (!installer) { + EXPECT_FALSE(true) << "the installer is nullptr"; + return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR; + } + + sptr receiver = new (std::nothrow) MockStatusReceiver(); + if (!receiver) { + EXPECT_FALSE(true) << "the receiver is nullptr"; + return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR; + } + InstallParam installParam; + installParam.installFlag = InstallFlag::REPLACE_EXISTING; + bool result = installer->Install(bundlePath, installParam, receiver); + EXPECT_TRUE(result); + return receiver->GetResultCode(); +} + +ErrCode BmsBundleUpdaterTest::UpdateBundle(const std::string &bundlePath, const bool needCheckInfo) const +{ + auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); + if (!installer) { + EXPECT_FALSE(true) << "the installer is nullptr"; + return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR; + } + sptr receiver = new (std::nothrow) MockStatusReceiver(); + if (!receiver) { + EXPECT_FALSE(true) << "the receiver is nullptr"; + return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR; + } + InstallParam installParam; + installParam.installFlag = InstallFlag::REPLACE_EXISTING; + bool result = installer->Install(bundlePath, installParam, receiver); + EXPECT_TRUE(result); + + // check can not access the application info between updating. + if (needCheckInfo) { + bool isBlock = false; + for (int32_t i = 0; i < MAX_TRY_TIMES; i++) { + std::this_thread::sleep_for(10ms); + bool isExist = CheckApplicationInfo(); + if (!isExist) { + isBlock = true; + break; + } + } + if (!isBlock) { + EXPECT_FALSE(true) << "the bundle info is not disable during updating"; + return ERR_APPEXECFWK_INSTALL_BUNDLE_MGR_SERVICE_ERROR; + } + } + + return receiver->GetResultCode(); +} + +void BmsBundleUpdaterTest::StopInstalldService() const +{ + installdService_->Stop(); + InstalldClient::GetInstance()->ResetInstalldProxy(); +} + +void BmsBundleUpdaterTest::StartInstalldService() const +{ + installdService_->Start(); +} + +void BmsBundleUpdaterTest::StopBundleService() const +{ + DelayedSingleton::GetInstance()->OnStop(); +} + +void BmsBundleUpdaterTest::CheckFileExist() const +{ + CommonTool tool; + bool isCodeExist = tool.CheckFilePathISExist(BUNDLE_CODE_DIR + SEPARATOR + PACKAGE_NAME); + EXPECT_TRUE(isCodeExist); + bool isDataExist = tool.CheckFilePathISExist(BUNDLE_DATA_DIR + SEPARATOR + PACKAGE_NAME); + EXPECT_TRUE(isDataExist); +} + +bool BmsBundleUpdaterTest::CheckBundleInfo(const uint32_t versionCode, const bool needCheckVersion) const +{ + BundleInfo info; + auto dataMgr = GetBundleDataMgr(); + if (dataMgr == nullptr) { + return false; + } + bool isExist = dataMgr->GetBundleInfo(BUNDLE_NAME, BundleFlag::GET_BUNDLE_DEFAULT, info); + if (!isExist) { + return false; + } + if (needCheckVersion) { + if (info.versionCode != versionCode) { + return false; + } + } + return true; +} + +bool BmsBundleUpdaterTest::CheckApplicationInfo() const +{ + ApplicationInfo info; + auto dataMgr = GetBundleDataMgr(); + if (dataMgr == nullptr) { + return false; + } + bool result = dataMgr->GetApplicationInfo(PACKAGE_NAME, ApplicationFlag::GET_BASIC_APPLICATION_INFO, USERID, info); + return result; +} + +/** + * @tc.number: Update_0100 + * @tc.name: test the same version bundle can be reinstalled + * @tc.desc: 1. the bundle is already installed + * 2. the same version bundle can be reinstalled successfully + */ +HWTEST_F(BmsBundleUpdaterTest, Update_0100, Function | SmallTest | Level2) +{ + ErrCode installResult = InstallBundle(BUNDLE_FILE_DIR + V1_BUNDLE); + ASSERT_EQ(installResult, ERR_OK); + CommonTool tool; + long codeDirFirstCreateTime = tool.GetFileBuildTime(BUNDLE_CODE_DIR.c_str()); + long dataDirFirstCreateTime = tool.GetFileBuildTime(BUNDLE_DATA_DIR.c_str()); + + // need to wait for 1s since the file create time counts in second unit. + std::this_thread::sleep_for(SLEEP_TIME); + + ErrCode updateResult = UpdateBundle(BUNDLE_FILE_DIR + V2_BUNDLE, true); + ASSERT_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); + + bool isExist = CheckBundleInfo(VERSION_2, true); + EXPECT_TRUE(isExist); +} + +/** + * @tc.number: Update_0200 + * @tc.name: test the larger version bundle can be updated + * @tc.desc: 1. the bundle is already installed + * 2. the larger version bundle can be updated successfully + */ +HWTEST_F(BmsBundleUpdaterTest, Update_0200, Function | SmallTest | Level1) +{ + ErrCode installResult = InstallBundle(BUNDLE_FILE_DIR + V2_BUNDLE); + ASSERT_EQ(installResult, ERR_OK); + + ErrCode updateResult = UpdateBundle(BUNDLE_FILE_DIR + V3_BUNDLE); + ASSERT_EQ(updateResult, ERR_OK); + CheckFileExist(); + + bool result = CheckBundleInfo(VERSION_3, true); + EXPECT_TRUE(result); +} + +/** + * @tc.number: Update_0300 + * @tc.name: test the empty path can't be updated + * @tc.desc: 1. the bundle file path is empty + * 2. the bundle can't be updated and the result is fail + */ +HWTEST_F(BmsBundleUpdaterTest, Update_0300, Function | SmallTest | Level0) +{ + ErrCode installResult = InstallBundle(BUNDLE_FILE_DIR + V1_BUNDLE); + ASSERT_EQ(installResult, ERR_OK); + + ErrCode updateResult = UpdateBundle(""); + EXPECT_EQ(updateResult, ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID); +} + +/** + * @tc.number: Update_0400 + * @tc.name: test the wrong path can't be updated + * @tc.desc: 1. the bundle file path is wrong + * 2. the bundle can't be updated and the result is fail + */ +HWTEST_F(BmsBundleUpdaterTest, Update_0400, Function | SmallTest | Level0) +{ + ErrCode installResult = InstallBundle(BUNDLE_FILE_DIR + V1_BUNDLE); + ASSERT_EQ(installResult, ERR_OK); + + ErrCode updateResult = UpdateBundle(BUNDLE_FILE_DIR + ERROR_BUNDLE_NAME); + EXPECT_EQ(updateResult, ERR_APPEXECFWK_INSTALL_INVALID_HAP_NAME); +} + +/** + * @tc.number: Update_0500 + * @tc.name: test the wrong format bundle can't be updated + * @tc.desc: 1. the bundle file is wrong format + * 2. the bundle can't be updated and the result is fail + */ +HWTEST_F(BmsBundleUpdaterTest, Update_0500, Function | SmallTest | Level0) +{ + ErrCode installResult = InstallBundle(BUNDLE_FILE_DIR + V1_BUNDLE); + ASSERT_EQ(installResult, ERR_OK); + + ErrCode updateResult = UpdateBundle(BUNDLE_FILE_DIR + ERROR_FORMART_BUNDLE); + EXPECT_EQ(updateResult, ERR_APPEXECFWK_PARSE_NO_PROFILE); +} + +/** + * @tc.number: Update_0600 + * @tc.name: test the lower version bundle can't be updated + * @tc.desc: 1. the bundle file is the lower version + * 2. the bundle can't be updated and the result is fail + */ +HWTEST_F(BmsBundleUpdaterTest, Update_0600, Function | SmallTest | Level0) +{ + ErrCode installResult = InstallBundle(BUNDLE_FILE_DIR + V2_BUNDLE); + ASSERT_EQ(installResult, ERR_OK); + + ErrCode updateResult = UpdateBundle(BUNDLE_FILE_DIR + V1_BUNDLE); + EXPECT_EQ(updateResult, ERR_APPEXECFWK_INSTALL_VERSION_DOWNGRADE); +} + +/** + * @tc.number: Update_0700 + * @tc.name: test the installd service error case + * @tc.desc: 1. the installd service error + * 2. the update operation will return fail and the next install operation will success after restart installd + * service + */ +HWTEST_F(BmsBundleUpdaterTest, Update_0700, Function | SmallTest | Level1) +{ + ErrCode installResult = InstallBundle(BUNDLE_FILE_DIR + V1_BUNDLE); + ASSERT_EQ(installResult, ERR_OK); + + StopInstalldService(); + ErrCode updateResult = UpdateBundle(BUNDLE_FILE_DIR + V3_BUNDLE); + ASSERT_EQ(updateResult, ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR); + + BundleInfo info; + auto dataMgr = GetBundleDataMgr(); + ASSERT_NE(dataMgr, nullptr); + bool isInfoExist = dataMgr->GetBundleInfo(BUNDLE_NAME, BundleFlag::GET_BUNDLE_DEFAULT, info); + ASSERT_TRUE(isInfoExist); + ASSERT_EQ(info.versionCode, VERSION_1); + + StartInstalldService(); + updateResult = UpdateBundle(BUNDLE_FILE_DIR + V3_BUNDLE); + ASSERT_EQ(updateResult, ERR_OK); + ASSERT_EQ(info.versionCode, VERSION_1); + CheckFileExist(); +} + +/** + * @tc.number: Update_0800 + * @tc.name: test the bundle mgr service error case + * @tc.desc: 1. the bundle mgr service error + * 2. the update operation will return fail and the next install operation will success after restart bundle + * mgr service + */ +HWTEST_F(BmsBundleUpdaterTest, Update_0800, Function | SmallTest | Level1) +{ + ErrCode installResult = InstallBundle(BUNDLE_FILE_DIR + V1_BUNDLE); + ASSERT_EQ(installResult, ERR_OK); + + StopBundleService(); + DelayedSingleton::DestroyInstance(); + + sptr installer = new (std::nothrow) BundleInstallerHost(); + ASSERT_NE(installer, nullptr); + installer->Init(); + sptr receiver = new (std::nothrow) MockStatusReceiver(); + ASSERT_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); + + DelayedSingleton::GetInstance()->OnStart(); + BundleInfo info; + auto dataMgr = GetBundleDataMgr(); + ASSERT_NE(dataMgr, nullptr); + bool isInfoExist = dataMgr->GetBundleInfo(BUNDLE_NAME, BundleFlag::GET_BUNDLE_DEFAULT, info); + ASSERT_TRUE(isInfoExist); + ASSERT_EQ(info.versionCode, VERSION_1); + + ErrCode updateResult = UpdateBundle(BUNDLE_FILE_DIR + V3_BUNDLE); + ASSERT_EQ(updateResult, ERR_OK); + CheckFileExist(); +} + +/** + * @tc.number: Update_0900 + * @tc.name: test when status receiver is null will not update bundle + * @tc.desc: 1. the status receiver is null + * 2. the update bundle operation will not execute when status receiver is null + */ +HWTEST_F(BmsBundleUpdaterTest, Update_0900, Function | SmallTest | Level2) +{ + ErrCode installResult = InstallBundle(BUNDLE_FILE_DIR + V1_BUNDLE); + ASSERT_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); + InstallParam installParam; + installParam.installFlag = InstallFlag::REPLACE_EXISTING; + installer->Install(BUNDLE_FILE_DIR + V2_BUNDLE, installParam, nullptr); + + std::this_thread::sleep_for(50ms); + + 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); + + bool isExist = CheckBundleInfo(VERSION_1, true); + EXPECT_TRUE(isExist); +} + +/** + * @tc.number: Update_1000 + * @tc.name: test the larger version bundle can be installed continuously + * @tc.desc: 1. the bundle is already installed + * 2. the larger version bundle can be installed continuously + */ +HWTEST_F(BmsBundleUpdaterTest, Update_1000, Function | SmallTest | Level2) +{ + ErrCode installResult = InstallBundle(BUNDLE_FILE_DIR + V1_BUNDLE); + ASSERT_EQ(installResult, ERR_OK); + CommonTool tool; + long codeDirFirstCreateTime = tool.GetFileBuildTime(BUNDLE_CODE_DIR.c_str()); + long dataDirFirstCreateTime = tool.GetFileBuildTime(BUNDLE_DATA_DIR.c_str()); + + // need to wait for 1s since the file create time counts in second unit. + std::this_thread::sleep_for(SLEEP_TIME); + + ErrCode updateResult = UpdateBundle(BUNDLE_FILE_DIR + V2_BUNDLE); + ASSERT_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); + + bool isExist = CheckBundleInfo(VERSION_2, true); + EXPECT_TRUE(isExist); + + std::this_thread::sleep_for(SLEEP_TIME); + + updateResult = UpdateBundle(BUNDLE_FILE_DIR + V3_BUNDLE); + ASSERT_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); + + 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 new file mode 100644 index 000000000..04580a5fe --- /dev/null +++ b/services/bundlemgr/test/unittest/bms_data_mgr_test/BUILD.gn @@ -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. + +import("//build/test.gni") +import("//foundation/appexecfwk/standard/appexecfwk.gni") +import( + "//foundation/appexecfwk/standard/services/bundlemgr/appexecfwk_bundlemgr.gni") + +module_output_path = "appexecfwk_standard/bundlemgrservice" + +ohos_unittest("BmsDataMgrTest") { + module_out_path = module_output_path + + sources = [ + "${innerkits_path}/appexecfwk_base/src/ability_info.cpp", + "${innerkits_path}/appexecfwk_base/src/application_info.cpp", + "${innerkits_path}/appexecfwk_base/src/bundle_info.cpp", + "${innerkits_path}/appexecfwk_base/src/element_name.cpp", + "${services_path}/bundlemgr/src/bundle_data_mgr.cpp", + "${services_path}/bundlemgr/src/bundle_data_storage.cpp", + "${services_path}/bundlemgr/src/bundle_status_callback_death_recipient.cpp", + ] + + sources += bundle_install_sources + + sources += [ "bms_data_mgr_test.cpp" ] + + configs = [ + "${services_path}/bundlemgr/test:bundlemgr_test_config", + "${libs_path}/libeventhandler:libeventhandler_config", + "${innerkits_path}/appexecfwk_base:appexecfwk_base_sdk_config", + ] + 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", + "${libs_path}/libeventhandler:libeventhandler_target", + "${services_path}/bundlemgr:bundle_parser", + "${services_path}/bundlemgr:parser_common", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//third_party/googletest:gtest_main", + ] + + deps += bundle_install_deps + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":BmsDataMgrTest" ] +} 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 new file mode 100755 index 000000000..45100eaa6 --- /dev/null +++ b/services/bundlemgr/test/unittest/bms_data_mgr_test/bms_data_mgr_test.cpp @@ -0,0 +1,1015 @@ +/* + * 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 "json_constants.h" +#include "json_serializer.h" +#include "parcel.h" +#include "bundle_data_storage_interface.h" +#include "bundle_data_storage.h" +#include "bundle_data_mgr.h" + +using namespace testing::ext; +using namespace OHOS::AppExecFwk; +using OHOS::Parcel; +using OHOS::AAFwk::Want; + +namespace { + +const std::string BUNDLE_NAME = "com.example.l3jsdemo"; +const std::string APP_NAME = "com.example.l3jsdemo"; +const std::string ABILITY_NAME = "com.example.l3jsdemo.MainAbility"; +const std::string PACKAGE_NAME = "com.example.l3jsdemo"; +const std::string DEVICE_ID = "PHONE-001"; +const std::string LABEL = "hello"; +const std::string DESCRIPTION = "mainEntry"; +const std::string ICON_PATH = "/data/data/icon.png"; +const std::string KIND = "test"; +const AbilityType ABILITY_TYPE = AbilityType::PAGE; +const DisplayOrientation ORIENTATION = DisplayOrientation::PORTRAIT; +const LaunchMode LAUNCH_MODE = LaunchMode::SINGLETON; +const std::string CODE_PATH = "/data/accounts/account_/com.example.l3jsdemo"; +const std::string RESOURCE_PATH = "/data/accounts/account_/com.example.l3jsdemo"; +const std::string LIB_PATH = "/data/accounts/account_/com.example.l3jsdemo"; +const bool VISIBLE = true; +const int32_t USERID = 0; + +} // namespace + +class BmsDataMgrTest : public testing::Test { +public: + BmsDataMgrTest(); + ~BmsDataMgrTest(); + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + const std::shared_ptr GetDataMgr() const; + AbilityInfo GetDefaultAbilityInfo() const; + +private: + std::shared_ptr dataMgr_ = std::make_shared(); +}; + +BmsDataMgrTest::BmsDataMgrTest() +{} + +BmsDataMgrTest::~BmsDataMgrTest() +{} + +void BmsDataMgrTest::SetUpTestCase() +{} + +void BmsDataMgrTest::TearDownTestCase() +{} + +void BmsDataMgrTest::SetUp() +{} + +void BmsDataMgrTest::TearDown() +{ + // create db file + std::ofstream o(Constants::BUNDLE_DATA_BASE_FILE); + dataMgr_->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_SUCCESS); + if (!o.is_open()) { + return; + } + o.close(); +} + +AbilityInfo BmsDataMgrTest::GetDefaultAbilityInfo() const +{ + AbilityInfo abilityInfo; + abilityInfo.package = PACKAGE_NAME; + abilityInfo.name = ABILITY_NAME; + abilityInfo.bundleName = BUNDLE_NAME; + abilityInfo.applicationName = APP_NAME; + abilityInfo.deviceId = DEVICE_ID; + abilityInfo.label = LABEL; + abilityInfo.description = DESCRIPTION; + abilityInfo.iconPath = ICON_PATH; + abilityInfo.visible = VISIBLE; + abilityInfo.kind = KIND; + abilityInfo.type = ABILITY_TYPE; + abilityInfo.orientation = ORIENTATION; + abilityInfo.launchMode = LAUNCH_MODE; + abilityInfo.codePath = CODE_PATH; + abilityInfo.resourcePath = RESOURCE_PATH; + abilityInfo.libPath = LIB_PATH; + return abilityInfo; +} + +const std::shared_ptr BmsDataMgrTest::GetDataMgr() const +{ + return dataMgr_; +} + +/** + * @tc.number: UpdateInstallState_0100 + * @tc.name: UpdateInstallState + * @tc.desc: 1. correct status transfer INSTALL_START->INSTALL_FAIL + * 2. verify function return value + */ +HWTEST_F(BmsDataMgrTest, UpdateInstallState_0100, Function | SmallTest | Level0) +{ + auto dataMgr = GetDataMgr(); + ASSERT_NE(dataMgr, nullptr); + bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); + bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_FAIL); + EXPECT_TRUE(ret1); + EXPECT_TRUE(ret2); +} + +/** + * @tc.number: UpdateInstallState_0200 + * @tc.name: UpdateInstallState + * @tc.desc: 1. correct status transfer INSTALL_START->INSTALL_SUCCESS->UPDATING_START->UPDATING_FAIL + * 2. verify function return value + */ +HWTEST_F(BmsDataMgrTest, UpdateInstallState_0200, Function | SmallTest | Level0) +{ + auto dataMgr = GetDataMgr(); + ASSERT_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); + bool ret4 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UPDATING_FAIL); + EXPECT_TRUE(ret1); + EXPECT_TRUE(ret2); + EXPECT_TRUE(ret3); + EXPECT_TRUE(ret4); +} + +/** + * @tc.number: UpdateInstallState_0300 + * @tc.name: UpdateInstallState + * @tc.desc: 1. correct status transfer INSTALL_START->INSTALL_SUCCESS->UPDATING_START->UPDATING_SUCCESS + * 2. verify function return value + */ +HWTEST_F(BmsDataMgrTest, UpdateInstallState_0300, Function | SmallTest | Level0) +{ + auto dataMgr = GetDataMgr(); + ASSERT_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); + bool ret4 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UPDATING_SUCCESS); + EXPECT_TRUE(ret1); + EXPECT_TRUE(ret2); + EXPECT_TRUE(ret3); + EXPECT_TRUE(ret4); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_START); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_SUCCESS); +} + +/** + * @tc.number: UpdateInstallState_0400 + * @tc.name: UpdateInstallState + * @tc.desc: 1. correct status transfer INSTALL_START->INSTALL_SUCCESS->UNINSTALL_START->UNINSTALL_SUCCESS + * 2. verify function return value + */ +HWTEST_F(BmsDataMgrTest, UpdateInstallState_0400, Function | SmallTest | Level0) +{ + auto dataMgr = GetDataMgr(); + ASSERT_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); + bool ret4 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_SUCCESS); + EXPECT_TRUE(ret1); + EXPECT_TRUE(ret2); + EXPECT_TRUE(ret3); + EXPECT_TRUE(ret4); +} + +/** + * @tc.number: UpdateInstallState_0500 + * @tc.name: UpdateInstallState + * @tc.desc: 1. correct status transfer INSTALL_START->INSTALL_SUCCESS->UNINSTALL_START->UNINSTALL_FAIL + * 2. verify function return value + */ +HWTEST_F(BmsDataMgrTest, UpdateInstallState_0500, Function | SmallTest | Level0) +{ + auto dataMgr = GetDataMgr(); + ASSERT_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); + bool ret4 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_FAIL); + EXPECT_TRUE(ret1); + EXPECT_TRUE(ret2); + EXPECT_TRUE(ret3); + EXPECT_TRUE(ret4); +} + +/** + * @tc.number: UpdateInstallState_0600 + * @tc.name: UpdateInstallState + * @tc.desc: 1. NOT correct status transfer INSTALL_START->INSTALL_START + * 2. verify function return value + */ +HWTEST_F(BmsDataMgrTest, UpdateInstallState_0600, Function | SmallTest | Level0) +{ + auto dataMgr = GetDataMgr(); + ASSERT_NE(dataMgr, nullptr); + bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); + bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); + EXPECT_TRUE(ret1); + EXPECT_FALSE(ret2); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_FAIL); +} + +/** + * @tc.number: UpdateInstallState_0700 + * @tc.name: UpdateInstallState + * @tc.desc: 1. NOT correct status transfer INSTALL_START->UNINSTALL_START + * 2. verify function return value + */ +HWTEST_F(BmsDataMgrTest, UpdateInstallState_0700, Function | SmallTest | Level0) +{ + auto dataMgr = GetDataMgr(); + ASSERT_NE(dataMgr, nullptr); + bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); + bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_START); + EXPECT_TRUE(ret1); + EXPECT_FALSE(ret2); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_FAIL); +} + +/** + * @tc.number: UpdateInstallState_0800 + * @tc.name: UpdateInstallState + * @tc.desc: 1. NOT correct status transfer INSTALL_START->UNINSTALL_SUCCESS + * 2. verify function return value + */ +HWTEST_F(BmsDataMgrTest, UpdateInstallState_0800, Function | SmallTest | Level0) +{ + auto dataMgr = GetDataMgr(); + ASSERT_NE(dataMgr, nullptr); + bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); + bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_SUCCESS); + EXPECT_TRUE(ret1); + EXPECT_FALSE(ret2); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_FAIL); +} + +/** + * @tc.number: UpdateInstallState_0900 + * @tc.name: UpdateInstallState + * @tc.desc: 1. NOT correct status transfer INSTALL_START->UNINSTALL_FAIL + * 2. verify function return value + */ +HWTEST_F(BmsDataMgrTest, UpdateInstallState_0900, Function | SmallTest | Level0) +{ + auto dataMgr = GetDataMgr(); + ASSERT_NE(dataMgr, nullptr); + bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); + bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_FAIL); + EXPECT_TRUE(ret1); + EXPECT_FALSE(ret2); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_FAIL); +} + +/** + * @tc.number: UpdateInstallState_1000 + * @tc.name: UpdateInstallState + * @tc.desc: 1. NOT correct status transfer INSTALL_START->UPDATING_STAR + * 2. verify function return value + */ +HWTEST_F(BmsDataMgrTest, UpdateInstallState_1000, Function | SmallTest | Level0) +{ + auto dataMgr = GetDataMgr(); + ASSERT_NE(dataMgr, nullptr); + bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); + bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UPDATING_START); + EXPECT_TRUE(ret1); + EXPECT_FALSE(ret2); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_FAIL); +} + +/** + * @tc.number: UpdateInstallState_1100 + * @tc.name: UpdateInstallState + * @tc.desc: 1. NOT correct status transfer INSTALL_START->UPDATING_SUCCESS + * 2. verify function return value + */ +HWTEST_F(BmsDataMgrTest, UpdateInstallState_1100, Function | SmallTest | Level0) +{ + auto dataMgr = GetDataMgr(); + ASSERT_NE(dataMgr, nullptr); + bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); + bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UPDATING_SUCCESS); + EXPECT_TRUE(ret1); + EXPECT_FALSE(ret2); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_FAIL); +} + +/** + * @tc.number: UpdateInstallState_1200 + * @tc.name: UpdateInstallState + * @tc.desc: 1. NOT correct status transfer INSTALL_START->UPDATING_FAIL + * 2. verify function return value + */ +HWTEST_F(BmsDataMgrTest, UpdateInstallState_1200, Function | SmallTest | Level0) +{ + auto dataMgr = GetDataMgr(); + ASSERT_NE(dataMgr, nullptr); + bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); + bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UPDATING_FAIL); + EXPECT_TRUE(ret1); + EXPECT_FALSE(ret2); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_FAIL); +} + +/** + * @tc.number: UpdateInstallState_1300 + * @tc.name: UpdateInstallState + * @tc.desc: 1. NOT correct status transfer INSTALL_START->INSTALL_SUCCESS->INSTALL_SUCCESS + * 2. verify function return value + */ +HWTEST_F(BmsDataMgrTest, UpdateInstallState_1300, Function | SmallTest | Level0) +{ + auto dataMgr = GetDataMgr(); + ASSERT_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); + EXPECT_TRUE(ret1); + EXPECT_TRUE(ret2); + EXPECT_FALSE(ret3); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_START); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_SUCCESS); +} + +/** + * @tc.number: UpdateInstallState_1400 + * @tc.name: UpdateInstallState + * @tc.desc: 1. NOT correct status transfer INSTALL_START->INSTALL_SUCCESS->INSTALL_START + * 2. verify function return value + */ +HWTEST_F(BmsDataMgrTest, UpdateInstallState_1400, Function | SmallTest | Level0) +{ + auto dataMgr = GetDataMgr(); + ASSERT_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); + EXPECT_TRUE(ret1); + EXPECT_TRUE(ret2); + EXPECT_FALSE(ret3); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_START); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_SUCCESS); +} + +/** + * @tc.number: UpdateInstallState_1500 + * @tc.name: UpdateInstallState + * @tc.desc: 1. NOT correct status transfer INSTALL_START->INSTALL_SUCCESS->INSTALL_FAIL + * 2. verify function return value + */ +HWTEST_F(BmsDataMgrTest, UpdateInstallState_1500, Function | SmallTest | Level0) +{ + auto dataMgr = GetDataMgr(); + ASSERT_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); + EXPECT_TRUE(ret1); + EXPECT_TRUE(ret2); + EXPECT_FALSE(ret3); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_START); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_SUCCESS); +} + +/** + * @tc.number: UpdateInstallState_1600 + * @tc.name: UpdateInstallState + * @tc.desc: 1. NOT correct status transfer INSTALL_START->INSTALL_SUCCESS->UNINSTALL_SUCCESS + * 2. verify function return value + */ +HWTEST_F(BmsDataMgrTest, UpdateInstallState_1600, Function | SmallTest | Level0) +{ + auto dataMgr = GetDataMgr(); + ASSERT_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); + EXPECT_TRUE(ret1); + EXPECT_TRUE(ret2); + EXPECT_FALSE(ret3); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_START); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_SUCCESS); +} + +/** + * @tc.number: UpdateInstallState_1700 + * @tc.name: UpdateInstallState + * @tc.desc: 1. NOT correct status transfer INSTALL_START->INSTALL_SUCCESS->UNINSTALL_FAIL + * 2. verify function return value + */ +HWTEST_F(BmsDataMgrTest, UpdateInstallState_1700, Function | SmallTest | Level0) +{ + auto dataMgr = GetDataMgr(); + ASSERT_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); + EXPECT_TRUE(ret1); + EXPECT_TRUE(ret2); + EXPECT_FALSE(ret3); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_START); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_SUCCESS); +} + +/** + * @tc.number: UpdateInstallState_1800 + * @tc.name: UpdateInstallState + * @tc.desc: 1. NOT correct status transfer INSTALL_START->INSTALL_SUCCESS->UPDATING_FAIL + * 2. verify function return value + */ +HWTEST_F(BmsDataMgrTest, UpdateInstallState_1800, Function | SmallTest | Level0) +{ + auto dataMgr = GetDataMgr(); + ASSERT_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); + EXPECT_TRUE(ret1); + EXPECT_TRUE(ret2); + EXPECT_FALSE(ret3); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_START); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_SUCCESS); +} + +/** + * @tc.number: UpdateInstallState_1900 + * @tc.name: UpdateInstallState + * @tc.desc: 1. NOT correct status transfer INSTALL_START->INSTALL_SUCCESS->UPDATING_SUCCESS + * 2. verify function return value + */ +HWTEST_F(BmsDataMgrTest, UpdateInstallState_1900, Function | SmallTest | Level0) +{ + auto dataMgr = GetDataMgr(); + ASSERT_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); + EXPECT_TRUE(ret1); + EXPECT_TRUE(ret2); + EXPECT_FALSE(ret3); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_START); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_SUCCESS); +} + +/** + * @tc.number: UpdateInstallState_2000 + * @tc.name: UpdateInstallState + * @tc.desc: 1. empty bundle name + * 2. verify function return value + */ +HWTEST_F(BmsDataMgrTest, UpdateInstallState_2000, Function | SmallTest | Level0) +{ + auto dataMgr = GetDataMgr(); + ASSERT_NE(dataMgr, nullptr); + bool ret1 = dataMgr->UpdateBundleInstallState("", InstallState::INSTALL_START); + EXPECT_FALSE(ret1); +} + +/** + * @tc.number: LoadDataFromPersistentStorage_0100 + * @tc.name: LoadDataFromPersistentStorage + * @tc.desc: 1. NA + * 2. load data from persistent storage + */ +HWTEST_F(BmsDataMgrTest, LoadDataFromPersistentStorage_0100, Function | SmallTest | Level0) +{ + auto dataMgr = GetDataMgr(); + ASSERT_NE(dataMgr, nullptr); + bool ret1 = dataMgr->LoadDataFromPersistentStorage(); + EXPECT_FALSE(ret1); + + InnerBundleInfo info; + BundleInfo bundleInfo; + bundleInfo.name = BUNDLE_NAME; + bundleInfo.applicationInfo.name = APP_NAME; + ApplicationInfo applicationInfo; + applicationInfo.name = BUNDLE_NAME; + info.SetBaseBundleInfo(bundleInfo); + info.SetBaseApplicationInfo(applicationInfo); + + std::shared_ptr dataStorage_ = std::make_shared(); + dataStorage_->SaveStorageBundleInfo(Constants::CURRENT_DEVICE_ID, info); + + bool ret2 = dataMgr->LoadDataFromPersistentStorage(); + EXPECT_TRUE(ret2); +} + +/** + * @tc.number: AddBundleInfo_0100 + * @tc.name: AddBundleInfo + * @tc.desc: 1. add info to the data manager + * 2. query data then verify + */ +HWTEST_F(BmsDataMgrTest, AddBundleInfo_0100, Function | SmallTest | Level0) +{ + InnerBundleInfo info; + BundleInfo bundleInfo; + bundleInfo.name = BUNDLE_NAME; + bundleInfo.applicationInfo.name = APP_NAME; + ApplicationInfo applicationInfo; + applicationInfo.name = BUNDLE_NAME; + applicationInfo.deviceId = DEVICE_ID; + info.SetBaseBundleInfo(bundleInfo); + info.SetBaseApplicationInfo(applicationInfo); + auto dataMgr = GetDataMgr(); + ASSERT_NE(dataMgr, nullptr); + InnerBundleInfo info1; + 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); + bool ret4 = dataMgr->GetInnerBundleInfo(BUNDLE_NAME, DEVICE_ID, info1); + EXPECT_TRUE(ret1); + EXPECT_TRUE(ret2); + EXPECT_TRUE(ret3); + EXPECT_TRUE(ret4); + + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_START); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_SUCCESS); +} + +/** + * @tc.number: AddBundleInfo_0200 + * @tc.name: AddBundleInfo + * @tc.desc: 1. add info to the data manager + * 2. query data then verify + */ +HWTEST_F(BmsDataMgrTest, AddBundleInfo_0200, Function | SmallTest | Level0) +{ + InnerBundleInfo info1; + BundleInfo bundleInfo1; + bundleInfo1.name = BUNDLE_NAME; + bundleInfo1.applicationInfo.name = APP_NAME; + bundleInfo1.applicationInfo.bundleName = BUNDLE_NAME; + ApplicationInfo applicationInfo1; + applicationInfo1.name = BUNDLE_NAME; + applicationInfo1.deviceId = DEVICE_ID; + info1.SetBaseBundleInfo(bundleInfo1); + info1.SetBaseApplicationInfo(applicationInfo1); + + InnerBundleInfo info2; + BundleInfo bundleInfo2; + bundleInfo2.name = BUNDLE_NAME; + bundleInfo2.applicationInfo.name = APP_NAME; + bundleInfo2.applicationInfo.bundleName = BUNDLE_NAME; + ApplicationInfo applicationInfo2; + applicationInfo2.name = BUNDLE_NAME; + applicationInfo2.deviceId = DEVICE_ID; + info2.SetBaseBundleInfo(bundleInfo2); + info2.SetBaseApplicationInfo(applicationInfo2); + auto dataMgr = GetDataMgr(); + ASSERT_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); + bool ret4 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UPDATING_START); + bool ret5 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UPDATING_SUCCESS); + bool ret6 = dataMgr->UpdateInnerBundleInfo(BUNDLE_NAME, info2, info1); + bool ret7 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_SUCCESS); + EXPECT_TRUE(ret1); + EXPECT_TRUE(ret2); + EXPECT_TRUE(ret3); + EXPECT_TRUE(ret4); + EXPECT_TRUE(ret5); + EXPECT_TRUE(ret6); + EXPECT_TRUE(ret7); + + ApplicationInfo appInfo; + bool ret8 = dataMgr->GetApplicationInfo(BUNDLE_NAME, ApplicationFlag::GET_BASIC_APPLICATION_INFO, USERID, appInfo); + EXPECT_TRUE(ret8); + + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_START); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_SUCCESS); +} + +/** + * @tc.number: AddBundleInfo_0300 + * @tc.name: AddBundleInfo + * @tc.desc: 1. scan dir not exist + * 2. verify scan result file number is 0 + */ +HWTEST_F(BmsDataMgrTest, AddBundleInfo_0300, Function | SmallTest | Level0) +{ + auto dataMgr = GetDataMgr(); + ASSERT_NE(dataMgr, nullptr); + InnerBundleInfo info; + bool ret = dataMgr->AddInnerBundleInfo("", info); + EXPECT_FALSE(ret); +} + +/** + * @tc.number: AddBundleInfo_0400 + * @tc.name: AddBundleInfo + * @tc.desc: 1. add info to the data manager, then uninstall, then reinstall + * 2. query data then verify + */ +HWTEST_F(BmsDataMgrTest, AddBundleInfo_0400, Function | SmallTest | Level0) +{ + InnerBundleInfo info; + BundleInfo bundleInfo; + bundleInfo.name = BUNDLE_NAME; + bundleInfo.applicationInfo.name = APP_NAME; + ApplicationInfo applicationInfo; + applicationInfo.name = BUNDLE_NAME; + applicationInfo.deviceId = DEVICE_ID; + info.SetBaseBundleInfo(bundleInfo); + info.SetBaseApplicationInfo(applicationInfo); + auto dataMgr = GetDataMgr(); + ASSERT_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); + EXPECT_TRUE(ret1); + EXPECT_TRUE(ret2); + EXPECT_TRUE(ret3); + + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_START); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_SUCCESS); + bool ret4 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); + bool ret5 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_SUCCESS); + bool ret6 = dataMgr->AddInnerBundleInfo(BUNDLE_NAME, info); + EXPECT_TRUE(ret4); + EXPECT_TRUE(ret5); + EXPECT_TRUE(ret6); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_START); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_SUCCESS); +} + +/** + * @tc.number: AddBundleInfo_0500 + * @tc.name: AddBundleInfo + * @tc.desc: 1. add module info to the data manager + * 2. query data then verify + */ +HWTEST_F(BmsDataMgrTest, AddBundleInfo_0500, Function | SmallTest | Level0) +{ + InnerBundleInfo info1; + BundleInfo bundleInfo1; + bundleInfo1.name = BUNDLE_NAME; + bundleInfo1.applicationInfo.name = APP_NAME; + bundleInfo1.applicationInfo.bundleName = BUNDLE_NAME; + ApplicationInfo applicationInfo1; + applicationInfo1.name = BUNDLE_NAME; + applicationInfo1.deviceId = DEVICE_ID; + info1.SetBaseBundleInfo(bundleInfo1); + info1.SetBaseApplicationInfo(applicationInfo1); + + InnerBundleInfo info2; + BundleInfo bundleInfo2; + bundleInfo2.name = BUNDLE_NAME; + bundleInfo2.applicationInfo.name = APP_NAME; + bundleInfo2.applicationInfo.bundleName = BUNDLE_NAME; + ApplicationInfo applicationInfo2; + applicationInfo2.name = BUNDLE_NAME; + applicationInfo2.deviceId = DEVICE_ID; + info2.SetBaseBundleInfo(bundleInfo2); + info2.SetBaseApplicationInfo(applicationInfo2); + + InnerBundleInfo info3; + InnerBundleInfo info4; + auto dataMgr = GetDataMgr(); + ASSERT_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); + bool ret4 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UPDATING_START); + bool ret5 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UPDATING_SUCCESS); + bool ret6 = dataMgr->AddNewModuleInfo(BUNDLE_NAME, info2, info1); + bool ret7 = dataMgr->GetInnerBundleInfo(BUNDLE_NAME, DEVICE_ID, info3); + bool ret8 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_SUCCESS); + bool ret9 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UPDATING_START); + bool ret10 = dataMgr->RemoveModuleInfo(BUNDLE_NAME, PACKAGE_NAME, info1); + bool ret11 = dataMgr->GetInnerBundleInfo(BUNDLE_NAME, DEVICE_ID, info4); + EXPECT_TRUE(ret1); + EXPECT_TRUE(ret2); + EXPECT_TRUE(ret3); + EXPECT_TRUE(ret4); + EXPECT_TRUE(ret5); + EXPECT_TRUE(ret6); + EXPECT_TRUE(ret7); + EXPECT_TRUE(ret8); + EXPECT_TRUE(ret9); + EXPECT_TRUE(ret10); + EXPECT_TRUE(ret11); + + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_START); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_SUCCESS); +} + +/** + * @tc.number: GenerateUidAndGid_0100 + * @tc.name: GenerateUidAndGid + * @tc.desc: 1. app type is system app + * 2. generate uid and gid then verify + */ +HWTEST_F(BmsDataMgrTest, GenerateUidAndGid_0100, Function | SmallTest | Level0) +{ + InnerBundleInfo info; + BundleInfo bundleInfo; + bundleInfo.name = BUNDLE_NAME; + bundleInfo.applicationInfo.name = APP_NAME; + ApplicationInfo applicationInfo; + applicationInfo.name = BUNDLE_NAME; + applicationInfo.deviceId = DEVICE_ID; + info.SetBaseBundleInfo(bundleInfo); + info.SetBaseApplicationInfo(applicationInfo); + info.SetAppType(Constants::AppType::SYSTEM_APP); + auto dataMgr = GetDataMgr(); + ASSERT_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); + bool ret4 = dataMgr->GenerateUidAndGid(info); + EXPECT_TRUE(ret1); + EXPECT_TRUE(ret2); + EXPECT_TRUE(ret3); + EXPECT_TRUE(ret4); + + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_START); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_SUCCESS); +} + +/** + * @tc.number: GenerateUidAndGid_0200 + * @tc.name: GenerateUidAndGid + * @tc.desc: 1. app type is third party app + * 2. generate uid and gid then verify + */ +HWTEST_F(BmsDataMgrTest, GenerateUidAndGid_0200, Function | SmallTest | Level0) +{ + InnerBundleInfo info; + BundleInfo bundleInfo; + bundleInfo.name = BUNDLE_NAME; + bundleInfo.applicationInfo.name = APP_NAME; + ApplicationInfo applicationInfo; + applicationInfo.name = BUNDLE_NAME; + applicationInfo.deviceId = DEVICE_ID; + info.SetBaseBundleInfo(bundleInfo); + info.SetBaseApplicationInfo(applicationInfo); + info.SetAppType(Constants::AppType::THIRD_SYSTEM_APP); + auto dataMgr = GetDataMgr(); + ASSERT_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); + bool ret4 = dataMgr->GenerateUidAndGid(info); + EXPECT_TRUE(ret1); + EXPECT_TRUE(ret2); + EXPECT_TRUE(ret3); + EXPECT_TRUE(ret4); + + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_START); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_SUCCESS); +} + +/** + * @tc.number: GenerateUidAndGid_0300 + * @tc.name: GenerateUidAndGid + * @tc.desc: 1. app type is third party app + * 2. generate uid and gid then verify + */ +HWTEST_F(BmsDataMgrTest, GenerateUidAndGid_0300, Function | SmallTest | Level0) +{ + InnerBundleInfo info; + BundleInfo bundleInfo; + bundleInfo.name = BUNDLE_NAME; + bundleInfo.applicationInfo.name = APP_NAME; + ApplicationInfo applicationInfo; + applicationInfo.name = BUNDLE_NAME; + applicationInfo.deviceId = DEVICE_ID; + info.SetBaseBundleInfo(bundleInfo); + info.SetBaseApplicationInfo(applicationInfo); + info.SetAppType(Constants::AppType::THIRD_PARTY_APP); + auto dataMgr = GetDataMgr(); + ASSERT_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); + bool ret4 = dataMgr->GenerateUidAndGid(info); + EXPECT_TRUE(ret1); + EXPECT_TRUE(ret2); + EXPECT_TRUE(ret3); + EXPECT_TRUE(ret4); + + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_START); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_SUCCESS); +} + +/** + * @tc.number: QueryAbilityInfo_0100 + * @tc.name: QueryAbilityInfo + * @tc.desc: 1. add info to the data manager + * 2. query data then verify + */ +HWTEST_F(BmsDataMgrTest, QueryAbilityInfo_0100, Function | SmallTest | Level0) +{ + InnerBundleInfo info1; + BundleInfo bundleInfo1; + bundleInfo1.name = BUNDLE_NAME; + bundleInfo1.applicationInfo.name = APP_NAME; + bundleInfo1.applicationInfo.bundleName = BUNDLE_NAME; + ApplicationInfo applicationInfo1; + applicationInfo1.name = BUNDLE_NAME; + + AbilityInfo abilityInfo = GetDefaultAbilityInfo(); + bundleInfo1.abilityInfos.push_back(abilityInfo); + info1.SetBaseBundleInfo(bundleInfo1); + info1.SetBaseApplicationInfo(applicationInfo1); + info1.InsertAbilitiesInfo(BUNDLE_NAME + PACKAGE_NAME + ABILITY_NAME, abilityInfo); + auto dataMgr = GetDataMgr(); + ASSERT_NE(dataMgr, nullptr); + bool ret1 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_START); + EXPECT_TRUE(ret1); + bool ret2 = dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::INSTALL_SUCCESS); + EXPECT_TRUE(ret2); + bool ret3 = dataMgr->AddInnerBundleInfo(BUNDLE_NAME, info1); + EXPECT_TRUE(ret3); + + Want want; + ElementName name; + name.SetAbilityName(ABILITY_NAME); + name.SetBundleName(BUNDLE_NAME); + want.SetElement(name); + + AbilityInfo abilityInfo2; + bool ret4 = dataMgr->QueryAbilityInfo(want, abilityInfo2); + EXPECT_TRUE(ret4); + + Parcel parcel; + parcel.WriteParcelable(&abilityInfo); + std::unique_ptr abilityInfo3; + abilityInfo3.reset(parcel.ReadParcelable()); + + EXPECT_EQ(abilityInfo3->package, abilityInfo2.package); + EXPECT_EQ(abilityInfo3->name, abilityInfo2.name); + EXPECT_EQ(abilityInfo3->bundleName, abilityInfo2.bundleName); + EXPECT_EQ(abilityInfo3->applicationName, abilityInfo2.applicationName); + EXPECT_EQ(abilityInfo3->deviceId, abilityInfo2.deviceId); + EXPECT_EQ(abilityInfo3->label, abilityInfo2.label); + EXPECT_EQ(abilityInfo3->description, abilityInfo2.description); + EXPECT_EQ(abilityInfo3->iconPath, abilityInfo2.iconPath); + EXPECT_EQ(abilityInfo3->visible, abilityInfo2.visible); + EXPECT_EQ(abilityInfo3->kind, abilityInfo2.kind); + EXPECT_EQ(abilityInfo3->type, abilityInfo2.type); + EXPECT_EQ(abilityInfo3->orientation, abilityInfo2.orientation); + EXPECT_EQ(abilityInfo3->launchMode, abilityInfo2.launchMode); + EXPECT_EQ(abilityInfo3->codePath, abilityInfo2.codePath); + EXPECT_EQ(abilityInfo3->resourcePath, abilityInfo2.resourcePath); + EXPECT_EQ(abilityInfo3->libPath, abilityInfo2.libPath); + + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_START); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_SUCCESS); +} + +/** + * @tc.number: QueryAbilityInfo_0200 + * @tc.name: QueryAbilityInfo + * @tc.desc: 1. add info to the data manager + * 2. query data then verify + */ +HWTEST_F(BmsDataMgrTest, QueryAbilityInfo_0200, Function | SmallTest | Level0) +{ + Want want; + ElementName name; + name.SetAbilityName(ABILITY_NAME); + want.SetElement(name); + auto dataMgr = GetDataMgr(); + ASSERT_NE(dataMgr, nullptr); + AbilityInfo abilityInfo; + bool ret = dataMgr->QueryAbilityInfo(want, abilityInfo); + EXPECT_FALSE(ret); +} + +/** + * @tc.number: QueryAbilityInfo_0300 + * @tc.name: QueryAbilityInfo + * @tc.desc: 1. add info to the data manager + * 2. query data then verify + */ +HWTEST_F(BmsDataMgrTest, QueryAbilityInfo_0300, Function | SmallTest | Level0) +{ + Want want; + ElementName element1; + EXPECT_EQ("//", element1.GetURI()); + + element1.SetDeviceID(DEVICE_ID); + EXPECT_EQ(DEVICE_ID, element1.GetDeviceID()); + + element1.SetBundleName(BUNDLE_NAME); + EXPECT_EQ(BUNDLE_NAME, element1.GetBundleName()); + + element1.SetAbilityName(ABILITY_NAME); + EXPECT_EQ(ABILITY_NAME, element1.GetAbilityName()); + EXPECT_EQ(DEVICE_ID + "/" + BUNDLE_NAME + "/" + ABILITY_NAME, element1.GetURI()); + + ElementName element2(DEVICE_ID, BUNDLE_NAME, ABILITY_NAME); + EXPECT_EQ(DEVICE_ID + "/" + BUNDLE_NAME + "/" + ABILITY_NAME, element2.GetURI()); + + bool equal = (element2 == element1); + EXPECT_TRUE(equal); + + Parcel parcel; + parcel.WriteParcelable(&element1); + std::unique_ptr newElement; + newElement.reset(parcel.ReadParcelable()); + EXPECT_EQ(newElement->GetDeviceID(), element1.GetDeviceID()); + EXPECT_EQ(newElement->GetBundleName(), element1.GetBundleName()); + EXPECT_EQ(newElement->GetAbilityName(), element1.GetAbilityName()); + + want.SetElement(element1); + auto dataMgr = GetDataMgr(); + ASSERT_NE(dataMgr, nullptr); + AbilityInfo abilityInfo; + bool ret = dataMgr->QueryAbilityInfo(want, abilityInfo); + EXPECT_FALSE(ret); +} + +/** + * @tc.number: GetApplicationInfo_0100 + * @tc.name: GetApplicationInfo + * @tc.desc: 1. add info to the data manager + * 2. query data then verify + */ +HWTEST_F(BmsDataMgrTest, GetApplicationInfo_0100, Function | SmallTest | Level0) +{ + InnerBundleInfo info1; + BundleInfo bundleInfo1; + bundleInfo1.name = BUNDLE_NAME; + bundleInfo1.applicationInfo.name = APP_NAME; + bundleInfo1.applicationInfo.bundleName = BUNDLE_NAME; + ApplicationInfo applicationInfo1; + applicationInfo1.name = BUNDLE_NAME; + info1.SetBaseBundleInfo(bundleInfo1); + info1.SetBaseApplicationInfo(applicationInfo1); + auto dataMgr = GetDataMgr(); + ASSERT_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); + + ApplicationInfo appInfo; + bool ret4 = dataMgr->GetApplicationInfo(APP_NAME, ApplicationFlag::GET_BASIC_APPLICATION_INFO, USERID, appInfo); + std::string name = appInfo.name; + EXPECT_TRUE(ret1); + EXPECT_TRUE(ret2); + EXPECT_TRUE(ret3); + EXPECT_TRUE(ret4); + EXPECT_EQ(name, APP_NAME); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_START); + dataMgr->UpdateBundleInstallState(BUNDLE_NAME, InstallState::UNINSTALL_SUCCESS); +} + +/** + * @tc.number: GetApplicationInfo_0200 + * @tc.name: GetApplicationInfo + * @tc.desc: 1. add info to the data manager + * 2. query data then verify + */ +HWTEST_F(BmsDataMgrTest, GetApplicationInfo_0200, Function | SmallTest | Level0) +{ + ApplicationInfo appInfo; + appInfo.name = APP_NAME; + appInfo.bundleName = BUNDLE_NAME; + appInfo.deviceId = DEVICE_ID; + + Parcel parcel; + parcel.WriteParcelable(&appInfo); + std::unique_ptr appInfo2; + appInfo2.reset(parcel.ReadParcelable()); + EXPECT_EQ(appInfo.name, appInfo2->name); + EXPECT_EQ(appInfo.bundleName, appInfo2->bundleName); + EXPECT_EQ(appInfo.deviceId, appInfo2->deviceId); + auto dataMgr = GetDataMgr(); + ASSERT_NE(dataMgr, nullptr); + ApplicationInfo appInfo3; + bool ret = dataMgr->GetApplicationInfo(BUNDLE_NAME, ApplicationFlag::GET_BASIC_APPLICATION_INFO, USERID, appInfo3); + EXPECT_FALSE(ret); + + EXPECT_NE(appInfo.name, appInfo3.name); + EXPECT_NE(appInfo.bundleName, appInfo3.bundleName); + EXPECT_NE(appInfo.deviceId, appInfo3.deviceId); +} \ No newline at end of file diff --git a/services/bundlemgr/test/unittest/bms_install_daemon_test/BUILD.gn b/services/bundlemgr/test/unittest/bms_install_daemon_test/BUILD.gn new file mode 100644 index 000000000..f36436d03 --- /dev/null +++ b/services/bundlemgr/test/unittest/bms_install_daemon_test/BUILD.gn @@ -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. + +import("//build/test.gni") +import("//foundation/appexecfwk/standard/appexecfwk.gni") +import( + "//foundation/appexecfwk/standard/services/bundlemgr/appexecfwk_bundlemgr.gni") + +module_output_path = "appexecfwk_standard/bundlemgrservice" + +ohos_unittest("BmsInstallDaemonTest") { + module_out_path = module_output_path + + sources = [ + "${services_path}/bundlemgr/src/installd_death_recipient.cpp", + "${services_path}/bundlemgr/test/mock/src/system_ability_helper.cpp", + ] + + sources += install_daemon_sources + + sources += [ "bms_install_daemon_test.cpp" ] + + configs = [ "${services_path}/bundlemgr/test:bundlemgr_test_config" ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${common_path}:libappexecfwk_common", + "${innerkits_path}/appexecfwk_core:appexecfwk_core", + "${services_path}/bundlemgr:bundle_parser", + "${services_path}/bundlemgr:parser_common", + "//third_party/googletest:gtest_main", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":BmsInstallDaemonTest" ] +} 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 new file mode 100755 index 000000000..f644149bc --- /dev/null +++ b/services/bundlemgr/test/unittest/bms_install_daemon_test/bms_install_daemon_test.cpp @@ -0,0 +1,533 @@ +/* + * 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 "directory_ex.h" +#include "installd/installd_service.h" +#include "installd_client.h" + +using namespace testing::ext; +using namespace OHOS::AppExecFwk; +using namespace OHOS; + +namespace { + +const std::string BUNDLE_FILE = "/data/test/resource/bms/install_daemon/right.hap"; +const std::string SYSTEM_DIR = "/sys/com.example.l3jsdemo"; +const std::string TEMP_DIR = "/data/accounts/account_0/applications/com.example.l3jsdemo/temp"; +const std::string MODULE_DIR = "/data/accounts/account_0/applications/com.example.l3jsdemo/com.example.l3jsdemo"; +const std::string BUNDLE_DATA_DIR = "/data/accounts/account_0/appdata/com.example.l3jsdemo"; +const std::string BUNDLE_CODE_DIR = "/data/accounts/account_0/applications/com.example.l3jsdemo"; +const std::string ROOT_DIR = "/data/accounts"; +const int32_t ROOT_UID = 0; +const int32_t UID = 1000; +const int32_t GID = 1000; + +} // namespace + +class BmsInstallDaemonTest : public testing::Test { +public: + BmsInstallDaemonTest(); + ~BmsInstallDaemonTest(); + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + + int CreateBundleDir(const std::string &bundleDir) const; + int CreateBundleDataDir(const std::string &bundleDir, const int32_t uid, const int32_t gid) const; + int RemoveBundleDir(const std::string &bundleDir) const; + int RemoveBundleDataDir(const std::string &bundleDataDir) const; + int CleanBundleDataDir(const std::string &bundleDataDir) const; + int ExtractModuleFiles(const std::string &srcModulePath, const std::string &targetPath) const; + int RenameModuleDir(const std::string &oldPath, const std::string &newPath) const; + bool CheckBundleDirExist() const; + bool CheckBundleDataDirExist() const; + +private: + std::shared_ptr service_ = std::make_shared(); +}; + +BmsInstallDaemonTest::BmsInstallDaemonTest() +{} + +BmsInstallDaemonTest::~BmsInstallDaemonTest() +{} + +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"; + } + if (chown(ROOT_DIR.c_str(), ROOT_UID, ROOT_UID) != 0) { + ASSERT_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"; + } +} + +void BmsInstallDaemonTest::TearDownTestCase() +{} + +void BmsInstallDaemonTest::SetUp() +{} + +void BmsInstallDaemonTest::TearDown() +{ + // clear files. + OHOS::ForceRemoveDirectory(BUNDLE_CODE_DIR); + OHOS::ForceRemoveDirectory(BUNDLE_DATA_DIR); + + if (service_->IsServiceReady()) { + service_->Stop(); + InstalldClient::GetInstance()->ResetInstalldProxy(); + } +} + +int BmsInstallDaemonTest::CreateBundleDir(const std::string &bundleDir) const +{ + if (!service_->IsServiceReady()) { + service_->Start(); + } + return InstalldClient::GetInstance()->CreateBundleDir(bundleDir); +} + +int BmsInstallDaemonTest::CreateBundleDataDir( + const std::string &bundleDataDir, const int32_t uid, const int32_t gid) const +{ + if (!service_->IsServiceReady()) { + service_->Start(); + } + return InstalldClient::GetInstance()->CreateBundleDataDir(bundleDataDir, uid, gid); +} + +int BmsInstallDaemonTest::RemoveBundleDir(const std::string &bundleDir) const +{ + if (!service_->IsServiceReady()) { + service_->Start(); + } + return InstalldClient::GetInstance()->RemoveBundleDir(bundleDir); +} + +int BmsInstallDaemonTest::RemoveBundleDataDir(const std::string &bundleDataDir) const +{ + if (!service_->IsServiceReady()) { + service_->Start(); + } + return InstalldClient::GetInstance()->RemoveBundleDataDir(bundleDataDir); +} + +int BmsInstallDaemonTest::CleanBundleDataDir(const std::string &bundleDataDir) const +{ + if (!service_->IsServiceReady()) { + service_->Start(); + } + return InstalldClient::GetInstance()->CleanBundleDataDir(bundleDataDir); +} + +int BmsInstallDaemonTest::ExtractModuleFiles(const std::string &srcModulePath, const std::string &targetPath) const +{ + if (!service_->IsServiceReady()) { + service_->Start(); + } + return InstalldClient::GetInstance()->ExtractModuleFiles(srcModulePath, targetPath); +} + +int BmsInstallDaemonTest::RenameModuleDir(const std::string &oldPath, const std::string &newPath) const +{ + if (!service_->IsServiceReady()) { + service_->Start(); + } + return InstalldClient::GetInstance()->RenameModuleDir(oldPath, newPath); +} + +bool BmsInstallDaemonTest::CheckBundleDirExist() const +{ + int bundleCodeExist = access(BUNDLE_CODE_DIR.c_str(), F_OK); + if (bundleCodeExist == 0) { + return true; + } + return false; +} + +bool BmsInstallDaemonTest::CheckBundleDataDirExist() const +{ + int bundleDataExist = access(BUNDLE_DATA_DIR.c_str(), F_OK); + if (bundleDataExist == 0) { + return true; + } + return false; +} + +/** +* @tc.number: Startup_0100 +* @tc.name: test the start function of the installd service when service is not ready +* @tc.desc: 1. the service is not initialized +* 2. the non initialized installd service can be started +*/ +HWTEST_F(BmsInstallDaemonTest, Startup_0100, Function | SmallTest | Level0) +{ + std::shared_ptr installdService = std::make_shared(); + ASSERT_NE(installdService, nullptr); + bool ready = installdService->IsServiceReady(); + ASSERT_EQ(false, ready); + installdService->Start(); + ready = installdService->IsServiceReady(); + EXPECT_EQ(true, ready); +} + +/** +* @tc.number: Startup_0200 +* @tc.name: test the stop function of the installd service when service is ready +* @tc.desc: 1. the service is already initialized +* 2. the initialized installd service can be stopped +*/ +HWTEST_F(BmsInstallDaemonTest, Startup_0200, Function | SmallTest | Level0) +{ + std::shared_ptr installdService = std::make_shared(); + ASSERT_NE(installdService, nullptr); + installdService->Start(); + bool ready = installdService->IsServiceReady(); + ASSERT_EQ(true, ready); + installdService->Stop(); + ready = installdService->IsServiceReady(); + EXPECT_EQ(false, ready); +} + +/** +* @tc.number: Startup_0300 +* @tc.name: test the restart function of the installd service +* @tc.desc: 1. the service is already initialized +* 2. the stopped installd service can be restarted +*/ +HWTEST_F(BmsInstallDaemonTest, Startup_0300, Function | SmallTest | Level0) +{ + std::shared_ptr installdService = std::make_shared(); + ASSERT_NE(installdService, nullptr); + installdService->Start(); + bool ready = installdService->IsServiceReady(); + ASSERT_EQ(true, ready); + installdService->Stop(); + ready = installdService->IsServiceReady(); + ASSERT_EQ(false, ready); + installdService->Start(); + ready = installdService->IsServiceReady(); + EXPECT_EQ(true, ready); +} + +/** +* @tc.number: Startup_0400 +* @tc.name: test the restart function of the installd service which is already initialized +* @tc.desc: 1. the service is already initialized +* 2. the recall start function will not affect the initialized installd service +*/ +HWTEST_F(BmsInstallDaemonTest, Startup_0400, Function | SmallTest | Level0) +{ + std::shared_ptr installdService = std::make_shared(); + ASSERT_NE(installdService, nullptr); + installdService->Start(); + bool ready = installdService->IsServiceReady(); + ASSERT_EQ(true, ready); + installdService->Start(); + ready = installdService->IsServiceReady(); + EXPECT_EQ(true, ready); +} + +/** +* @tc.number: Communication_0100 +* @tc.name: test the communication of the installd service and installd client +* @tc.desc: 1. the service is already initialized +* 2. the installd client can send msg to the service and receive the right result +*/ +HWTEST_F(BmsInstallDaemonTest, Communication_0100, Function | SmallTest | Level0) +{ + int result = CreateBundleDir(BUNDLE_CODE_DIR); + EXPECT_EQ(result, 0); +} + +/** +* @tc.number: Communication_0200 +* @tc.name: test the communication of the installd service and installd client +* @tc.desc: 1. the service is not initialized +* 2. the installd client can't send msg to the service and receive the error result +*/ +HWTEST_F(BmsInstallDaemonTest, Communication_0200, Function | SmallTest | Level0) +{ + std::shared_ptr installdService = std::make_shared(); + ASSERT_NE(installdService, nullptr); + bool ready = installdService->IsServiceReady(); + ASSERT_EQ(false, ready); + InstalldClient::GetInstance()->ResetInstalldProxy(); + int result = InstalldClient::GetInstance()->CreateBundleDir(BUNDLE_CODE_DIR); + EXPECT_EQ(result, ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR); +} + +/** +* @tc.number: Communication_0300 +* @tc.name: test the communication of the installd service and installd client +* @tc.desc: 1. the service is already initialized +* 2. the installd client can send msg to the service and receive the right result +*/ +HWTEST_F(BmsInstallDaemonTest, Communication_0300, Function | SmallTest | Level0) +{ + int result = CreateBundleDataDir(BUNDLE_DATA_DIR, UID, GID); + EXPECT_EQ(result, 0); +} + +/** +* @tc.number: Communication_0400 +* @tc.name: test the communication of the installd service and installd client +* @tc.desc: 1. the service is not initialized +* 2. the installd client can't send msg to the service and receive the error result +*/ +HWTEST_F(BmsInstallDaemonTest, Communication_0400, Function | SmallTest | Level0) +{ + std::shared_ptr installdService = std::make_shared(); + ASSERT_NE(installdService, nullptr); + bool ready = installdService->IsServiceReady(); + ASSERT_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); +} + +/** +* @tc.number:BundleDir_0100 +* @tc.name: test the create and remove bundle dir function of installd service +* @tc.desc: 1. the service is already initialized +* 2. the bundle dir of the right code dir can be created and removed +*/ +HWTEST_F(BmsInstallDaemonTest, BundleDir_0100, Function | SmallTest | Level0) +{ + int result = CreateBundleDir(BUNDLE_CODE_DIR); + ASSERT_EQ(result, 0); + bool dirExist = CheckBundleDirExist(); + ASSERT_TRUE(dirExist); + int result1 = RemoveBundleDir(BUNDLE_CODE_DIR); + ASSERT_EQ(result1, 0); + dirExist = CheckBundleDirExist(); + EXPECT_FALSE(dirExist); +} + +/** +* @tc.number: BundleDir_0200 +* @tc.name: test the create and remove bundle dir function of installd service +* @tc.desc: 1. the service is already initialized and the code dir is illegal +* 2. the bundle dir of the illegal code dir can't be created +*/ +HWTEST_F(BmsInstallDaemonTest, BundleDir_0200, Function | SmallTest | Level0) +{ + int result = CreateBundleDir(""); + ASSERT_EQ(result, ERR_APPEXECFWK_INSTALLD_PARAM_ERROR); + bool dirExist = CheckBundleDirExist(); + EXPECT_FALSE(dirExist); +} + +/** +* @tc.number: BundleDir_0300 +* @tc.name: test the create and remove bundle dir function of installd service +* @tc.desc: 1. the service is already initialized and the code dir is system dir +* 2. the bundle dir of the system dir can't be created +*/ +HWTEST_F(BmsInstallDaemonTest, BundleDir_0300, Function | SmallTest | Level0) +{ + int result1 = CreateBundleDir(SYSTEM_DIR); + ASSERT_EQ(result1, ERR_APPEXECFWK_INSTALLD_CREATE_DIR_FAILED); + bool dirExist = CheckBundleDirExist(); + EXPECT_FALSE(dirExist); +} + +/** +* @tc.number: BundleDataDir_0100 +* @tc.name: test the create and remove bundle data dir function of installd service +* @tc.desc: 1. the service is already initialized and the code dir is system dir +* 2. the bundle data dir of the right code dir can be created and removed +*/ +HWTEST_F(BmsInstallDaemonTest, BundleDataDir_0100, Function | SmallTest | Level0) +{ + int result = CreateBundleDataDir(BUNDLE_DATA_DIR, UID, GID); + ASSERT_EQ(result, 0); + bool dirExist = CheckBundleDataDirExist(); + ASSERT_TRUE(dirExist); + int result1 = RemoveBundleDataDir(BUNDLE_DATA_DIR); + ASSERT_EQ(result1, 0); + dirExist = CheckBundleDataDirExist(); + EXPECT_FALSE(dirExist); +} + +/** +* @tc.number: BundleDataDir_0200 +* @tc.name: test the create and clean bundle data dir function of installd service +* @tc.desc: 1. the service is already initialized +* 2. the bundle data dir of the right code dir can be created and clean +*/ +HWTEST_F(BmsInstallDaemonTest, BundleDataDir_0200, Function | SmallTest | Level0) +{ + int result = CreateBundleDataDir(BUNDLE_DATA_DIR, UID, GID); + ASSERT_EQ(result, 0); + bool dirExist = CheckBundleDataDirExist(); + ASSERT_TRUE(dirExist); + int result1 = CleanBundleDataDir(BUNDLE_DATA_DIR); + ASSERT_EQ(result1, 0); + dirExist = CheckBundleDataDirExist(); + EXPECT_TRUE(dirExist); +} + +/** +* @tc.number: BundleDataDir_0300 +* @tc.name: test the create and remove bundle data dir function of installd service +* @tc.desc: 1. the service is already initialized and the code dir is illegal +* 2. the bundle data dir of the illegal code dir can't be created +*/ +HWTEST_F(BmsInstallDaemonTest, BundleDataDir_0300, Function | SmallTest | Level0) +{ + int result = CreateBundleDataDir("", UID, GID); + ASSERT_EQ(result, ERR_APPEXECFWK_INSTALLD_PARAM_ERROR); + bool dirExist = CheckBundleDataDirExist(); + EXPECT_FALSE(dirExist); +} + +/** +* @tc.number: BundleDataDir_0400 +* @tc.name: test the create and remove bundle data dir function of installd service +* @tc.desc: 1. the service is already initialized and the uid is illegal +* 2. the bundle data dir of the illegal uid can't be created +*/ +HWTEST_F(BmsInstallDaemonTest, BundleDataDir_0400, Function | SmallTest | Level0) +{ + int result = CreateBundleDataDir(BUNDLE_DATA_DIR, -1, GID); + ASSERT_EQ(result, ERR_APPEXECFWK_INSTALLD_PARAM_ERROR); + bool dirExist = CheckBundleDataDirExist(); + EXPECT_FALSE(dirExist); +} + +/** +* @tc.number: BundleDataDir_0500 +* @tc.name: test the create and remove bundle data dir function of installd service +* @tc.desc: 1. the service is already initialized and the gid is illegal +* 2. the bundle data dir of the illegal gid can't be created +*/ +HWTEST_F(BmsInstallDaemonTest, BundleDataDir_0500, Function | SmallTest | Level0) +{ + int result = CreateBundleDataDir(BUNDLE_DATA_DIR, UID, -1); + ASSERT_EQ(result, ERR_APPEXECFWK_INSTALLD_PARAM_ERROR); + bool dirExist = CheckBundleDataDirExist(); + EXPECT_FALSE(dirExist); +} + +/** +* @tc.number: BundleDataDir_0500 +* @tc.name: test the create and remove bundle data dir function of installd service +* @tc.desc: 1. the service is already initialized and the code dir is system dir +* 2. the bundle data dir of the system dir can't be created +*/ +HWTEST_F(BmsInstallDaemonTest, BundleDataDir_0600, Function | SmallTest | Level0) +{ + int result = CreateBundleDataDir(SYSTEM_DIR, UID, GID); + ASSERT_EQ(result, ERR_APPEXECFWK_INSTALLD_CREATE_DIR_FAILED); + bool dirExist = CheckBundleDataDirExist(); + EXPECT_FALSE(dirExist); +} + +/** +* @tc.number: ExtractBundleFile_0100 +* @tc.name: test the ExtractBundleFile function of installd service with flag system bundle +* @tc.desc: 1. the bundle file is available and the target dir exists +* 2. the origin file exists and the extracted file exists +*/ +HWTEST_F(BmsInstallDaemonTest, ExtractBundleFile_0100, Function | SmallTest | Level0) +{ + CreateBundleDir(BUNDLE_CODE_DIR); + bool dirExist = CheckBundleDirExist(); + ASSERT_TRUE(dirExist); + auto bundleFile = BUNDLE_FILE; + int result = ExtractModuleFiles(bundleFile, TEMP_DIR); + ASSERT_EQ(result, 0); + int result1 = RenameModuleDir(TEMP_DIR, MODULE_DIR); + EXPECT_EQ(result1, 0); +} + +/** +* @tc.number: ExtractBundleFile_0200 +* @tc.name: test the ExtractBundleFile function of installd service +* @tc.desc: 1. the bundle file is illegal +* 2. the bundle file can't be extracted and the extracted file does not exists +*/ +HWTEST_F(BmsInstallDaemonTest, ExtractBundleFile_0200, Function | SmallTest | Level0) +{ + CreateBundleDir(BUNDLE_CODE_DIR); + bool dirExist = CheckBundleDirExist(); + ASSERT_TRUE(dirExist); + int result = ExtractModuleFiles("", TEMP_DIR); + EXPECT_EQ(result, ERR_APPEXECFWK_INSTALLD_PARAM_ERROR); +} + +/** +* @tc.number: ExtractBundleFile_0300 +* @tc.name: test the ExtractBundleFile function of installd service +* @tc.desc: 1. the temp dir does not exist +* 2. the bundle file can't be extracted and the extracted file does not exists +*/ +HWTEST_F(BmsInstallDaemonTest, ExtractBundleFile_0300, Function | SmallTest | Level0) +{ + CreateBundleDir(BUNDLE_CODE_DIR); + bool dirExist = CheckBundleDirExist(); + ASSERT_TRUE(dirExist); + auto bundleFile = BUNDLE_FILE; + int result = ExtractModuleFiles(bundleFile, ""); + EXPECT_EQ(result, ERR_APPEXECFWK_INSTALLD_PARAM_ERROR); +} + +/** +* @tc.number: ExtractBundleFile_0400 +* @tc.name: test the ExtractBundleFile function of installd service +* @tc.desc: 1. the old path does not exist +* 2. the bundle file can't be extracted and the extracted file does not exists +*/ +HWTEST_F(BmsInstallDaemonTest, ExtractBundleFile_0400, Function | SmallTest | Level0) +{ + CreateBundleDir(BUNDLE_CODE_DIR); + bool dirExist = CheckBundleDirExist(); + ASSERT_TRUE(dirExist); + auto bundleFile = BUNDLE_FILE; + int result = ExtractModuleFiles(bundleFile, TEMP_DIR); + ASSERT_EQ(result, 0); + int result1 = RenameModuleDir("", MODULE_DIR); + EXPECT_EQ(result1, ERR_APPEXECFWK_INSTALLD_PARAM_ERROR); +} + +/** +* @tc.number: ExtractBundleFile_0500 +* @tc.name: test the ExtractBundleFile function of installd service +* @tc.desc: 1. the new path does not exist +* 2. the bundle file can't be extracted and the extracted file does not exists +*/ +HWTEST_F(BmsInstallDaemonTest, ExtractBundleFile_0500, Function | SmallTest | Level0) +{ + CreateBundleDir(BUNDLE_CODE_DIR); + bool dirExist = CheckBundleDirExist(); + ASSERT_TRUE(dirExist); + auto bundleFile = BUNDLE_FILE; + int result = ExtractModuleFiles(bundleFile, TEMP_DIR); + ASSERT_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 new file mode 100644 index 000000000..8c011d800 --- /dev/null +++ b/services/bundlemgr/test/unittest/bms_service_bundle_scan_test/BUILD.gn @@ -0,0 +1,73 @@ +# 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") +import( + "//foundation/appexecfwk/standard/services/bundlemgr/appexecfwk_bundlemgr.gni") + +module_output_path = "appexecfwk_standard/bundlemgrservice" + +ohos_unittest("BmsServiceBundleScanTest") { + module_out_path = module_output_path + + sources = [ + "${services_path}/bundlemgr/src/bundle_data_mgr.cpp", + "${services_path}/bundlemgr/src/bundle_data_storage.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", + ] + + sources += + [ "${services_path}/bundlemgr/test/mock/src/system_ability_helper.cpp" ] + + sources += bundle_install_sources + + sources += [ "bms_service_bundle_scan_test.cpp" ] + + configs = [ + "${services_path}/bundlemgr/test:bundlemgr_test_config", + "${libs_path}/libeventhandler:libeventhandler_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${libs_path}/libeventhandler:libeventhandler_target", + "//base/notification/ces_standard/cesfwk/kits/native:cesfwk_kits", + "//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/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//third_party/googletest:gtest_main", + ] + + deps += bundle_install_deps + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":BmsServiceBundleScanTest" ] +} 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 new file mode 100755 index 000000000..8abd6d4c9 --- /dev/null +++ b/services/bundlemgr/test/unittest/bms_service_bundle_scan_test/bms_service_bundle_scan_test.cpp @@ -0,0 +1,269 @@ +/* + * 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 "app_log_wrapper.h" +#include "bundle_mgr_service.h" +#include "bundle_scanner.h" + +using namespace testing::ext; +using namespace OHOS::AppExecFwk; +using OHOS::DelayedSingleton; + +namespace { + +const std::string TEST_DIR = "/data/test/resource"; +const std::string BUNDLE_FILENAME_1 = "app1.hap"; +const std::string BUNDLE_FILENAME_2 = "app2.hap"; +const std::string BUNDLE_FILENAME_3 = "app3.hap"; +const std::string BUNDLE_FILENAME_4 = "app1.ha"; +const std::string BUNDLE_FILENAME_5 = "app2..ap"; +const std::string BUNDLE_FILENAME_6 = "app3"; + +} // namespace + +class BmsServiceBundleScanTest : public testing::Test { +public: + BmsServiceBundleScanTest(); + ~BmsServiceBundleScanTest(); + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + + void CreateDir(const std::string &path) const; + void DeleteDir(const std::string &path) const; + void CreateFile(const std::string &path) const; + void DeleteFile(const std::string &path) const; + + // return scan result list number + long TriggerScan(); + bool IsScanResultContain(const std::string name) const; + +private: + std::list bundleList_{}; +}; + +BmsServiceBundleScanTest::BmsServiceBundleScanTest() +{} + +BmsServiceBundleScanTest::~BmsServiceBundleScanTest() +{} + +void BmsServiceBundleScanTest::SetUpTestCase() +{} + +void BmsServiceBundleScanTest::TearDownTestCase() +{} + +void BmsServiceBundleScanTest::SetUp() +{ + CreateDir(TEST_DIR); +} + +void BmsServiceBundleScanTest::TearDown() +{ + bundleList_.clear(); + DeleteDir(TEST_DIR); +} + +void BmsServiceBundleScanTest::CreateDir(const std::string &path) const +{ + if (access(path.c_str(), F_OK) != 0) { + if (mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) { + APP_LOGE("CreateDir:%{public}s error", path.c_str()); + } + } +} + +void BmsServiceBundleScanTest::DeleteDir(const std::string &path) const +{ + if (access(path.c_str(), F_OK) == 0) { + if (rmdir(path.c_str()) != 0) { + APP_LOGE("DeleteDir:%{public}s error", path.c_str()); + } + } +} + +void BmsServiceBundleScanTest::CreateFile(const std::string &path) const +{ + if (path.size() > PATH_MAX) { + 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); + if (fd == -1) { + APP_LOGE("CreateFile-open:%{public}s error", realPath.c_str()); + return; + } + if (close(fd) != 0) { + APP_LOGW("CreateFile-close:%{public}s error", realPath.c_str()); + } + + if (access(realPath.c_str(), F_OK) != 0) { + APP_LOGE("CreateFile-checkFile:%{public}s not exist", realPath.c_str()); + } +} + +void BmsServiceBundleScanTest::DeleteFile(const std::string &path) const +{ + if (remove(path.c_str()) != 0) { + APP_LOGE("DeleteFile:%{public}s fail", path.c_str()); + } +} + +long BmsServiceBundleScanTest::TriggerScan() +{ + auto scanner = std::make_unique(); + bundleList_ = scanner->Scan(TEST_DIR); + return bundleList_.size(); +} + +bool BmsServiceBundleScanTest::IsScanResultContain(const std::string name) const +{ + auto it = std::find(bundleList_.begin(), bundleList_.end(), name); + if (it == bundleList_.end()) { + GTEST_LOG_(ERROR) << "not find file in list"; + APP_LOGE("file:%{public}s not find in list", name.c_str()); + return false; + } + return true; +} +/** +* @tc.number: BundleScan_0100 +* @tc.name: Scan +* @tc.desc: 1. scan dir not exist +* 2. verify scan result file number is 0 +*/ +HWTEST_F(BmsServiceBundleScanTest, BundleScan_0100, Function | SmallTest | Level0) +{ + DeleteDir(TEST_DIR); + int number = static_cast(TriggerScan()); + EXPECT_EQ(0, number); +} +/** +* @tc.number: BundleScan_0200 +* @tc.name: Scan +* @tc.desc: 1. scan dir exist, no bundle file +* 2. verify scan result file number is 0 +*/ +HWTEST_F(BmsServiceBundleScanTest, BundleScan_0200, Function | SmallTest | Level0) +{ + int number = static_cast(TriggerScan()); + EXPECT_EQ(0, number); +} +/** +* @tc.number: BundleScan_0300 +* @tc.name: Scan +* @tc.desc: 1. scan dir exist, 3 legal file exist +* 2. verify scan result file number is 3 and file name correct +*/ +HWTEST_F(BmsServiceBundleScanTest, BundleScan_0300, Function | SmallTest | Level0) +{ + CreateDir(TEST_DIR); + const std::string TEST_FILE_NAME_1 = TEST_DIR + "/" + BUNDLE_FILENAME_1; + const std::string TEST_FILE_NAME_2 = TEST_DIR + "/" + BUNDLE_FILENAME_2; + const std::string TEST_FILE_NAME_3 = TEST_DIR + "/" + BUNDLE_FILENAME_3; + CreateFile(TEST_FILE_NAME_1); + CreateFile(TEST_FILE_NAME_2); + CreateFile(TEST_FILE_NAME_3); + + int number = static_cast(TriggerScan()); + ASSERT_EQ(3, number); + + EXPECT_TRUE(IsScanResultContain(TEST_FILE_NAME_1)); + EXPECT_TRUE(IsScanResultContain(TEST_FILE_NAME_2)); + EXPECT_TRUE(IsScanResultContain(TEST_FILE_NAME_3)); + + DeleteFile(TEST_FILE_NAME_1); + DeleteFile(TEST_FILE_NAME_2); + DeleteFile(TEST_FILE_NAME_3); +} +/** +* @tc.number: BundleScan_0400 +* @tc.name: Scan +* @tc.desc: 1. scan dir exist, 3 illegal file exist +* 2. verify scan result file number is 0 +*/ +HWTEST_F(BmsServiceBundleScanTest, BundleScan_0400, Function | SmallTest | Level0) +{ + const std::string TEST_FILE_NAME_4 = TEST_DIR + "/" + BUNDLE_FILENAME_4; + const std::string TEST_FILE_NAME_5 = TEST_DIR + "/" + BUNDLE_FILENAME_5; + const std::string TEST_FILE_NAME_6 = TEST_DIR + "/" + BUNDLE_FILENAME_6; + + CreateFile(TEST_FILE_NAME_4); + CreateFile(TEST_FILE_NAME_5); + CreateFile(TEST_FILE_NAME_6); + + int number = static_cast(TriggerScan()); + EXPECT_EQ(0, number); + + DeleteFile(TEST_FILE_NAME_4); + DeleteFile(TEST_FILE_NAME_5); + DeleteFile(TEST_FILE_NAME_6); +} +/** +* @tc.number: BundleScan_0500 +* @tc.name: Scan +* @tc.desc: 1. scan dir exist, 3 illegal and 3 legal file exist +* 2. verify scan result file number is 3 and file name correct +*/ +HWTEST_F(BmsServiceBundleScanTest, BundleScan_0500, Function | SmallTest | Level0) +{ + const std::string TEST_FILE_NAME_1 = TEST_DIR + "/" + BUNDLE_FILENAME_1; + const std::string TEST_FILE_NAME_2 = TEST_DIR + "/" + BUNDLE_FILENAME_2; + const std::string TEST_FILE_NAME_3 = TEST_DIR + "/" + BUNDLE_FILENAME_3; + const std::string TEST_FILE_NAME_4 = TEST_DIR + "/" + BUNDLE_FILENAME_4; + const std::string TEST_FILE_NAME_5 = TEST_DIR + "/" + BUNDLE_FILENAME_5; + const std::string TEST_FILE_NAME_6 = TEST_DIR + "/" + BUNDLE_FILENAME_6; + + CreateFile(TEST_FILE_NAME_1); + CreateFile(TEST_FILE_NAME_2); + CreateFile(TEST_FILE_NAME_3); + CreateFile(TEST_FILE_NAME_4); + CreateFile(TEST_FILE_NAME_5); + CreateFile(TEST_FILE_NAME_6); + + int number = static_cast(TriggerScan()); + ASSERT_EQ(3, number); + + EXPECT_TRUE(IsScanResultContain(TEST_FILE_NAME_1)); + EXPECT_TRUE(IsScanResultContain(TEST_FILE_NAME_2)); + EXPECT_TRUE(IsScanResultContain(TEST_FILE_NAME_3)); + + DeleteFile(TEST_FILE_NAME_1); + DeleteFile(TEST_FILE_NAME_2); + DeleteFile(TEST_FILE_NAME_3); + DeleteFile(TEST_FILE_NAME_4); + DeleteFile(TEST_FILE_NAME_5); + DeleteFile(TEST_FILE_NAME_6); +} diff --git a/services/bundlemgr/test/unittest/bms_service_startup_test/BUILD.gn b/services/bundlemgr/test/unittest/bms_service_startup_test/BUILD.gn new file mode 100644 index 000000000..8bb1a6027 --- /dev/null +++ b/services/bundlemgr/test/unittest/bms_service_startup_test/BUILD.gn @@ -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. + +import("//build/test.gni") +import("//foundation/appexecfwk/standard/appexecfwk.gni") +import( + "//foundation/appexecfwk/standard/services/bundlemgr/appexecfwk_bundlemgr.gni") + +module_output_path = "appexecfwk_standard/bundlemgrservice" + +ohos_unittest("BmsServiceStartupTest") { + module_out_path = module_output_path + + sources = [ + "${services_path}/bundlemgr/src/bundle_data_mgr.cpp", + "${services_path}/bundlemgr/src/bundle_data_storage.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", + ] + + sources += + [ "${services_path}/bundlemgr/test/mock/src/system_ability_helper.cpp" ] + + sources += bundle_install_sources + + sources += [ "bms_service_startup_test.cpp" ] + + configs = [ + "${services_path}/bundlemgr/test:bundlemgr_test_config", + "${libs_path}/libeventhandler:libeventhandler_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${libs_path}/libeventhandler:libeventhandler_target", + "//base/notification/ces_standard/cesfwk/kits/native:cesfwk_kits", + "//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/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + ] + + deps += bundle_install_deps + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("unittest") { + testonly = true + + deps = [ ":BmsServiceStartupTest" ] +} 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 new file mode 100755 index 000000000..82311aceb --- /dev/null +++ b/services/bundlemgr/test/unittest/bms_service_startup_test/bms_service_startup_test.cpp @@ -0,0 +1,146 @@ +/* + * 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 "bundle_mgr_service.h" + +using namespace testing::ext; +using namespace OHOS::AppExecFwk; +using OHOS::DelayedSingleton; + +class BmsServiceStartupTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); +}; + +void BmsServiceStartupTest::SetUpTestCase() +{} + +void BmsServiceStartupTest::TearDownTestCase() +{} + +void BmsServiceStartupTest::SetUp() +{} + +void BmsServiceStartupTest::TearDown() +{ + DelayedSingleton::DestroyInstance(); +} + +/** +* @tc.number: Startup_0100 +* @tc.name: test the start function of the BMS service when service is not ready +* @tc.desc: 1. the service is not initialized +* 2. the non initialized BMS service can be started +*/ +HWTEST_F(BmsServiceStartupTest, Startup_0100, Function | SmallTest | Level0) +{ + std::shared_ptr bms = DelayedSingleton::GetInstance(); + bool ready = bms->IsServiceReady(); + ASSERT_EQ(false, ready); + bms->OnStart(); + ready = bms->IsServiceReady(); + EXPECT_EQ(true, ready); +} + +/** +* @tc.number: Startup_0200 +* @tc.name: test the stop function of the BMS service when service is ready +* @tc.desc: 1. the service is already initialized +* 2. the initialized BMS service can be stopped +*/ +HWTEST_F(BmsServiceStartupTest, Startup_0200,Function | SmallTest | Level0) +{ + std::shared_ptr bms = DelayedSingleton::GetInstance(); + bms->OnStart(); + bool ready = bms->IsServiceReady(); + ASSERT_EQ(true, ready); + bms->OnStop(); + ready = bms->IsServiceReady(); + EXPECT_EQ(false, ready); +} + +/** +* @tc.number: Startup_0300 +* @tc.name: test the restart function of the BMS service +* @tc.desc: 1. the service is already initialized +* 2. the stopped BMS service can be restarted +*/ +HWTEST_F(BmsServiceStartupTest, Startup_0300,Function | SmallTest | Level0) +{ + std::shared_ptr bms = DelayedSingleton::GetInstance(); + bms->OnStart(); + bool ready = bms->IsServiceReady(); + ASSERT_EQ(true, ready); + bms->OnStop(); + ready = bms->IsServiceReady(); + ASSERT_EQ(false, ready); + bms->OnStart(); + ready = bms->IsServiceReady(); + EXPECT_EQ(true, ready); +} + +/** +* @tc.number: Startup_0400 +* @tc.name: test the restart function of the BMS service which is already initialized +* @tc.desc: 1. the service is already initialized +* 2. the recall start function will not affect the initialized BMS service +*/ +HWTEST_F(BmsServiceStartupTest, Startup_0400,Function | SmallTest | Level0) +{ + std::shared_ptr bms = DelayedSingleton::GetInstance(); + bms->OnStart(); + bool ready = bms->IsServiceReady(); + ASSERT_EQ(true, ready); + bms->OnStart(); + ready = bms->IsServiceReady(); + EXPECT_EQ(true, ready); +} + +/** +* @tc.number: GetDataMgr_0100 +* @tc.name: test the dataMgr can be obtained +* @tc.desc: 1. the service is already initialized +* 2. the dataMgr can be obtained +*/ +HWTEST_F(BmsServiceStartupTest, GetDataMgr_0100,Function | SmallTest | Level0) +{ + std::shared_ptr bms = DelayedSingleton::GetInstance(); + bms->OnStart(); + auto dataMgr = bms->GetDataMgr(); + EXPECT_NE(nullptr, dataMgr); + bms->OnStop(); +} + +/** +* @tc.number: GetBundleInstaller_0100 +* @tc.name: test the installer can be obtained +* @tc.desc: 1. the service is already initialized +* 2. the installer can be obtained +*/ +HWTEST_F(BmsServiceStartupTest, GetBundleInstaller_0100,Function | SmallTest | Level0) +{ + std::shared_ptr bms = DelayedSingleton::GetInstance(); + bms->OnStart(); + auto installer = bms->GetBundleInstaller(); + EXPECT_NE(nullptr, installer); + bms->OnStop(); +} \ No newline at end of file diff --git a/services/test/BUILD.gn b/services/test/BUILD.gn new file mode 100644 index 000000000..a9638d49a --- /dev/null +++ b/services/test/BUILD.gn @@ -0,0 +1,39 @@ +# 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("services_module_test_config") { + include_dirs = [ + "mock/include", + "//base/notification/ces_standard/cesfwk/kits/native/include", + ] + + configs = [] +} + +config("services_mock_ams_config") { + include_dirs = [ "../appmgr/test/mock/include" ] +} + +group("moduletest") { + testonly = true + + deps = [ + "moduletest/common/ams:moduletest", + "moduletest/common/bms:moduletest", + + # Temporary disable bms because build error. + #"moduletest/common/bms:moduletest", + ] +} diff --git a/services/test/mock/include/mock_ability_mgr_host.h b/services/test/mock/include/mock_ability_mgr_host.h new file mode 100644 index 000000000..57cfb5a17 --- /dev/null +++ b/services/test/mock/include/mock_ability_mgr_host.h @@ -0,0 +1,144 @@ +/* + * 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 "ability_manager_interface.h" +#include +#include + +namespace OHOS { +namespace AppExecFwk { + +class MockAbilityMgrStub : public IRemoteStub { +public: + using Uri = OHOS::Uri; + MockAbilityMgrStub() = default; + virtual ~MockAbilityMgrStub() = default; + + virtual int StartAbility(const AAFwk::Want &want, int requestCode = -1) override + { + return 0; + } + virtual int StartAbility( + const AAFwk::Want &want, const sptr &callerToken, int requestCode = -1) override + { + return 0; + } + virtual int TerminateAbility( + const sptr &token, int resultCode, const AAFwk::Want *resultWant = nullptr) override + { + return 0; + } + virtual int ConnectAbility(const AAFwk::Want &want, const sptr &connect, + const sptr &callerToken) override + { + return 0; + } + virtual int DisconnectAbility(const sptr &connect) override + { + return 0; + } + virtual sptr AcquireDataAbility( + const Uri &uri, bool tryBind, const sptr &callerToken) override + { + return nullptr; + } + virtual int ReleaseDataAbility( + sptr dataAbilityScheduler, const sptr &callerToken) override + { + return 0; + } + virtual void AddWindowInfo(const sptr &token, int32_t windowToken) override + { + return; + } + virtual int AttachAbilityThread( + const sptr &scheduler, const sptr &token) override + { + return 0; + } + virtual int AbilityTransitionDone(const sptr &token, int state) override + { + return 0; + } + virtual int ScheduleConnectAbilityDone( + const sptr &token, const sptr &remoteObject) override + { + return 0; + } + virtual int ScheduleDisconnectAbilityDone(const sptr &token) override + { + return 0; + } + virtual int ScheduleCommandAbilityDone(const sptr &token) override + { + return 0; + } + virtual void DumpState(const std::string &args, std::vector &state) override + { + return; + } + virtual int TerminateAbilityResult(const sptr &token, int startId) override + { + return 0; + } + virtual int StopServiceAbility(const AAFwk::Want &want) override + { + return 0; + } + virtual int GetAllStackInfo(AAFwk::StackInfo &stackInfo) override + { + return 0; + } + virtual int GetRecentMissions( + const int32_t numMax, const int32_t flags, std::vector &recentList) override + { + return 0; + } + virtual int GetMissionSnapshot(const int32_t missionId, AAFwk::MissionSnapshotInfo &snapshot) override + { + return 0; + } + virtual int MoveMissionToTop(int32_t missionId) override + { + return 0; + } + virtual int RemoveMission(int id) override + { + return 0; + } + virtual int RemoveStack(int id) override + { + return 0; + } + virtual int KillProcess(const std::string &bundleName) override + { + return 0; + } + virtual int UninstallApp(const std::string &bundleName) override + { + return 0; + } + virtual int TerminateAbilityByCaller(const sptr &callerToken, int requestCode) override + { + return 0; + } +}; + +} // 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/test/mock/include/mock_status_receiver.h b/services/test/mock/include/mock_status_receiver.h new file mode 100644 index 000000000..1085c272f --- /dev/null +++ b/services/test/mock/include/mock_status_receiver.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_SERVICES_BUNDLEMGR_TEST_MOCK_INCLUDE_MOCK_STATUS_RECEIVER_H +#define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_TEST_MOCK_INCLUDE_MOCK_STATUS_RECEIVER_H + +#include + +#include "nocopyable.h" + +#include "status_receiver_interface.h" + +namespace OHOS { +namespace AppExecFwk { + +class MockStatusReceiver : public IStatusReceiver { +public: + MockStatusReceiver() = default; + virtual ~MockStatusReceiver() override = default; + + virtual void OnStatusNotify(const int32_t progress) override; + virtual void OnFinished(const int32_t resultCode, [[maybe_unused]] const std::string &resultMsg) override; + virtual sptr AsObject() override; + int32_t GetResultCode(); + +private: + std::promise signal_; + + DISALLOW_COPY_AND_MOVE(MockStatusReceiver); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_TEST_MOCK_INCLUDE_MOCK_STATUS_RECEIVER_H \ No newline at end of file diff --git a/services/test/mock/src/mock_status_receiver.cpp b/services/test/mock/src/mock_status_receiver.cpp new file mode 100644 index 000000000..cd8b57538 --- /dev/null +++ b/services/test/mock/src/mock_status_receiver.cpp @@ -0,0 +1,44 @@ +/* + * 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 "mock_status_receiver.h" + +namespace OHOS { +namespace AppExecFwk { + +void MockStatusReceiver::OnFinished(const int32_t resultCode, [[maybe_unused]] const std::string &resultMsg) +{ + signal_.set_value(resultCode); +} + +void MockStatusReceiver::OnStatusNotify(const int32_t progress) +{ + return; +} + +sptr MockStatusReceiver::AsObject() +{ + return nullptr; +} + +int32_t MockStatusReceiver::GetResultCode() +{ + auto future = signal_.get_future(); + future.wait(); + return future.get(); +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/test/mock/src/system_ability_helper.cpp b/services/test/mock/src/system_ability_helper.cpp new file mode 100644 index 000000000..b02c8202f --- /dev/null +++ b/services/test/mock/src/system_ability_helper.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 "system_ability_helper.h" + +#include + +#include "system_ability_definition.h" +#include "app_log_wrapper.h" +#include "mock_ability_mgr_host.h" + +namespace OHOS { +namespace AppExecFwk { + +static std::map> g_abilities; + +sptr SystemAbilityHelper::GetSystemAbility(const int32_t systemAbilityId) +{ + APP_LOGD("mock system ability helper get %{public}d system ability", systemAbilityId); + auto iter = g_abilities.find(systemAbilityId); + if (iter != g_abilities.end()) { + return iter->second; + } + if (systemAbilityId == ABILITY_MGR_SERVICE_ID) { + return new MockAbilityMgrStub(); + } + return nullptr; +} + +bool SystemAbilityHelper::AddSystemAbility(const int32_t systemAbilityId, const sptr &systemAbility) +{ + if (g_abilities.erase(systemAbilityId) > 0) { + APP_LOGD("mock system ability helper add system ability erase exist key"); + } + APP_LOGD("mock system ability helper emplace %{public}d system ability", systemAbilityId); + g_abilities.emplace(systemAbilityId, systemAbility); + // mock helper always return true. + return true; +} + +bool SystemAbilityHelper::RemoveSystemAbility(const int32_t systemAbilityId) +{ + APP_LOGD("mock system ability helper remove system ability"); + if (g_abilities.erase(systemAbilityId) > 0) { + APP_LOGD("mock system ability helper remove %{public}d system ability erase exist key", systemAbilityId); + } + // mock helper always return true. + return true; +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/test/moduletest/common/ams/BUILD.gn b/services/test/moduletest/common/ams/BUILD.gn new file mode 100755 index 000000000..ccc70bee3 --- /dev/null +++ b/services/test/moduletest/common/ams/BUILD.gn @@ -0,0 +1,108 @@ +# 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") + +ohos_source_set("appmgr_mst_source") { + testonly = true + + sources = [ + "${services_path}/appmgr/src/ability_running_record.cpp", + "${services_path}/appmgr/src/ams_mgr_scheduler.cpp", + "${services_path}/appmgr/src/app_death_recipient.cpp", + "${services_path}/appmgr/src/app_lifecycle_deal.cpp", + "${services_path}/appmgr/src/app_mgr_service.cpp", + "${services_path}/appmgr/src/app_mgr_service_event_handler.cpp", + "${services_path}/appmgr/src/app_mgr_service_inner.cpp", + "${services_path}/appmgr/src/app_process_manager.cpp", + "${services_path}/appmgr/src/app_running_manager.cpp", + "${services_path}/appmgr/src/app_running_record.cpp", + "${services_path}/appmgr/src/app_spawn_client.cpp", + "${services_path}/appmgr/src/app_spawn_msg_wrapper.cpp", + "${services_path}/appmgr/src/app_spawn_socket.cpp", + "${services_path}/appmgr/src/cgroup_manager.cpp", + "${services_path}/appmgr/src/lmk_util.cpp", + "${services_path}/appmgr/src/lmkd_client.cpp", + "${services_path}/appmgr/src/process_optimizer.cpp", + "${services_path}/appmgr/src/process_optimizer_uba.cpp", + "${services_path}/appmgr/src/remote_client_manager.cpp", + "${services_path}/appmgr/test/mock/src/mock_bundle_manager.cpp", + ] + + defines = [ "APP_LOG_TAG = \"AppMgrService\"" ] + + include_dirs = [ + "//third_party/json/include", + "${services_path}/appmgr/test/mock/include", + ] + + public_configs = [ + "${libs_path}/libeventhandler:libeventhandler_config", + "${services_path}/test:services_module_test_config", + "${services_path}/appmgr:appmgr_config", + "${services_path}/test:services_mock_ams_config", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appmgr_sdk_config", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:bundlemgr_sdk_config", + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_base:appexecfwk_base_sdk_config", + "${innerkits_path}/appexecfwk_core:appexecfwk_core_config", + "${innerkits_path}/libeventhandler:public_libeventhandler_config", + "//foundation/aafwk/standard/interfaces/innerkits/want:want_public_config", + "//foundation/aafwk/standard/interfaces/innerkits/base:base_public_config", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy_config", + "//utils/native/base:utils_config", + "//third_party/googletest:gtest_config", + "//third_party/googletest:gmock_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + public_deps = [ + "${common_path}:libappexecfwk_common", + "${innerkits_path}/appexecfwk_base:appexecfwk_base", + "${innerkits_path}/appexecfwk_core:appexecfwk_core", + "${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/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/googletest:gmock_main", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("moduletest") { + testonly = true + + deps = [ + "ability_running_record_test:moduletest", + "app_life_cycle_test:moduletest", + "app_mgr_service_test:moduletest", + "app_recent_list_test:moduletest", + "app_running_record_test:moduletest", + "app_service_flow_test:moduletest", + "ipc_ams_mgr_test:moduletest", + "ipc_app_mgr_test:moduletest", + "ipc_app_scheduler_test:moduletest", + "service_app_spawn_client_test:moduletest", + "service_event_drive_test:moduletest", + "service_start_process_test:moduletest", + ] +} diff --git a/services/test/moduletest/common/ams/ability_running_record_test/BUILD.gn b/services/test/moduletest/common/ams/ability_running_record_test/BUILD.gn new file mode 100755 index 000000000..de1f91dbf --- /dev/null +++ b/services/test/moduletest/common/ams/ability_running_record_test/BUILD.gn @@ -0,0 +1,36 @@ +# 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/mstappmgrservice" + +ohos_moduletest("AmsAbilityRunningRecordModuleTest") { + module_out_path = module_output_path + include_dirs = [ + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include/hilog/", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + ] + sources = [ "ams_ability_running_record_module_test.cpp" ] + + deps = [ "${services_path}/test/moduletest/common/ams:appmgr_mst_source" ] + + external_deps = [ "ipc:ipc_core" ] +} + +group("moduletest") { + testonly = true + + deps = [ ":AmsAbilityRunningRecordModuleTest" ] +} diff --git a/services/test/moduletest/common/ams/ability_running_record_test/ams_ability_running_record_module_test.cpp b/services/test/moduletest/common/ams/ability_running_record_test/ams_ability_running_record_module_test.cpp new file mode 100644 index 000000000..21555dd04 --- /dev/null +++ b/services/test/moduletest/common/ams/ability_running_record_test/ams_ability_running_record_module_test.cpp @@ -0,0 +1,432 @@ +/* + * 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_running_record.h" +#include +#include "app_log_wrapper.h" +#include "app_record_id.h" +#include "app_scheduler_host.h" +#include "ability_info.h" +#include "application_info.h" +#include "app_running_record.h" +#include "mock_ability_token.h" + +using namespace testing::ext; +namespace OHOS { +namespace AppExecFwk { +namespace { + +const std::string APP_RECORD_NAME = "App_Name_Z"; +const std::string ABILITY_RECORD_NAME = "Ability_Name_Z"; + +// schedule phase +const int NONE_SCHEDULED = 0; +const int FOREGROUND_SCHEDULED = 1 << 0; +const int BACKGROUND_SCHEDULED = 1 << 1; +const int TERMINATE_SCHEDULED = 1 << 2; +const int SHRINK_MEMORY_SCHEDULED = 1 << 3; +const int LOW_MEMORY_SCHEDULED = 1 << 4; +const int LAUNCH_APPLICATION_SCHEDULED = 1 << 5; +const int LAUNCH_ABILITY_SCHEDULED = 1 << 6; +const int CLEAN_ABILITY_SCHEDULED = 1 << 7; +const int PROFILE_CHANGED_SCHEDULED = 1 << 8; +const int SCHEDULE_CONFIGURATION_UPDATED = 1 << 9; +const int ABILITY_RUNNING_RECORD_NUM = 1000; + +} // namespace + +class MockedSchedulerBase { +public: + MockedSchedulerBase() + { + Reset(); + } + + virtual ~MockedSchedulerBase() + {} + + virtual void Reset() + { + scheduled_ = NONE_SCHEDULED; + } + + bool IsScheduled(const int scheduledPhase) const + { + return (scheduled_ & scheduledPhase) > 0; + } + +protected: + unsigned int scheduled_ = NONE_SCHEDULED; +}; + +class MockedApplication : public AppSchedulerHost, public MockedSchedulerBase { +public: + void ScheduleForegroundApplication() override + { + scheduled_ |= FOREGROUND_SCHEDULED; + } + void ScheduleBackgroundApplication() override + { + scheduled_ |= BACKGROUND_SCHEDULED; + } + void ScheduleTerminateApplication() override + { + scheduled_ |= TERMINATE_SCHEDULED; + } + void ScheduleShrinkMemory(const int) override + { + scheduled_ |= SHRINK_MEMORY_SCHEDULED; + } + void ScheduleLowMemory() override + { + scheduled_ |= LOW_MEMORY_SCHEDULED; + } + void ScheduleLaunchApplication(const AppLaunchData &) override + { + scheduled_ |= LAUNCH_APPLICATION_SCHEDULED; + appLaunchTime++; + } + void ScheduleLaunchAbility(const AbilityInfo &, const sptr &) override + { + scheduled_ |= LAUNCH_ABILITY_SCHEDULED; + abilityLaunchTime++; + } + void ScheduleCleanAbility(const sptr &) override + { + scheduled_ |= CLEAN_ABILITY_SCHEDULED; + } + void ScheduleProfileChanged(const Profile &) override + { + scheduled_ |= PROFILE_CHANGED_SCHEDULED; + } + void ScheduleConfigurationUpdated(const Configuration &config) + { + scheduled_ |= SCHEDULE_CONFIGURATION_UPDATED; + } + void ScheduleProcessSecurityExit() + {} + int GetAppLaunchTime() const + { + return appLaunchTime; + } + int GetAbilityLaunchTime() const + { + return abilityLaunchTime; + } + void Reset() override + { + MockedSchedulerBase::Reset(); + abilityLaunchTime = 0; + appLaunchTime = 0; + } + +private: + int abilityLaunchTime = 0; + int appLaunchTime = 0; +}; + +class AmsAbilityRunningRecordModuleTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + +protected: + std::shared_ptr QueryAppRunningRecord(); + sptr QueryMockedAppSchedulerClient(); + +protected: + sptr mockedAppClient_; + sptr client_; + std::shared_ptr caseAppRunningRecord_; +}; + +void AmsAbilityRunningRecordModuleTest::SetUpTestCase() +{} + +void AmsAbilityRunningRecordModuleTest::TearDownTestCase() +{} + +void AmsAbilityRunningRecordModuleTest::SetUp() +{ + mockedAppClient_ = new (std::nothrow) MockedApplication(); +} + +void AmsAbilityRunningRecordModuleTest::TearDown() +{ + caseAppRunningRecord_.reset(); +} + +sptr AmsAbilityRunningRecordModuleTest::QueryMockedAppSchedulerClient() +{ + if (!client_) { + client_ = iface_cast(mockedAppClient_.GetRefPtr()); + } + return client_; +} + +std::shared_ptr AmsAbilityRunningRecordModuleTest::QueryAppRunningRecord() +{ + if (caseAppRunningRecord_ == nullptr) { + auto appInfo = std::make_shared(); + appInfo->name = APP_RECORD_NAME; + appInfo->bundleName = APP_RECORD_NAME; // specify process condition + caseAppRunningRecord_.reset( + new (std::nothrow) AppRunningRecord(appInfo, AppRecordId::Create(), appInfo->bundleName)); + caseAppRunningRecord_->SetApplicationClient(QueryMockedAppSchedulerClient()); + } + return caseAppRunningRecord_; +} + +/* + * Feature: AMS + * Function: AbilityRunningRecord + * SubFunction: NA + * FunctionPoints: Create AbilityRunningRecord succeed + * EnvConditions: NA + * CaseDescription: Verify the function creating two same names of AbilityRunningRecord. + */ +HWTEST_F(AmsAbilityRunningRecordModuleTest, AddAbilityRunningRecord_001, TestSize.Level0) +{ + APP_LOGI("AddAbilityRunningRecord_001 start"); + auto appRunningRecord = QueryAppRunningRecord(); + auto caseAbilityInfo = std::make_shared(); + caseAbilityInfo->name = ABILITY_RECORD_NAME; + sptr token = new MockAbilityToken(); + auto caseAbilityRunningRecord = appRunningRecord->AddAbility(token, caseAbilityInfo); + + EXPECT_TRUE(caseAbilityRunningRecord != nullptr); + EXPECT_EQ(caseAbilityRunningRecord, appRunningRecord->GetAbilityRunningRecordByToken(token)); + auto abilityRunningRecordWithSameName = appRunningRecord->AddAbility(token, caseAbilityInfo); + appRunningRecord->ClearAbility(caseAbilityRunningRecord); + EXPECT_TRUE(appRunningRecord->GetAbilityRunningRecordByToken(token) == nullptr); + APP_LOGI("AddAbilityRunningRecord_001 end"); +} + +/* + * Feature: AMS + * Function: AbilityRunningRecord + * SubFunction: NA + * FunctionPoints: Create AbilityRunningRecord succeed + * EnvConditions: NA + * CaseDescription: Verify the function creating more AbilityRunningRecords. + */ +HWTEST_F(AmsAbilityRunningRecordModuleTest, AddAbilityRunningRecord_002, TestSize.Level0) +{ + APP_LOGI("AddAbilityRunningRecord_002 start"); + int i; + auto appRunningRecord = QueryAppRunningRecord(); + + for (i = 0; i < ABILITY_RUNNING_RECORD_NUM; i++) { + auto caseAbilityInfo = std::make_shared(); + caseAbilityInfo->name = ABILITY_RECORD_NAME + "_" + std::to_string(i); + sptr token = new MockAbilityToken(); + auto caseAbilityRunningRecord = appRunningRecord->AddAbility(token, caseAbilityInfo); + EXPECT_TRUE(caseAbilityRunningRecord != nullptr); + EXPECT_EQ(caseAbilityRunningRecord, appRunningRecord->GetAbilityRunningRecordByToken(token)); + EXPECT_EQ(caseAbilityRunningRecord->GetState(), AbilityState::ABILITY_STATE_BEGIN); + } + APP_LOGI("AddAbilityRunningRecord_002 end"); +} + +/* + * Feature: AMS + * Function: AbilityRunningRecord + * SubFunction: NA + * FunctionPoints: Update AbilityRunningRecord succeed + * EnvConditions: NA + * CaseDescription: Verify the function updating more AbilityRunningRecords. + */ +HWTEST_F(AmsAbilityRunningRecordModuleTest, UpdateAbilityRunningRecord_001, TestSize.Level1) +{ + APP_LOGI("UpdateAbilityRunningRecord_001 start"); + int i; + auto appRunningRecord = QueryAppRunningRecord(); + + for (i = 0; i < ABILITY_RUNNING_RECORD_NUM; i++) { + auto caseAbilityInfo = std::make_shared(); + caseAbilityInfo->name = ABILITY_RECORD_NAME + "_" + std::to_string(i); + sptr token = new MockAbilityToken(); + auto caseAbilityRunningRecord = appRunningRecord->AddAbility(token, caseAbilityInfo); + EXPECT_TRUE(caseAbilityRunningRecord != nullptr); + EXPECT_EQ(caseAbilityRunningRecord, appRunningRecord->GetAbilityRunningRecordByToken(token)); + caseAbilityRunningRecord->SetState(AbilityState::ABILITY_STATE_BACKGROUND); + appRunningRecord->SetState(ApplicationState::APP_STATE_FOREGROUND); + appRunningRecord->UpdateAbilityState(token, AbilityState::ABILITY_STATE_FOREGROUND); + EXPECT_EQ(caseAbilityRunningRecord->GetState(), AbilityState::ABILITY_STATE_FOREGROUND); + appRunningRecord->UpdateAbilityState(token, AbilityState::ABILITY_STATE_BACKGROUND); + EXPECT_EQ(caseAbilityRunningRecord->GetState(), AbilityState::ABILITY_STATE_BACKGROUND); + } + APP_LOGI("UpdateAbilityRunningRecord_001 end"); +} + +/* + * Feature: AMS + * Function: AbilityRunningRecord + * SubFunction: NA + * FunctionPoints: Update AbilityRunningRecord succeed + * EnvConditions: NA + * CaseDescription: Verify the function updating an illegal state of AbilityRunningRecord. + */ +HWTEST_F(AmsAbilityRunningRecordModuleTest, UpdateAbilityRunningRecord_002, TestSize.Level0) +{ + APP_LOGI("UpdateAbilityRunningRecord_002 start"); + int i; + auto appRunningRecord = QueryAppRunningRecord(); + + for (i = 0; i < ABILITY_RUNNING_RECORD_NUM; i++) { + auto caseAbilityInfo = std::make_shared(); + caseAbilityInfo->name = ABILITY_RECORD_NAME + "_" + std::to_string(i); + sptr token = new MockAbilityToken(); + auto caseAbilityRunningRecord = appRunningRecord->AddAbility(token, caseAbilityInfo); + EXPECT_TRUE(caseAbilityRunningRecord != nullptr); + EXPECT_EQ(caseAbilityRunningRecord, appRunningRecord->GetAbilityRunningRecordByToken(token)); + appRunningRecord->UpdateAbilityState(token, AbilityState::ABILITY_STATE_END); + EXPECT_EQ(caseAbilityRunningRecord->GetState(), AbilityState::ABILITY_STATE_BEGIN); + } + APP_LOGI("UpdateAbilityRunningRecord_002 end"); +} + +/* + * Feature: AMS + * Function: AbilityRunningRecord + * SubFunction: NA + * FunctionPoints: Update AbilityRunningRecord succeed + * EnvConditions: NA + * CaseDescription: Verify the function updating more AbilityRunningRecords. + */ +HWTEST_F(AmsAbilityRunningRecordModuleTest, UpdateAbilityRunningRecord_003, TestSize.Level1) +{ + APP_LOGI("UpdateAbilityRunningRecord_003 start"); + int i; + auto appRunningRecord = QueryAppRunningRecord(); + + for (i = 0; i < ABILITY_RUNNING_RECORD_NUM; i++) { + auto caseAbilityInfo = std::make_shared(); + caseAbilityInfo->name = ABILITY_RECORD_NAME + "_" + std::to_string(i); + sptr token = new MockAbilityToken(); + auto caseAbilityRunningRecord = appRunningRecord->AddAbility(token, caseAbilityInfo); + EXPECT_TRUE(caseAbilityRunningRecord != nullptr); + EXPECT_EQ(caseAbilityRunningRecord, appRunningRecord->GetAbilityRunningRecordByToken(token)); + caseAbilityRunningRecord->SetState(AbilityState::ABILITY_STATE_FOREGROUND); + appRunningRecord->SetState(ApplicationState::APP_STATE_BACKGROUND); + appRunningRecord->UpdateAbilityState(token, AbilityState::ABILITY_STATE_BACKGROUND); + EXPECT_EQ(caseAbilityRunningRecord->GetState(), AbilityState::ABILITY_STATE_BACKGROUND); + appRunningRecord->UpdateAbilityState(token, AbilityState::ABILITY_STATE_READY); + EXPECT_EQ(caseAbilityRunningRecord->GetState(), AbilityState::ABILITY_STATE_BACKGROUND); + } + APP_LOGI("UpdateAbilityRunningRecord_003 end"); +} + +/* + * Feature: AMS + * Function: AbilityRunningRecord + * SubFunction: NA + * FunctionPoints: Clear AbilityRunningRecord succeed + * EnvConditions: NA + * CaseDescription: Verify the function clearing more AbilityRunningRecords. + */ +HWTEST_F(AmsAbilityRunningRecordModuleTest, ClearAbilityRunningRecord_001, TestSize.Level1) +{ + APP_LOGI("ClearAbilityRunningRecord_001 start"); + int i; + auto appRunningRecord = QueryAppRunningRecord(); + + for (i = 0; i < ABILITY_RUNNING_RECORD_NUM; i++) { + auto caseAbilityInfo = std::make_shared(); + caseAbilityInfo->name = ABILITY_RECORD_NAME + "_" + std::to_string(i); + sptr token = new MockAbilityToken(); + auto caseAbilityRunningRecord = appRunningRecord->AddAbility(token, caseAbilityInfo); + EXPECT_TRUE(caseAbilityRunningRecord != nullptr); + EXPECT_EQ(caseAbilityRunningRecord, appRunningRecord->GetAbilityRunningRecordByToken(token)); + } + for (i = 0; i < ABILITY_RUNNING_RECORD_NUM; i++) { + auto caseAbilityInfo = std::make_shared(); + caseAbilityInfo->name = ABILITY_RECORD_NAME + "_" + std::to_string(i); + sptr token = new MockAbilityToken(); + auto caseAbilityRunningRecord = appRunningRecord->GetAbilityRunningRecordByToken(token); + appRunningRecord->ClearAbility(caseAbilityRunningRecord); + EXPECT_TRUE(appRunningRecord->GetAbilityRunningRecordByToken(token) == nullptr); + } + APP_LOGI("ClearAbilityRunningRecord_001 end"); +} + +/* + * Feature: AMS + * Function: AbilityRunningRecord + * SubFunction: NA + * FunctionPoints: Clear AbilityRunningRecord succeed + * EnvConditions: NA + * CaseDescription: Verify the function clearing all AbilityRunningRecords, the AbilityRunningRecord is null. + */ +HWTEST_F(AmsAbilityRunningRecordModuleTest, ClearAbilityRunningRecord_002, TestSize.Level1) +{ + APP_LOGI("ClearAbilityRunningRecord_002 start"); + int i; + auto appRunningRecord = QueryAppRunningRecord(); + + for (i = 0; i < ABILITY_RUNNING_RECORD_NUM; i++) { + auto caseAbilityInfo = std::make_shared(); + caseAbilityInfo->name = ABILITY_RECORD_NAME + "_" + std::to_string(i); + sptr token = new MockAbilityToken(); + auto caseAbilityRunningRecord = appRunningRecord->AddAbility(token, caseAbilityInfo); + EXPECT_TRUE(caseAbilityRunningRecord != nullptr); + EXPECT_EQ(caseAbilityRunningRecord, appRunningRecord->GetAbilityRunningRecordByToken(token)); + appRunningRecord->ClearAbility(caseAbilityRunningRecord); + EXPECT_TRUE(appRunningRecord->GetAbilityRunningRecordByToken(token) == nullptr); + } + if (i == ABILITY_RUNNING_RECORD_NUM) { + auto abilityMap = appRunningRecord->GetAbilities(); + EXPECT_TRUE(abilityMap.empty()); + } + APP_LOGI("ClearAbilityRunningRecord_002 end"); +} + +/* + * Feature: AMS + * Function: AbilityRunningRecord + * SubFunction: NA + * FunctionPoints: Add ,update and Clear AbilityRunningRecord succeed + * EnvConditions: NA + * CaseDescription: Verify the function Add ,update and clear more AbilityRunningRecords. + */ +HWTEST_F(AmsAbilityRunningRecordModuleTest, OperateAbilityRunningRecord_001, TestSize.Level1) +{ + APP_LOGI("OperateAbilityRunningRecord_001 start"); + int i; + auto appRunningRecord = QueryAppRunningRecord(); + + for (i = 0; i < ABILITY_RUNNING_RECORD_NUM; i++) { + auto caseAbilityInfo = std::make_shared(); + caseAbilityInfo->name = ABILITY_RECORD_NAME + "_" + std::to_string(i); + sptr token = new MockAbilityToken(); + auto caseAbilityRunningRecord = appRunningRecord->AddAbility(token, caseAbilityInfo); + EXPECT_TRUE(caseAbilityRunningRecord != nullptr); + EXPECT_EQ(caseAbilityRunningRecord, appRunningRecord->GetAbilityRunningRecordByToken(token)); + } + for (i = 0; i < ABILITY_RUNNING_RECORD_NUM; i++) { + auto caseAbilityInfo = std::make_shared(); + caseAbilityInfo->name = ABILITY_RECORD_NAME + "_" + std::to_string(i); + sptr token = new MockAbilityToken(); + auto caseAbilityRunningRecord = appRunningRecord->GetAbilityRunningRecordByToken(token); + appRunningRecord->ClearAbility(caseAbilityRunningRecord); + EXPECT_TRUE(appRunningRecord->GetAbilityRunningRecordByToken(token) == nullptr); + } + APP_LOGI("OperateAbilityRunningRecord_001 end"); +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/test/moduletest/common/ams/app_life_cycle_test/BUILD.gn b/services/test/moduletest/common/ams/app_life_cycle_test/BUILD.gn new file mode 100755 index 000000000..81afa727f --- /dev/null +++ b/services/test/moduletest/common/ams/app_life_cycle_test/BUILD.gn @@ -0,0 +1,37 @@ +# 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/mstappmgrservice" + +ohos_moduletest("AmsAppLifeCycleModuleTest") { + module_out_path = module_output_path + + include_dirs = [ + "//base/hiviewdfx/hilog/interfaces/native/kits/include/hilog/", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + ] + sources = [ "ams_app_life_cycle_module_test.cpp" ] + + deps = [ "${services_path}/test/moduletest/common/ams:appmgr_mst_source" ] + + external_deps = [ "ipc:ipc_core" ] +} + +group("moduletest") { + testonly = true + + deps = [ ":AmsAppLifeCycleModuleTest" ] +} 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 new file mode 100755 index 000000000..e81e2e839 --- /dev/null +++ b/services/test/moduletest/common/ams/app_life_cycle_test/ams_app_life_cycle_module_test.cpp @@ -0,0 +1,1370 @@ +/* + * 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. + */ + +#define private public +#include "remote_client_manager.h" +#include "app_mgr_service_inner.h" +#undef private + +#include +#include +#include "app_launch_data.h" +#include "iremote_object.h" +#include "app_state_callback_proxy.h" +#include "app_log_wrapper.h" +#include "refbase.h" +#include "mock_bundle_manager.h" +#include "mock_ability_token.h" +#include "mock_app_scheduler.h" +#include "mock_app_spawn_client.h" +#include "mock_app_spawn_socket.h" +#include "mock_iapp_state_callback.h" + +using namespace testing::ext; +using testing::_; +using testing::Return; +using testing::SetArgReferee; + +namespace { + +const int32_t ABILITY_NUM = 100; +const int32_t APPLICATION_NUM = 100; +const int32_t INDEX_NUM_100 = 100; +const int32_t INDEX_NUM_MAX = 100; +const std::string TEST_APP_NAME = "test_app_"; +const std::string TEST_ABILITY_NAME = "test_ability_"; + +} // namespace + +namespace OHOS { +namespace AppExecFwk { + +struct TestProcessInfo { + pid_t pid = 0; + bool isStart = false; +}; + +// specify process condition +class AmsAppLifeCycleModuleTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + std::shared_ptr GetApplicationInfo(const std::string &appName) const; + std::shared_ptr GetAbilityInfo(const std::string &abilityIndex, const std::string &name, + const std::string &process, const std::string &applicationName) const; + void StartAppProcess(const pid_t &pid) const; + std::shared_ptr StartProcessAndLoadAbility(const sptr &mockAppScheduler, + const sptr &token, const std::shared_ptr &abilityInfo, + const std::shared_ptr &appInfo, const TestProcessInfo &testProcessInfo) const; + void ChangeAbilityStateAfterAppStart(const sptr &mockAppScheduler, const pid_t &pid) const; + void ChangeAbilityStateToForegroud(const sptr &mockAppScheduler, + const std::shared_ptr &appRunningRecord, const sptr &token, + const bool isChange = false) const; + void ChangeAbilityStateToBackGroud(const sptr &mockAppScheduler, + const std::shared_ptr &appRunningRecord, const sptr &token, + const bool isChange = false) const; + void ChangeAbilityStateToTerminate( + const sptr &mockAppScheduler, const sptr &token) const; + void ChangeAppToTerminate(const sptr &mockAppScheduler, + const std::shared_ptr &appRunningRecord, const sptr &token, + const bool isStop = false) const; + void CheckState(const std::shared_ptr &appRunningRecord, const sptr &token, + const AbilityState abilityState, const ApplicationState appState) const; + void CheckStateAfterClearAbility(const std::shared_ptr &appRunningRecord, + const std::vector> &tokens, const int32_t &recordId, + const sptr &mockAppScheduler) const; + void CheckStateAfterChangeAbility(const std::shared_ptr &appRunningRecord, + const std::vector> &tokens, const sptr &mockAppScheduler); + void CreateAppRecentList(const int32_t appNum); + + sptr GetAbilityToken(); + +protected: + std::unique_ptr serviceInner_ = nullptr; + sptr mockToken_ = nullptr; + sptr mockAppStateCallbackStub_ = nullptr; + std::shared_ptr inner_ = nullptr; + sptr mockBundleMgr; +}; + +void AmsAppLifeCycleModuleTest::SetUpTestCase() +{} + +void AmsAppLifeCycleModuleTest::TearDownTestCase() +{} + +void AmsAppLifeCycleModuleTest::SetUp() +{ + serviceInner_.reset(new (std::nothrow) AppMgrServiceInner()); + mockAppStateCallbackStub_ = new (std::nothrow) MockAppStateCallback(); + + inner_ = std::make_shared(); + + if (serviceInner_ && mockAppStateCallbackStub_) { + auto mockAppStateCallbackProxy = iface_cast(mockAppStateCallbackStub_); + if (mockAppStateCallbackProxy) { + serviceInner_->RegisterAppStateCallback(mockAppStateCallbackProxy); + inner_->RegisterAppStateCallback(mockAppStateCallbackProxy); + } + } + + mockBundleMgr = new (std::nothrow) BundleMgrService(); + serviceInner_->SetBundleManager(mockBundleMgr); +} + +void AmsAppLifeCycleModuleTest::TearDown() +{ + serviceInner_.reset(); + mockAppStateCallbackStub_.clear(); +} + +std::shared_ptr AmsAppLifeCycleModuleTest::GetApplicationInfo(const std::string &appName) const +{ + auto appInfo = std::make_shared(); + appInfo->name = appName; + return appInfo; +} + +std::shared_ptr AmsAppLifeCycleModuleTest::GetAbilityInfo(const std::string &abilityIndex, + const std::string &name, const std::string &process, const std::string &applicationName) const +{ + auto abilityInfo = std::make_shared(); + abilityInfo->name = name + abilityIndex; + if (!process.empty()) { + abilityInfo->process = process; + } + abilityInfo->applicationName = applicationName; + return abilityInfo; +} + +std::shared_ptr AmsAppLifeCycleModuleTest::StartProcessAndLoadAbility( + const sptr &mockAppScheduler, const sptr &token, + const std::shared_ptr &abilityInfo, const std::shared_ptr &appInfo, + const TestProcessInfo &testProcessInfo) const +{ + if (!testProcessInfo.isStart) { + StartAppProcess(testProcessInfo.pid); + } else { + EXPECT_CALL(*mockAppScheduler, ScheduleLaunchAbility(_, _)).Times(1); + } + + serviceInner_->LoadAbility(token, nullptr, abilityInfo, appInfo); + + std::shared_ptr record = + serviceInner_->GetAppRunningRecordByProcessName(appInfo->name, abilityInfo->process); + if (record == nullptr) { + EXPECT_TRUE(false); + } else { + pid_t newPid = record->GetPriorityObject()->GetPid(); + EXPECT_EQ(newPid, testProcessInfo.pid); + } + return record; +} + +void AmsAppLifeCycleModuleTest::StartAppProcess(const pid_t &pid) const +{ + MockAppSpawnClient *mockClientPtr = new (std::nothrow) MockAppSpawnClient(); + EXPECT_TRUE(mockClientPtr); + + EXPECT_CALL(*mockClientPtr, StartProcess(_, _)).Times(1).WillOnce(DoAll(SetArgReferee<1>(pid), Return(ERR_OK))); + EXPECT_CALL(*mockAppStateCallbackStub_, OnAppStateChanged(_)).Times(1); + + serviceInner_->SetAppSpawnClient(std::unique_ptr(mockClientPtr)); +} + +void AmsAppLifeCycleModuleTest::ChangeAbilityStateAfterAppStart( + const sptr &mockAppScheduler, const pid_t &pid) const +{ + EXPECT_CALL(*mockAppScheduler, ScheduleLaunchApplication(_)).Times(1); + EXPECT_CALL(*mockAppScheduler, ScheduleLaunchAbility(_, _)).Times(1); + + sptr client = iface_cast(mockAppScheduler.GetRefPtr()); + serviceInner_->AttachApplication(pid, client); +} + +void AmsAppLifeCycleModuleTest::ChangeAbilityStateToForegroud(const sptr &mockAppScheduler, + const std::shared_ptr &appRunningRecord, const sptr &token, + const bool isChange) const +{ + if (!isChange) { + EXPECT_CALL(*mockAppScheduler, ScheduleForegroundApplication()).Times(1); + EXPECT_CALL(*mockAppStateCallbackStub_, OnAppStateChanged(_)).Times(1); + } + + serviceInner_->UpdateAbilityState(token, AbilityState::ABILITY_STATE_FOREGROUND); + + if (!isChange) { + ASSERT_NE(appRunningRecord, nullptr); + int32_t recordId = appRunningRecord->GetRecordId(); + serviceInner_->ApplicationForegrounded(recordId); + } +} + +void AmsAppLifeCycleModuleTest::ChangeAbilityStateToBackGroud(const sptr &mockAppScheduler, + const std::shared_ptr &appRunningRecord, const sptr &token, + const bool isChange) const +{ + if (!isChange) { + EXPECT_CALL(*mockAppScheduler, ScheduleBackgroundApplication()).Times(1); + EXPECT_CALL(*mockAppStateCallbackStub_, OnAppStateChanged(_)).Times(1); + } + + serviceInner_->UpdateAbilityState(token, AbilityState::ABILITY_STATE_BACKGROUND); + + if (!isChange) { + ASSERT_NE(appRunningRecord, nullptr); + int32_t recordId = appRunningRecord->GetRecordId(); + serviceInner_->ApplicationBackgrounded(recordId); + } +} + +void AmsAppLifeCycleModuleTest::ChangeAppToTerminate(const sptr &mockAppScheduler, + const std::shared_ptr &appRunningRecord, const sptr &token, + const bool isStop) const +{ + ChangeAbilityStateToTerminate(mockAppScheduler, token); + + if (isStop) { + EXPECT_CALL(*mockAppScheduler, ScheduleTerminateApplication()).Times(1); + EXPECT_CALL(*mockAppStateCallbackStub_, OnAppStateChanged(_)).Times(1); + serviceInner_->AbilityTerminated(token); + ASSERT_NE(appRunningRecord, nullptr); + int32_t recordId = appRunningRecord->GetRecordId(); + serviceInner_->ApplicationTerminated(recordId); + } else { + serviceInner_->AbilityTerminated(token); + } +} + +void AmsAppLifeCycleModuleTest::ChangeAbilityStateToTerminate( + const sptr &mockAppScheduler, const sptr &token) const +{ + EXPECT_CALL(*mockAppScheduler, ScheduleCleanAbility(_)).Times(1); + serviceInner_->TerminateAbility(token); +} + +void AmsAppLifeCycleModuleTest::CheckState(const std::shared_ptr &appRunningRecord, + const sptr &token, const AbilityState abilityState, const ApplicationState appState) const +{ + ASSERT_NE(appRunningRecord, nullptr); + auto abilityRunningRecord = appRunningRecord->GetAbilityRunningRecordByToken(token); + ApplicationState getAppState = appRunningRecord->GetState(); + EXPECT_EQ(appState, getAppState); + ASSERT_NE(abilityRunningRecord, nullptr); + AbilityState getAbilityState = abilityRunningRecord->GetState(); + EXPECT_EQ(abilityState, getAbilityState); +} + +void AmsAppLifeCycleModuleTest::CheckStateAfterClearAbility(const std::shared_ptr &appRunningRecord, + const std::vector> &tokens, const int32_t &recordId, + const sptr &mockAppScheduler) const +{ + unsigned long size = tokens.size(); + for (unsigned long i = 0; i < size; i++) { + if (i != size - 1) { + ChangeAppToTerminate(mockAppScheduler, appRunningRecord, tokens[i], false); + ApplicationState getAppState = appRunningRecord->GetState(); + EXPECT_EQ(ApplicationState::APP_STATE_BACKGROUND, getAppState); + } else { + ChangeAppToTerminate(mockAppScheduler, appRunningRecord, tokens[i], true); + auto record = serviceInner_->GetAppRunningRecordByAppRecordId(recordId); + EXPECT_EQ(nullptr, record); + } + } +} + +void AmsAppLifeCycleModuleTest::CheckStateAfterChangeAbility(const std::shared_ptr &appRunningRecord, + const std::vector> &tokens, const sptr &mockAppScheduler) +{ + unsigned long size = tokens.size(); + for (unsigned long i = 0; i < size; i++) { + if (i != size - 1) { + ChangeAbilityStateToBackGroud(mockAppScheduler, appRunningRecord, tokens[i], true); + CheckState(appRunningRecord, + tokens[i], + AbilityState::ABILITY_STATE_BACKGROUND, + ApplicationState::APP_STATE_FOREGROUND); + } else { + ChangeAbilityStateToBackGroud(mockAppScheduler, appRunningRecord, tokens[i], false); + CheckState(appRunningRecord, + tokens[i], + AbilityState::ABILITY_STATE_BACKGROUND, + ApplicationState::APP_STATE_BACKGROUND); + } + } +} + +void AmsAppLifeCycleModuleTest::CreateAppRecentList(const int32_t appNum) +{ + for (int32_t i = INDEX_NUM_MAX - appNum + 1; i <= INDEX_NUM_MAX; i++) { + std::shared_ptr appInfo = std::make_shared(); + std::shared_ptr abilityInfo = std::make_shared(); + appInfo->name = TEST_APP_NAME + std::to_string(i); + appInfo->bundleName = appInfo->name; + abilityInfo->name = TEST_ABILITY_NAME + std::to_string(i); + abilityInfo->applicationName = TEST_APP_NAME + std::to_string(i); + pid_t pid = i; + sptr token = new (std::nothrow) MockAbilityToken(); + MockAppSpawnClient *mockedSpawnClient = new (std::nothrow) MockAppSpawnClient(); + EXPECT_TRUE(mockedSpawnClient); + EXPECT_CALL(*mockedSpawnClient, StartProcess(_, _)) + .Times(1) + .WillOnce(DoAll(SetArgReferee<1>(pid), Return(ERR_OK))); + EXPECT_CALL(*mockAppStateCallbackStub_, OnAppStateChanged(_)).Times(1); + + serviceInner_->SetAppSpawnClient(std::unique_ptr(mockedSpawnClient)); + serviceInner_->LoadAbility(token, nullptr, abilityInfo, appInfo); + } + return; +} + +sptr AmsAppLifeCycleModuleTest::GetAbilityToken() +{ + if (mockToken_ != nullptr) { + return mockToken_; + } + mockToken_ = new (std::nothrow) MockAbilityToken(); + return mockToken_; +} + +void InvokeOnAbilityRequestDone(const sptr &obj, const AbilityState state) +{ + EXPECT_EQ(state, AbilityState::ABILITY_STATE_BACKGROUND); +} + +/* + * Feature: Ams + * Function: AppLifeCycle + * SubFunction: NA + * FunctionPoints: test app life cycle change with the start of ability + * EnvConditions: system running normally + * CaseDescription: 1.call loadAbility API to start app + * 2.switch ability to foreground and call ScheduleForegroundApplication API to enable Application + * foreground + * 3.switch ability to background and call ScheduleBackgroundApplication API to enable Application + * background + * 4.terminate ability + * 5.call ScheduleTerminateApplication API to make app terminated + */ +HWTEST_F(AmsAppLifeCycleModuleTest, StateChange_001, TestSize.Level2) +{ + ASSERT_NE(serviceInner_, nullptr); + pid_t pid = 1024; + sptr token = GetAbilityToken(); + 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); + + TestProcessInfo testProcessInfo; + testProcessInfo.pid = pid; + testProcessInfo.isStart = false; + auto appRunningRecord = StartProcessAndLoadAbility(mockAppScheduler, token, abilityInfo, appInfo, testProcessInfo); + int32_t recordId = appRunningRecord->GetRecordId(); + + ChangeAbilityStateAfterAppStart(mockAppScheduler, pid); + CheckState(appRunningRecord, token, AbilityState::ABILITY_STATE_READY, ApplicationState::APP_STATE_READY); + + ChangeAbilityStateToForegroud(mockAppScheduler, appRunningRecord, token); + CheckState(appRunningRecord, token, AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + + ChangeAbilityStateToBackGroud(mockAppScheduler, appRunningRecord, token); + CheckState(appRunningRecord, token, AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + + ChangeAppToTerminate(mockAppScheduler, appRunningRecord, token, true); + auto record = serviceInner_->GetAppRunningRecordByAppRecordId(recordId); + EXPECT_EQ(nullptr, record); +} + +/* + * Feature: Ams + * Function: AppLifeCycle + * SubFunction: NA + * FunctionPoints: test app life cycle change with the start of abilities + * EnvConditions: system running normally + * CaseDescription: 1.call loadAbility API to start app + * 2.switch ability to foreground and call ScheduleForegroundApplication API to enable Application + * foreground + * 3.load other ability, and switch last ability to background and call ScheduleBackgroundApplication + * API to enable Application background + * 4.terminate every ability + * 5.call ScheduleTerminateApplication API to make app terminated + */ +HWTEST_F(AmsAppLifeCycleModuleTest, StateChange_002, TestSize.Level3) +{ + pid_t pid = 1023; + ASSERT_NE(serviceInner_, nullptr); + std::shared_ptr appRunningRecord = nullptr; + std::vector> tokens; + auto abilityInfo = std::make_shared(); + auto appInfo = std::make_shared(); + sptr token; + int32_t recordId; + bool flag = false; + sptr mockAppScheduler = new (std::nothrow) MockAppScheduler(); + + TestProcessInfo testProcessInfo; + testProcessInfo.pid = pid; + + for (int i = 0; i < ABILITY_NUM; i++) { + abilityInfo = GetAbilityInfo(std::to_string(i), "MainAbility", "p1", "com.ohos.test.helloworld"); + appInfo = GetApplicationInfo("com.ohos.test.helloworld"); + token = new (std::nothrow) MockAbilityToken(); + tokens.push_back(token); + testProcessInfo.isStart = flag; + appRunningRecord = StartProcessAndLoadAbility(mockAppScheduler, token, abilityInfo, appInfo, testProcessInfo); + if (!flag) { + ChangeAbilityStateAfterAppStart(mockAppScheduler, pid); + recordId = appRunningRecord->GetRecordId(); + flag = true; + CheckState(appRunningRecord, token, AbilityState::ABILITY_STATE_READY, ApplicationState::APP_STATE_READY); + } else { + CheckState( + appRunningRecord, token, AbilityState::ABILITY_STATE_READY, ApplicationState::APP_STATE_BACKGROUND); + } + ChangeAbilityStateToForegroud(mockAppScheduler, appRunningRecord, token); + CheckState( + appRunningRecord, token, AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + ChangeAbilityStateToBackGroud(mockAppScheduler, appRunningRecord, token); + CheckState( + appRunningRecord, token, AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + } + auto abilities = appRunningRecord->GetAbilities(); + int size = abilities.size(); + EXPECT_EQ(size, ABILITY_NUM); + CheckStateAfterClearAbility(appRunningRecord, tokens, recordId, mockAppScheduler); +} + +/* + * Feature: Ams + * Function: AppLifeCycle + * SubFunction: NA + * FunctionPoints: test app life cycle change with the start of abilities at the same time + * EnvConditions: system running normally + * CaseDescription: 1.call loadAbility API to start 1000 abilities + * 2.switch every ability to foreground + * 3.switch every ability to background + * 4.terminate every ability + * 5.call ScheduleTerminateApplication API to make app terminated + */ +HWTEST_F(AmsAppLifeCycleModuleTest, StateChange_003, TestSize.Level3) +{ + pid_t pid = 1025; + ASSERT_TRUE(serviceInner_); + std::shared_ptr appRunningRecord = nullptr; + std::vector> tokens; + auto abilityInfo = std::make_shared(); + auto appInfo = std::make_shared(); + sptr token; + int32_t recordId; + bool flag = false; + sptr mockAppScheduler = new (std::nothrow) MockAppScheduler(); + + TestProcessInfo testProcessInfo; + testProcessInfo.pid = pid; + + for (int i = 0; i < ABILITY_NUM; i++) { + abilityInfo = GetAbilityInfo(std::to_string(i), "MainAbility", "p1", "com.ohos.test.helloworld1"); + appInfo = GetApplicationInfo("com.ohos.test.helloworld1"); + token = new (std::nothrow) MockAbilityToken(); + tokens.push_back(token); + + testProcessInfo.isStart = flag; + appRunningRecord = StartProcessAndLoadAbility(mockAppScheduler, token, abilityInfo, appInfo, testProcessInfo); + if (!flag) { + ChangeAbilityStateAfterAppStart(mockAppScheduler, testProcessInfo.pid); + recordId = appRunningRecord->GetRecordId(); + flag = true; + CheckState(appRunningRecord, token, AbilityState::ABILITY_STATE_READY, ApplicationState::APP_STATE_READY); + ChangeAbilityStateToForegroud(mockAppScheduler, appRunningRecord, token); + } else { + CheckState( + appRunningRecord, token, AbilityState::ABILITY_STATE_READY, ApplicationState::APP_STATE_FOREGROUND); + ChangeAbilityStateToForegroud(mockAppScheduler, appRunningRecord, token, true); + } + } + CheckStateAfterChangeAbility(appRunningRecord, tokens, mockAppScheduler); + CheckStateAfterClearAbility(appRunningRecord, tokens, recordId, mockAppScheduler); +} + +/* + * Feature: Ams + * Function: AppLifeCycle + * SubFunction: NA + * FunctionPoints: test app life cycle change with the start of abilities + * EnvConditions: system running normally + * CaseDescription: 1.call loadAbility API to start app + * 2.switch ability to foreground and call ScheduleForegroundApplication API to enable Application + * foreground + * 3.switch ability to background and call ScheduleBackgroundApplication API to enable Application + * background + * 4.repeat step 2~3 1000 times + */ +HWTEST_F(AmsAppLifeCycleModuleTest, StateChange_004, TestSize.Level3) +{ + ASSERT_NE(serviceInner_, nullptr); + pid_t pid = 1024; + sptr token = GetAbilityToken(); + auto abilityInfo = GetAbilityInfo("0", "MainAbility", "p3", "com.ohos.test.helloworld"); + auto appInfo = GetApplicationInfo("com.ohos.test.helloworld"); + + sptr mockAppScheduler = new (std::nothrow) MockAppScheduler(); + + TestProcessInfo testProcessInfo; + testProcessInfo.pid = pid; + testProcessInfo.isStart = false; + + auto appRunningRecord = StartProcessAndLoadAbility(mockAppScheduler, token, abilityInfo, appInfo, testProcessInfo); + + ChangeAbilityStateAfterAppStart(mockAppScheduler, pid); + CheckState(appRunningRecord, token, AbilityState::ABILITY_STATE_READY, ApplicationState::APP_STATE_READY); + + int count = 1000; + while (count > 0) { + ChangeAbilityStateToForegroud(mockAppScheduler, appRunningRecord, token); + CheckState( + appRunningRecord, token, AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + + ChangeAbilityStateToBackGroud(mockAppScheduler, appRunningRecord, token); + CheckState( + appRunningRecord, token, AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + count--; + } +} + +/* + * Feature: Ams + * Function: AppLifeCycle + * SubFunction: NA + * FunctionPoints: test app life cycle change with the start of ability + * EnvConditions: system running normally + * CaseDescription: 1.call loadAbility API to start app + * 2.switch ability to foreground and call ScheduleForegroundApplication API to enable Application + * foreground + * 3.switch ability to background + * 4.start new ability to foreground + * 5.switch ability to background and call ScheduleBackgroundApplication API to enable Application + * background + * 6.call ScheduleTerminateApplication API to make app terminated + */ +HWTEST_F(AmsAppLifeCycleModuleTest, StateChange_005, TestSize.Level2) +{ + ASSERT_NE(serviceInner_, nullptr); + pid_t pid = 1024; + + sptr token0 = new (std::nothrow) MockAbilityToken(); + auto abilityInfo0 = GetAbilityInfo("0", "MainAbility", "p1", "com.ohos.test.helloworld"); + auto appInfo = GetApplicationInfo("com.ohos.test.helloworld"); + + sptr mockAppScheduler = new (std::nothrow) MockAppScheduler(); + + TestProcessInfo testProcessInfo; + testProcessInfo.pid = pid; + testProcessInfo.isStart = false; + + auto appRunningRecord = + StartProcessAndLoadAbility(mockAppScheduler, token0, abilityInfo0, appInfo, testProcessInfo); + + int32_t recordId = appRunningRecord->GetRecordId(); + + ChangeAbilityStateAfterAppStart(mockAppScheduler, pid); + CheckState(appRunningRecord, token0, AbilityState::ABILITY_STATE_READY, ApplicationState::APP_STATE_READY); + + ChangeAbilityStateToForegroud(mockAppScheduler, appRunningRecord, token0); + CheckState( + appRunningRecord, token0, AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + + ChangeAbilityStateToBackGroud(mockAppScheduler, appRunningRecord, token0); + CheckState( + appRunningRecord, token0, AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + + sptr token1 = new (std::nothrow) MockAbilityToken(); + auto abilityInfo1 = GetAbilityInfo("1", "SubAbility", "p1", "com.ohos.test.helloworld"); + testProcessInfo.isStart = true; + appRunningRecord = StartProcessAndLoadAbility(mockAppScheduler, token1, abilityInfo1, appInfo, testProcessInfo); + + ChangeAbilityStateToForegroud(mockAppScheduler, appRunningRecord, token1); + CheckState( + appRunningRecord, token1, AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + + ChangeAbilityStateToBackGroud(mockAppScheduler, appRunningRecord, token1); + CheckState( + appRunningRecord, token1, AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + + ChangeAppToTerminate(mockAppScheduler, appRunningRecord, token0); + ChangeAppToTerminate(mockAppScheduler, appRunningRecord, token1, true); + auto record = serviceInner_->GetAppRunningRecordByAppRecordId(recordId); + EXPECT_EQ(nullptr, record); +} + +/* + * Feature: Ams + * Function: AppLifeCycle + * SubFunction: NA + * FunctionPoints: test app life cycle change with the start of ability + * EnvConditions: system running normally + * CaseDescription: 1.call loadAbility API to start app + * 2.switch ability to foreground and call ScheduleForegroundApplication API to enable Application + * foreground + * 3.switch ability to background and call ScheduleBackgroundApplication API to enable Application + * background + * 4.through appName kill application + */ +HWTEST_F(AmsAppLifeCycleModuleTest, StateChange_006, TestSize.Level2) +{ + ASSERT_NE(serviceInner_, nullptr); + + pid_t pid = fork(); + if (pid == 0) { + pause(); + exit(0); + } + + ASSERT_TRUE(pid > 0); + usleep(50000); + + sptr token = GetAbilityToken(); + auto abilityInfo = GetAbilityInfo("0", "MainAbility", "p1", "com.ohos.test.helloworld"); + auto appInfo = GetApplicationInfo("com.ohos.test.helloworld"); + appInfo->bundleName = "com.ohos.test.helloworld"; + sptr mockAppScheduler = new (std::nothrow) MockAppScheduler(); + + TestProcessInfo testProcessInfo; + testProcessInfo.pid = pid; + testProcessInfo.isStart = false; + + auto appRunningRecord = StartProcessAndLoadAbility(mockAppScheduler, token, abilityInfo, appInfo, testProcessInfo); + int32_t recordId = appRunningRecord->GetRecordId(); + + ChangeAbilityStateAfterAppStart(mockAppScheduler, pid); + CheckState(appRunningRecord, token, AbilityState::ABILITY_STATE_READY, ApplicationState::APP_STATE_READY); + + ChangeAbilityStateToForegroud(mockAppScheduler, appRunningRecord, token); + CheckState(appRunningRecord, token, AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + + ChangeAbilityStateToBackGroud(mockAppScheduler, appRunningRecord, token); + CheckState(appRunningRecord, token, AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + + EXPECT_CALL(*mockAppScheduler, ScheduleProcessSecurityExit()).Times(1); + int32_t ret = serviceInner_->KillApplication(appInfo->bundleName); + EXPECT_EQ(ret, 0); + serviceInner_->OnRemoteDied(mockAppScheduler); // A faked death recipient. + auto record = serviceInner_->GetAppRunningRecordByAppRecordId(recordId); + EXPECT_EQ(nullptr, record); +} + +/* + * Feature: Ams + * Function: AppLifeCycle + * SubFunction: NA + * FunctionPoints: test app life cycle change with the start of ability + * EnvConditions: system running normally + * CaseDescription: 1.call loadAbility API to start app + * 2.switch ability to foreground and call ScheduleForegroundApplication API to enable Application + * foreground + * 3.switch ability to background and call ScheduleBackgroundApplication API to enable Application + * background + * 4.terminate ability + * 5.call ScheduleTerminateApplication API to make app terminated + */ +HWTEST_F(AmsAppLifeCycleModuleTest, StateChange_007, TestSize.Level2) +{ + ASSERT_NE(serviceInner_, nullptr); + pid_t pid = 1024; + sptr token = GetAbilityToken(); + auto abilityInfo = GetAbilityInfo("0", "MainAbility", "p1", "com.ohos.test.helloworld"); + auto appInfo = GetApplicationInfo("com.ohos.test.helloworld"); + sptr mockAppScheduler = new (std::nothrow) MockAppScheduler(); + + TestProcessInfo testProcessInfo; + testProcessInfo.pid = pid; + testProcessInfo.isStart = false; + + auto appRunningRecord = StartProcessAndLoadAbility(mockAppScheduler, token, abilityInfo, appInfo, testProcessInfo); + int32_t recordId = appRunningRecord->GetRecordId(); + + ChangeAbilityStateAfterAppStart(mockAppScheduler, pid); + CheckState(appRunningRecord, token, AbilityState::ABILITY_STATE_READY, ApplicationState::APP_STATE_READY); + + ChangeAbilityStateToForegroud(mockAppScheduler, appRunningRecord, token); + CheckState(appRunningRecord, token, AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + + ChangeAbilityStateToBackGroud(mockAppScheduler, appRunningRecord, token); + CheckState(appRunningRecord, token, AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + + ChangeAppToTerminate(mockAppScheduler, appRunningRecord, token, true); + auto record = serviceInner_->GetAppRunningRecordByAppRecordId(recordId); + EXPECT_EQ(nullptr, record); +} + +/* + * Feature: Ams + * Function: AppLifeCycle + * SubFunction: NA + * FunctionPoints: test app life cycle change with the start of ability + * EnvConditions: system running normally + * CaseDescription: 1.call loadAbility API to start app + * 2.switch ability to foreground and call ScheduleForegroundApplication API to enable Application + * foreground + * 3.switch ability to background and call ScheduleBackgroundApplication API to enable Application + * background + * 4.call loadAbility API to start new app + * 5.switch ability to foreground and call ScheduleForegroundApplication API to enable new Application + * foreground + * 6.switch ability to background and call ScheduleBackgroundApplication API to enable new Application + * background + * 7.terminate ability + * 8.call ScheduleTerminateApplication API to make app terminated + */ +HWTEST_F(AmsAppLifeCycleModuleTest, StateChange_008, TestSize.Level2) +{ + ASSERT_NE(serviceInner_, nullptr); + pid_t pid_0 = 1024; + pid_t pid_1 = 2048; + sptr token_0 = new (std::nothrow) MockAbilityToken(); + sptr token_1 = new (std::nothrow) MockAbilityToken(); + auto abilityInfo_0 = GetAbilityInfo("0", "MainAbility", "p1", "com.ohos.test.helloworld_0"); + auto appInfo_0 = GetApplicationInfo("com.ohos.test.helloworld_0"); + auto abilityInfo_1 = GetAbilityInfo("0", "MainAbility", "p1", "com.ohos.test.helloworld_1"); + auto appInfo_1 = GetApplicationInfo("com.ohos.test.helloworld_1"); + sptr mockAppScheduler = new (std::nothrow) MockAppScheduler(); + TestProcessInfo testProcessInfo; + + testProcessInfo.pid = pid_0; + testProcessInfo.isStart = false; + auto appRunningRecord_0 = + StartProcessAndLoadAbility(mockAppScheduler, token_0, abilityInfo_0, appInfo_0, testProcessInfo); + + testProcessInfo.pid = pid_1; + testProcessInfo.isStart = false; + auto appRunningRecord_1 = + StartProcessAndLoadAbility(mockAppScheduler, token_1, abilityInfo_1, appInfo_1, testProcessInfo); + int32_t recordId_0 = appRunningRecord_0->GetRecordId(); + int32_t recordId_1 = appRunningRecord_1->GetRecordId(); + + ChangeAbilityStateAfterAppStart(mockAppScheduler, pid_0); + CheckState(appRunningRecord_0, token_0, AbilityState::ABILITY_STATE_READY, ApplicationState::APP_STATE_READY); + + ChangeAbilityStateToForegroud(mockAppScheduler, appRunningRecord_0, token_0); + CheckState( + appRunningRecord_0, token_0, AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + + ChangeAbilityStateToBackGroud(mockAppScheduler, appRunningRecord_0, token_0); + CheckState( + appRunningRecord_0, token_0, AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + + ChangeAbilityStateAfterAppStart(mockAppScheduler, pid_1); + CheckState(appRunningRecord_1, token_1, AbilityState::ABILITY_STATE_READY, ApplicationState::APP_STATE_READY); + + ChangeAbilityStateToForegroud(mockAppScheduler, appRunningRecord_1, token_1); + CheckState( + appRunningRecord_1, token_1, AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + + ChangeAbilityStateToBackGroud(mockAppScheduler, appRunningRecord_1, token_1); + CheckState( + appRunningRecord_1, token_1, AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + + ChangeAppToTerminate(mockAppScheduler, appRunningRecord_0, token_0, true); + auto record = serviceInner_->GetAppRunningRecordByAppRecordId(recordId_0); + EXPECT_EQ(nullptr, record); + + ChangeAppToTerminate(mockAppScheduler, appRunningRecord_1, token_1, true); + record = serviceInner_->GetAppRunningRecordByAppRecordId(recordId_1); + EXPECT_EQ(nullptr, record); +} + +/* + * Feature: Ams + * Function: AppLifeCycle + * SubFunction: NA + * FunctionPoints: test app life cycle change with the start of abilities at the same time + * EnvConditions: system running normally + * CaseDescription: 1.call loadAbility API to start 100 app + * 2.switch every ability to foreground + * 3.switch every ability to background + * 4.terminate every ability + * 5.call ScheduleTerminateApplication API to make app terminated + */ +HWTEST_F(AmsAppLifeCycleModuleTest, StateChange_009, TestSize.Level3) +{ + pid_t pid = 1025; + ASSERT_NE(serviceInner_, nullptr); + std::shared_ptr appRunningRecord = nullptr; + auto abilityInfo = std::make_shared(); + auto appInfo = std::make_shared(); + sptr token; + int32_t recordId; + sptr mockAppScheduler = new (std::nothrow) MockAppScheduler(); + + TestProcessInfo testProcessInfo; + + for (int i = 0; i < APPLICATION_NUM; i++) { + abilityInfo = GetAbilityInfo("0", "MainAbility", "p1", "com.ohos.test.helloworld1"); + appInfo = GetApplicationInfo("com.ohos.test.helloworld1"); + token = new (std::nothrow) MockAbilityToken(); + pid += i; + + testProcessInfo.pid = pid; + testProcessInfo.isStart = false; + appRunningRecord = StartProcessAndLoadAbility(mockAppScheduler, token, abilityInfo, appInfo, testProcessInfo); + ChangeAbilityStateAfterAppStart(mockAppScheduler, testProcessInfo.pid); + recordId = appRunningRecord->GetRecordId(); + CheckState(appRunningRecord, token, AbilityState::ABILITY_STATE_READY, ApplicationState::APP_STATE_READY); + ChangeAbilityStateToForegroud(mockAppScheduler, appRunningRecord, token); + + ChangeAbilityStateToBackGroud(mockAppScheduler, appRunningRecord, token); + CheckState( + appRunningRecord, token, AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + + ChangeAppToTerminate(mockAppScheduler, appRunningRecord, token, true); + auto record = serviceInner_->GetAppRunningRecordByAppRecordId(recordId); + EXPECT_EQ(nullptr, record); + } +} + +/* + * Feature: Ams + * Function: AppLifeCycle + * SubFunction: NA + * FunctionPoints: test get and stop all process. + * EnvConditions: system running normally + * CaseDescription: 1.call loadAbility API to start 100 app + * 2.stop all process + */ +HWTEST_F(AmsAppLifeCycleModuleTest, StateChange_010, TestSize.Level3) +{ + pid_t pid = 1025; + ASSERT_NE(serviceInner_, nullptr); + std::shared_ptr appRunningRecord = nullptr; + int32_t recordId[APPLICATION_NUM]; + sptr mockAppScheduler[APPLICATION_NUM]; + + TestProcessInfo testProcessInfo; + for (int i = 0; i < APPLICATION_NUM; i++) { + mockAppScheduler[i] = new MockAppScheduler(); + + char index[32]; + int ref = snprintf_s(index, sizeof(index), sizeof(index) - 1, "%d", i); + ASSERT_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); + auto abilityInfo = GetAbilityInfo(index, "MainAbility", index, name); + auto appInfo = GetApplicationInfo(name); + auto token = new (std::nothrow) MockAbilityToken(); + pid += i; + + testProcessInfo.pid = pid; + testProcessInfo.isStart = false; + + appRunningRecord = + StartProcessAndLoadAbility(mockAppScheduler[i], token, abilityInfo, appInfo, testProcessInfo); + ASSERT_TRUE(appRunningRecord); + + ChangeAbilityStateAfterAppStart(mockAppScheduler[i], testProcessInfo.pid); + + recordId[i] = appRunningRecord->GetRecordId(); + + CheckState(appRunningRecord, token, AbilityState::ABILITY_STATE_READY, ApplicationState::APP_STATE_READY); + ChangeAbilityStateToForegroud(mockAppScheduler[i], appRunningRecord, token); + + ChangeAbilityStateToBackGroud(mockAppScheduler[i], appRunningRecord, token); + CheckState( + appRunningRecord, token, AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + EXPECT_CALL(*mockAppScheduler[i], ScheduleProcessSecurityExit()).Times(1); + } + + sptr bundleMgr = new BundleMgrService(); + serviceInner_->SetBundleManager(bundleMgr.GetRefPtr()); + auto allRunningProcessInfo = std::make_shared(); + serviceInner_->GetAllRunningProcesses(allRunningProcessInfo); + EXPECT_EQ(allRunningProcessInfo->appProcessInfos.size(), size_t(APPLICATION_NUM)); + + serviceInner_->StopAllProcess(); + + for (int i = 0; i < APPLICATION_NUM; i++) { + serviceInner_->OnRemoteDied(mockAppScheduler[i]); // A faked death recipient. + auto record = serviceInner_->GetAppRunningRecordByAppRecordId(recordId[i]); + EXPECT_EQ(nullptr, record); + } +} + +/* + * Feature: Ams + * Function: AppLifeCycle + * SubFunction: NA + * FunctionPoints: test getrecentapplist and removeappfromrecentlist all process. + * EnvConditions: system running normally + * CaseDescription: 1.call getrecentapplist API to get current app list + * 2.call removeappfromrecentlist API to remove current app list + */ +HWTEST_F(AmsAppLifeCycleModuleTest, StateChange_011, TestSize.Level0) +{ + EXPECT_TRUE(serviceInner_->GetRecentAppList().empty()); + CreateAppRecentList(INDEX_NUM_100); + EXPECT_EQ(INDEX_NUM_100, static_cast(serviceInner_->GetRecentAppList().size())); + for (int32_t i = INDEX_NUM_MAX; i > 0; i--) { + std::shared_ptr appInfo = std::make_shared(); + appInfo->name = TEST_APP_NAME + std::to_string(i); + appInfo->bundleName = appInfo->name; // specify process condition + auto appTaskInfo = + serviceInner_->appProcessManager_->GetAppTaskInfoByProcessName(appInfo->name, appInfo->bundleName); + serviceInner_->appProcessManager_->RemoveAppFromRecentList(appTaskInfo); + } + EXPECT_TRUE(serviceInner_->GetRecentAppList().empty()); +} + +/* + * Feature: Ams + * Function: AppLifeCycle + * SubFunction: NA + * FunctionPoints: test getrecentapplist and clearrecentappList all process. + * EnvConditions: system running normally + * CaseDescription: 1.call getrecentapplist API to get current app list + * 2.call clearrecentapplist API to clear current app list + */ +HWTEST_F(AmsAppLifeCycleModuleTest, StateChange_012, TestSize.Level0) +{ + EXPECT_TRUE(serviceInner_->GetRecentAppList().empty()); + CreateAppRecentList(INDEX_NUM_100); + EXPECT_EQ(INDEX_NUM_100, static_cast(serviceInner_->GetRecentAppList().size())); + + serviceInner_->appProcessManager_->ClearRecentAppList(); + EXPECT_TRUE(serviceInner_->GetRecentAppList().empty()); +} + +/* + * Feature: Ams + * Function: AppLifeCycle + * SubFunction: NA + * FunctionPoints: test get and stop all process. + * EnvConditions: system running normally + * CaseDescription: OnStop + */ +HWTEST_F(AmsAppLifeCycleModuleTest, StateChange_013, TestSize.Level3) +{ + ASSERT_TRUE(serviceInner_); + ASSERT_TRUE(serviceInner_->remoteClientManager_); + ASSERT_TRUE(serviceInner_->remoteClientManager_->GetSpawnClient()); + + auto mockAppSpawnSocket = std::make_shared(); + ASSERT_TRUE(mockAppSpawnSocket); + serviceInner_->remoteClientManager_->GetSpawnClient()->SetSocket(mockAppSpawnSocket); + + EXPECT_EQ(serviceInner_->QueryAppSpawnConnectionState(), SpawnConnectionState::STATE_NOT_CONNECT); + + EXPECT_CALL(*mockAppSpawnSocket, OpenAppSpawnConnection()).Times(1).WillOnce(Return(0)); + + int ret = serviceInner_->OpenAppSpawnConnection(); + ASSERT_EQ(ret, 0); + EXPECT_EQ(serviceInner_->QueryAppSpawnConnectionState(), SpawnConnectionState::STATE_CONNECTED); + + EXPECT_CALL(*mockAppSpawnSocket, CloseAppSpawnConnection()).Times(1); + + serviceInner_->OnStop(); + usleep(50000); + EXPECT_EQ(serviceInner_->QueryAppSpawnConnectionState(), SpawnConnectionState::STATE_NOT_CONNECT); +} + +/* + * Feature: Ams + * Function: AppLifeCycle + * SubFunction: NA + * FunctionPoints: test get app Running Record,When the app is added for the first time + * EnvConditions: system running normally + * CaseDescription: GetOrCreateAppRunningRecord + */ +HWTEST_F(AmsAppLifeCycleModuleTest, StateChange_014, TestSize.Level0) +{ + + pid_t pid = 1000; + sptr token = GetAbilityToken(); + auto abilityInfo = GetAbilityInfo("0", "MainAbility", "p1", "com.ohos.test.special"); + auto appInfo = GetApplicationInfo("com.ohos.test.special"); + sptr mockAppScheduler = new MockAppScheduler(); + TestProcessInfo testProcessInfo; + testProcessInfo.pid = pid; + testProcessInfo.isStart = false; + auto appRunningRecord = StartProcessAndLoadAbility(mockAppScheduler, token, abilityInfo, appInfo, testProcessInfo); + + // Because GetOrCreateAppRunningRecord was called in LoadAbility. + // When the app is added for the first time + EXPECT_EQ(appRunningRecord->GetName(), "com.ohos.test.special"); + EXPECT_EQ(appRunningRecord->GetProcessName(), "p1"); +} + +/* + * Feature: Ams + * Function: AppLifeCycle + * SubFunction: NA + * FunctionPoints: Ability Status change received + * EnvConditions: system running normally + * CaseDescription: OnAbilityRequestDone + */ +HWTEST_F(AmsAppLifeCycleModuleTest, StateChange_015, TestSize.Level0) +{ + pid_t pid = 1000; + sptr token = GetAbilityToken(); + auto abilityInfo = GetAbilityInfo("0", "MainAbility", "p1", "com.ohos.test.special"); + auto appInfo = GetApplicationInfo("com.ohos.test.special"); + sptr mockAppScheduler = new MockAppScheduler(); + TestProcessInfo testProcessInfo; + testProcessInfo.pid = pid; + testProcessInfo.isStart = false; + + auto appRunningRecord = StartProcessAndLoadAbility(mockAppScheduler, token, abilityInfo, appInfo, testProcessInfo); + + EXPECT_CALL(*mockAppScheduler, ScheduleBackgroundApplication()).Times(1); + EXPECT_CALL(*mockAppStateCallbackStub_, OnAbilityRequestDone(_, _)) + .Times(1) + .WillOnce(testing::Invoke(InvokeOnAbilityRequestDone)); + + ChangeAbilityStateAfterAppStart(mockAppScheduler, testProcessInfo.pid); + CheckState(appRunningRecord, token, AbilityState::ABILITY_STATE_READY, ApplicationState::APP_STATE_READY); + + ChangeAbilityStateToForegroud(mockAppScheduler, appRunningRecord, token); + CheckState(appRunningRecord, token, AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + + std::weak_ptr inner = inner_; + appRunningRecord->SetAppMgrServiceInner(inner); + + appRunningRecord->UpdateAbilityState(token, AbilityState::ABILITY_STATE_BACKGROUND); +} + +/* + * Feature: Ams + * Function: AbilityBehaviorAnalysis + * SubFunction: NA + * FunctionPoints: Ability Status change received + * EnvConditions: system running normally + * CaseDescription: Ability record update(specify process mode) + */ +HWTEST_F(AmsAppLifeCycleModuleTest, AbilityBehaviorAnalysis_01, TestSize.Level0) +{ + const int32_t formateVaule = 0; + const int32_t visibility = 1; + const int32_t perceptibility = 1; + const int32_t connectionState = 1; + + pid_t pid = 123; + sptr token = GetAbilityToken(); + auto abilityInfo = GetAbilityInfo("0", "MainAbility", "pNew", "com.ohos.test.special"); + auto appInfo = GetApplicationInfo("com.ohos.test.special"); + sptr mockAppScheduler = new MockAppScheduler(); + + sptr bundleMgr = new BundleMgrService(); + serviceInner_->SetBundleManager(bundleMgr.GetRefPtr()); + + StartAppProcess(pid); + serviceInner_->LoadAbility(token, nullptr, abilityInfo, appInfo); + std::shared_ptr record = + serviceInner_->GetAppRunningRecordByProcessName(appInfo->name, abilityInfo->process); + if (record == nullptr) { + EXPECT_TRUE(false); + } else { + pid_t newPid = record->GetPriorityObject()->GetPid(); + EXPECT_EQ(newPid, pid); + } + + auto abilityRecord = record->GetAbilityRunningRecordByToken(token); + + EXPECT_EQ(abilityRecord->GetVisibility(), formateVaule); + EXPECT_EQ(abilityRecord->GetPerceptibility(), formateVaule); + EXPECT_EQ(abilityRecord->GetConnectionState(), formateVaule); + + serviceInner_->AbilityBehaviorAnalysis(token, nullptr, visibility, perceptibility, connectionState); + + auto appRecord = serviceInner_->GetAppRunningRecordByAbilityToken(token); + auto abilityRecord_1 = appRecord->GetAbilityRunningRecordByToken(token); + + EXPECT_EQ(abilityRecord_1->GetToken(), token); + EXPECT_EQ(abilityRecord_1->GetPreToken(), nullptr); + EXPECT_EQ(abilityRecord_1->GetVisibility(), visibility); + EXPECT_EQ(abilityRecord_1->GetPerceptibility(), perceptibility); + EXPECT_EQ(abilityRecord_1->GetConnectionState(), connectionState); +} + +/* + * Feature: Ams + * Function: AbilityBehaviorAnalysis + * SubFunction: NA + * FunctionPoints: Ability Status change received + * EnvConditions: system running normally + * CaseDescription: Ability record update(specify process mode and assign visibility) + */ +HWTEST_F(AmsAppLifeCycleModuleTest, AbilityBehaviorAnalysis_02, TestSize.Level0) +{ + const int32_t formateVaule = 0; + const int32_t visibility = 1; + const int32_t perceptibility = 0; + const int32_t connectionState = 0; + + pid_t pid = 123; + sptr token = GetAbilityToken(); + auto abilityInfo = GetAbilityInfo("0", "MainAbility", "pNew", "com.ohos.test.special"); + auto appInfo = GetApplicationInfo("com.ohos.test.special"); + sptr mockAppScheduler = new MockAppScheduler(); + + sptr bundleMgr = new BundleMgrService(); + serviceInner_->SetBundleManager(bundleMgr.GetRefPtr()); + + StartAppProcess(pid); + serviceInner_->LoadAbility(token, nullptr, abilityInfo, appInfo); + std::shared_ptr record = + serviceInner_->GetAppRunningRecordByProcessName(appInfo->name, abilityInfo->process); + if (record == nullptr) { + EXPECT_TRUE(false); + } else { + pid_t newPid = record->GetPriorityObject()->GetPid(); + EXPECT_EQ(newPid, pid); + } + + auto abilityRecord = record->GetAbilityRunningRecordByToken(token); + + EXPECT_EQ(abilityRecord->GetVisibility(), formateVaule); + EXPECT_EQ(abilityRecord->GetPerceptibility(), formateVaule); + EXPECT_EQ(abilityRecord->GetConnectionState(), formateVaule); + + serviceInner_->AbilityBehaviorAnalysis(token, nullptr, visibility, perceptibility, connectionState); + + auto appRecord = serviceInner_->GetAppRunningRecordByAbilityToken(token); + auto abilityRecord_1 = appRecord->GetAbilityRunningRecordByToken(token); + + EXPECT_EQ(abilityRecord_1->GetToken(), token); + EXPECT_EQ(abilityRecord_1->GetPreToken(), nullptr); + EXPECT_EQ(abilityRecord_1->GetVisibility(), visibility); + EXPECT_EQ(abilityRecord_1->GetPerceptibility(), perceptibility); + EXPECT_EQ(abilityRecord_1->GetConnectionState(), connectionState); +} + +/* + * Feature: Ams + * Function: AbilityBehaviorAnalysis + * SubFunction: NA + * FunctionPoints: Ability Status change received + * EnvConditions: system running normally + * CaseDescription: Ability record update(specify process mode and assign perceptibility) + */ +HWTEST_F(AmsAppLifeCycleModuleTest, AbilityBehaviorAnalysis_03, TestSize.Level0) +{ + const int32_t formateVaule = 0; + const int32_t visibility = 0; + const int32_t perceptibility = 1; + const int32_t connectionState = 0; + + pid_t pid = 123; + sptr token = GetAbilityToken(); + auto abilityInfo = GetAbilityInfo("0", "MainAbility", "pNew", "com.ohos.test.special"); + auto appInfo = GetApplicationInfo("com.ohos.test.special"); + sptr mockAppScheduler = new MockAppScheduler(); + + sptr bundleMgr = new BundleMgrService(); + serviceInner_->SetBundleManager(bundleMgr.GetRefPtr()); + + StartAppProcess(pid); + serviceInner_->LoadAbility(token, nullptr, abilityInfo, appInfo); + std::shared_ptr record = + serviceInner_->GetAppRunningRecordByProcessName(appInfo->name, abilityInfo->process); + if (record == nullptr) { + EXPECT_TRUE(false); + } else { + pid_t newPid = record->GetPriorityObject()->GetPid(); + EXPECT_EQ(newPid, pid); + } + + auto abilityRecord = record->GetAbilityRunningRecordByToken(token); + + EXPECT_EQ(abilityRecord->GetVisibility(), formateVaule); + EXPECT_EQ(abilityRecord->GetPerceptibility(), formateVaule); + EXPECT_EQ(abilityRecord->GetConnectionState(), formateVaule); + + serviceInner_->AbilityBehaviorAnalysis(token, nullptr, visibility, perceptibility, connectionState); + + auto appRecord = serviceInner_->GetAppRunningRecordByAbilityToken(token); + auto abilityRecord_1 = appRecord->GetAbilityRunningRecordByToken(token); + + EXPECT_EQ(abilityRecord_1->GetToken(), token); + EXPECT_EQ(abilityRecord_1->GetPreToken(), nullptr); + EXPECT_EQ(abilityRecord_1->GetVisibility(), visibility); + EXPECT_EQ(abilityRecord_1->GetPerceptibility(), perceptibility); + EXPECT_EQ(abilityRecord_1->GetConnectionState(), connectionState); +} + +/* + * Feature: Ams + * Function: AbilityBehaviorAnalysis + * SubFunction: NA + * FunctionPoints: Ability Status change received + * EnvConditions: system running normally + * CaseDescription: Ability record update(specify process mode and assign connectionState) + */ +HWTEST_F(AmsAppLifeCycleModuleTest, AbilityBehaviorAnalysis_04, TestSize.Level0) +{ + const int32_t formateVaule = 0; + const int32_t visibility = 0; + const int32_t perceptibility = 0; + const int32_t connectionState = 1; + + pid_t pid = 123; + sptr token = GetAbilityToken(); + auto abilityInfo = GetAbilityInfo("0", "MainAbility", "pNew", "com.ohos.test.special"); + auto appInfo = GetApplicationInfo("com.ohos.test.special"); + sptr mockAppScheduler = new MockAppScheduler(); + + sptr bundleMgr = new BundleMgrService(); + serviceInner_->SetBundleManager(bundleMgr.GetRefPtr()); + + StartAppProcess(pid); + serviceInner_->LoadAbility(token, nullptr, abilityInfo, appInfo); + std::shared_ptr record = + serviceInner_->GetAppRunningRecordByProcessName(appInfo->name, abilityInfo->process); + if (record == nullptr) { + EXPECT_TRUE(false); + } else { + pid_t newPid = record->GetPriorityObject()->GetPid(); + EXPECT_EQ(newPid, pid); + } + + auto abilityRecord = record->GetAbilityRunningRecordByToken(token); + + EXPECT_EQ(abilityRecord->GetVisibility(), formateVaule); + EXPECT_EQ(abilityRecord->GetPerceptibility(), formateVaule); + EXPECT_EQ(abilityRecord->GetConnectionState(), formateVaule); + + serviceInner_->AbilityBehaviorAnalysis(token, nullptr, visibility, perceptibility, connectionState); + + auto appRecord = serviceInner_->GetAppRunningRecordByAbilityToken(token); + auto abilityRecord_1 = appRecord->GetAbilityRunningRecordByToken(token); + + EXPECT_EQ(abilityRecord_1->GetToken(), token); + EXPECT_EQ(abilityRecord_1->GetPreToken(), nullptr); + EXPECT_EQ(abilityRecord_1->GetVisibility(), visibility); + EXPECT_EQ(abilityRecord_1->GetPerceptibility(), perceptibility); + EXPECT_EQ(abilityRecord_1->GetConnectionState(), connectionState); +} + +/* + * Feature: Ams + * Function: AbilityBehaviorAnalysis + * SubFunction: NA + * FunctionPoints: Ability Status change received + * EnvConditions: system running normally + * CaseDescription: Ability record update(specify process mode and assign proken) + */ +HWTEST_F(AmsAppLifeCycleModuleTest, AbilityBehaviorAnalysis_05, TestSize.Level0) +{ + const int32_t formateVaule = 0; + const int32_t visibility = 0; + const int32_t perceptibility = 0; + const int32_t connectionState = 0; + + pid_t pid = 123; + sptr token = new (std::nothrow) MockAbilityToken(); + auto abilityInfo = GetAbilityInfo("0", "MainAbility", "pNew", "com.ohos.test.special"); + auto appInfo = GetApplicationInfo("com.ohos.test.special"); + sptr mockAppScheduler = new MockAppScheduler(); + + sptr bundleMgr = new BundleMgrService(); + serviceInner_->SetBundleManager(bundleMgr.GetRefPtr()); + + StartAppProcess(pid); + serviceInner_->LoadAbility(token, nullptr, abilityInfo, appInfo); + std::shared_ptr record = + serviceInner_->GetAppRunningRecordByProcessName(appInfo->name, abilityInfo->process); + if (record == nullptr) { + EXPECT_TRUE(false); + } else { + pid_t newPid = record->GetPriorityObject()->GetPid(); + EXPECT_EQ(newPid, pid); + } + + auto abilityRecord = record->GetAbilityRunningRecordByToken(token); + + EXPECT_EQ(abilityRecord->GetVisibility(), formateVaule); + EXPECT_EQ(abilityRecord->GetPerceptibility(), formateVaule); + EXPECT_EQ(abilityRecord->GetConnectionState(), formateVaule); + + sptr preToken = new (std::nothrow) MockAbilityToken(); + serviceInner_->AbilityBehaviorAnalysis(token, preToken, visibility, perceptibility, connectionState); + + auto appRecord = serviceInner_->GetAppRunningRecordByAbilityToken(token); + auto abilityRecord_1 = appRecord->GetAbilityRunningRecordByToken(token); + + EXPECT_EQ(abilityRecord_1->GetToken(), token); + EXPECT_EQ(abilityRecord_1->GetPreToken(), preToken); + EXPECT_EQ(abilityRecord_1->GetVisibility(), visibility); + EXPECT_EQ(abilityRecord_1->GetPerceptibility(), perceptibility); + EXPECT_EQ(abilityRecord_1->GetConnectionState(), connectionState); +} + +/* + * Feature: Ams + * Function: AbilityBehaviorAnalysis + * SubFunction: NA + * FunctionPoints: Ability Status change received + * EnvConditions: system running normally + * CaseDescription: Ability record update(specify process mode and assign bundleName) + */ +HWTEST_F(AmsAppLifeCycleModuleTest, AbilityBehaviorAnalysis_06, TestSize.Level0) +{ + const int32_t formateVaule = 0; + const int32_t visibility = 0; + const int32_t perceptibility = 0; + const int32_t connectionState = 0; + + pid_t pid = 123; + sptr token = new (std::nothrow) MockAbilityToken(); + auto abilityInfo = GetAbilityInfo("0", "MainAbility", "pNew", "com.ohos.test.special"); + auto appInfo = GetApplicationInfo("com.ohos.test.special"); + appInfo->bundleName = appInfo->name; + sptr mockAppScheduler = new MockAppScheduler(); + + sptr bundleMgr = new BundleMgrService(); + serviceInner_->SetBundleManager(bundleMgr.GetRefPtr()); + + StartAppProcess(pid); + serviceInner_->LoadAbility(token, nullptr, abilityInfo, appInfo); + std::shared_ptr record = + serviceInner_->GetAppRunningRecordByProcessName(appInfo->name, abilityInfo->process); + if (record == nullptr) { + EXPECT_TRUE(false); + } else { + pid_t newPid = record->GetPriorityObject()->GetPid(); + EXPECT_EQ(newPid, pid); + } + + auto abilityRecord = record->GetAbilityRunningRecordByToken(token); + + EXPECT_EQ(abilityRecord->GetVisibility(), formateVaule); + EXPECT_EQ(abilityRecord->GetPerceptibility(), formateVaule); + EXPECT_EQ(abilityRecord->GetConnectionState(), formateVaule); + + sptr preToken = new (std::nothrow) MockAbilityToken(); + serviceInner_->AbilityBehaviorAnalysis(token, preToken, visibility, perceptibility, connectionState); + + auto appRecord = serviceInner_->GetAppRunningRecordByAbilityToken(token); + auto abilityRecord_1 = appRecord->GetAbilityRunningRecordByToken(token); + + EXPECT_EQ(abilityRecord_1->GetToken(), token); + EXPECT_EQ(abilityRecord_1->GetPreToken(), preToken); + EXPECT_EQ(abilityRecord_1->GetVisibility(), visibility); + EXPECT_EQ(abilityRecord_1->GetPerceptibility(), perceptibility); + EXPECT_EQ(abilityRecord_1->GetConnectionState(), connectionState); +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/test/moduletest/common/ams/app_mgr_service_test/BUILD.gn b/services/test/moduletest/common/ams/app_mgr_service_test/BUILD.gn new file mode 100755 index 000000000..57b6b2d06 --- /dev/null +++ b/services/test/moduletest/common/ams/app_mgr_service_test/BUILD.gn @@ -0,0 +1,36 @@ +# 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/mstappmgrservice" + +ohos_moduletest("AmsAppMgrServiceModuleTest") { + module_out_path = module_output_path + include_dirs = [ + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include/hilog/", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + ] + sources = [ "ams_app_mgr_service_module_test.cpp" ] + + deps = [ "${services_path}/test/moduletest/common/ams:appmgr_mst_source" ] + + external_deps = [ "ipc:ipc_core" ] +} + +group("moduletest") { + testonly = true + + deps = [ ":AmsAppMgrServiceModuleTest" ] +} 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 new file mode 100644 index 000000000..bb3bbd0a2 --- /dev/null +++ b/services/test/moduletest/common/ams/app_mgr_service_test/ams_app_mgr_service_module_test.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. + */ + +#define private public +#include "app_mgr_service.h" +#include "app_mgr_service_inner.h" +#undef private + +#include +#include + +#include "semaphore_ex.h" +#include "app_scheduler_host.h" +#include "app_scheduler_proxy.h" +#include "mock_app_mgr_service_inner.h" +#include "mock_app_spawn_socket.h" + +using namespace testing::ext; +using testing::_; +using testing::Invoke; +using testing::InvokeWithoutArgs; +using testing::Return; + +namespace { + +constexpr int COUNT = 1; + +} + +namespace OHOS { +namespace AppExecFwk { + +class TestAppSchedulerImpl : public AppSchedulerHost { +public: + void ScheduleForegroundApplication() override + {} + void ScheduleBackgroundApplication() override + {} + void ScheduleTerminateApplication() override + {} + void ScheduleShrinkMemory(const int) override + {} + void ScheduleLowMemory() override + {} + void ScheduleLaunchApplication(const AppLaunchData &) override + {} + void ScheduleLaunchAbility(const AbilityInfo &, const sptr &) override + {} + void ScheduleCleanAbility(const sptr &) override + {} + void ScheduleProfileChanged(const Profile &) override + {} + void ScheduleConfigurationUpdated(const Configuration &) override + {} + void ScheduleProcessSecurityExit() override + {} +}; + +class AppMgrServiceModuleTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + +protected: + inline static std::shared_ptr mockAppMgrServiceInner_; + inline static std::shared_ptr appMgrService_; + inline static sptr testRemoteObject_; +}; + +void AppMgrServiceModuleTest::SetUpTestCase() +{ + if (!appMgrService_) { + appMgrService_ = std::make_shared(); + } + + if (!mockAppMgrServiceInner_) { + mockAppMgrServiceInner_ = std::make_shared(); + } + + if (appMgrService_ && mockAppMgrServiceInner_) { + appMgrService_->appMgrServiceInner_ = mockAppMgrServiceInner_; + appMgrService_->OnStart(); + } + + if (!testRemoteObject_) { + testRemoteObject_ = static_cast(new TestAppSchedulerImpl); + } +} + +void AppMgrServiceModuleTest::TearDownTestCase() +{ + if (testRemoteObject_) { + testRemoteObject_.clear(); + } + + if (mockAppMgrServiceInner_) { + mockAppMgrServiceInner_.reset(); + } + + if (appMgrService_) { + appMgrService_->OnStop(); + int sleepTime = 1; + sleep(sleepTime); // Waiting for appMgrService_'s event loop backend thread exited. + if (appMgrService_->appMgrServiceInner_) { + appMgrService_->appMgrServiceInner_.reset(); + } + if (appMgrService_->amsMgrScheduler_) { + appMgrService_->amsMgrScheduler_.clear(); + } + appMgrService_.reset(); + } +} + +void AppMgrServiceModuleTest::SetUp() +{} + +void AppMgrServiceModuleTest::TearDown() +{} + +/* + * Feature: AppMgrService + * Function: AttachApplication + * SubFunction: NA + * FunctionPoints: AppMgrService => AppMgrServiceInner: AttachApplication + * CaseDescription: Check event loop AttachApplication task post from AppMgrService to AppMgrServiceInner. + */ +HWTEST_F(AppMgrServiceModuleTest, AttachApplication_001, TestSize.Level1) +{ + ASSERT_TRUE(appMgrService_); + ASSERT_TRUE(mockAppMgrServiceInner_); + ASSERT_TRUE(testRemoteObject_); + + for (int i = 0; i < COUNT; ++i) { + EXPECT_CALL(*mockAppMgrServiceInner_, AddAppDeathRecipient(_, _)) + .WillOnce(InvokeWithoutArgs(mockAppMgrServiceInner_.get(), &MockAppMgrServiceInner::Post)); + EXPECT_CALL(*mockAppMgrServiceInner_, AttachApplication(_, _)) + .WillOnce(InvokeWithoutArgs(mockAppMgrServiceInner_.get(), &MockAppMgrServiceInner::Post)); + + sptr client; + appMgrService_->AttachApplication(client); + mockAppMgrServiceInner_->Wait(); + } +} + +/* + * Feature: AppMgrService + * Function: ApplicationForegrounded + * SubFunction: NA + * FunctionPoints: AppMgrService => AppMgrServiceInner: ApplicationForegrounded + * CaseDescription: Check event loop ApplicationForegrounded task post from AppMgrService to AppMgrServiceInner. + */ +HWTEST_F(AppMgrServiceModuleTest, ApplicationForegrounded_001, TestSize.Level1) +{ + ASSERT_TRUE(appMgrService_); + ASSERT_TRUE(mockAppMgrServiceInner_); + + int32_t testRecordId = 123; + bool testResult = false; + Semaphore sem(0); + + auto mockHandler = [&](const int32_t recordId) { + testResult = (recordId == testRecordId); + sem.Post(); + }; + + for (int i = 0; i < COUNT; ++i) { + testResult = false; + + EXPECT_CALL(*mockAppMgrServiceInner_, ApplicationForegrounded(_)).Times(1).WillOnce(Invoke(mockHandler)); + + appMgrService_->ApplicationForegrounded(testRecordId); + + sem.Wait(); + + EXPECT_TRUE(testResult); + } +} + +/* + * Feature: AppMgrService + * Function: ApplicationBackgrounded + * SubFunction: NA + * FunctionPoints: AppMgrService => AppMgrServiceInner: ApplicationBackgrounded + * CaseDescription: Check event loop ApplicationBackgrounded task post from AppMgrService to AppMgrServiceInner. + */ +HWTEST_F(AppMgrServiceModuleTest, ApplicationBackgrounded_001, TestSize.Level1) +{ + ASSERT_TRUE(appMgrService_); + ASSERT_TRUE(mockAppMgrServiceInner_); + + int32_t testRecordId = 123; + bool testResult = false; + Semaphore sem(0); + + auto mockHandler = [&](const int32_t recordId) { + testResult = (recordId == testRecordId); + sem.Post(); + }; + + for (int i = 0; i < COUNT; ++i) { + testResult = false; + + EXPECT_CALL(*mockAppMgrServiceInner_, ApplicationBackgrounded(_)).Times(1).WillOnce(Invoke(mockHandler)); + + appMgrService_->ApplicationBackgrounded(testRecordId); + + sem.Wait(); + + EXPECT_TRUE(testResult); + } +} + +/* + * Feature: AppMgrService + * Function: ApplicationTerminated + * SubFunction: NA + * FunctionPoints: AppMgrService => AppMgrServiceInner: ApplicationTerminated + * CaseDescription: Check event loop ApplicationTerminated task post from AppMgrService to AppMgrServiceInner. + */ +HWTEST_F(AppMgrServiceModuleTest, ApplicationTerminated_001, TestSize.Level1) +{ + ASSERT_TRUE(appMgrService_); + ASSERT_TRUE(mockAppMgrServiceInner_); + + int32_t testRecordId = 123; + bool testResult = false; + Semaphore sem(0); + + auto mockHandler = [&testResult, testRecordId, &sem](const int32_t recordId) { + testResult = (recordId == testRecordId); + sem.Post(); + }; + + for (int i = 0; i < COUNT; ++i) { + testResult = false; + + EXPECT_CALL(*mockAppMgrServiceInner_, ApplicationTerminated(_)).Times(1).WillOnce(Invoke(mockHandler)); + + appMgrService_->ApplicationTerminated(testRecordId); + + sem.Wait(); + + EXPECT_TRUE(testResult); + } +} + +/* + * Feature: AppMgrService + * Function: AbilityCleaned + * SubFunction: NA + * FunctionPoints: AppMgrService => AppMgrServiceInner: AbilityCleaned + * CaseDescription: Check event loop AbilityCleaned task post from AppMgrService to AppMgrServiceInner. + */ +HWTEST_F(AppMgrServiceModuleTest, AbilityCleaned_001, TestSize.Level1) +{ + ASSERT_TRUE(appMgrService_); + ASSERT_TRUE(mockAppMgrServiceInner_); + ASSERT_TRUE(testRemoteObject_); + + bool testResult = false; + Semaphore sem(0); + + auto mockHandler = [&testResult, &sem](const sptr &token) { + testResult = (token == testRemoteObject_); + sem.Post(); + }; + + for (int i = 0; i < COUNT; ++i) { + testResult = false; + + EXPECT_CALL(*mockAppMgrServiceInner_, AbilityTerminated(_)).Times(1).WillOnce(Invoke(mockHandler)); + + appMgrService_->AbilityCleaned(testRemoteObject_); + + sem.Wait(); + + EXPECT_TRUE(testResult); + } +} + +/* + * Feature: AppMgrService + * Function: ClearUpApplicationData + * SubFunction: NA + * FunctionPoints: AppMgrService => AppMgrServiceInner: ClearUpApplicationData + * CaseDescription: Check event loop ClearUpApplicationData task post from AppMgrService to AppMgrServiceInner. + */ +HWTEST_F(AppMgrServiceModuleTest, ClearUpApplicationData_001, TestSize.Level1) +{ + ASSERT_TRUE(appMgrService_); + ASSERT_TRUE(mockAppMgrServiceInner_); + + std::string testAppName("testApp"); + bool testResult = false; + Semaphore sem(0); + + auto mockHandler = [&testResult, testAppName, &sem](const std::string &appName, const int32_t, const pid_t) { + testResult = (appName == testAppName); + sem.Post(); + }; + + for (int i = 0; i < COUNT; ++i) { + testResult = false; + + EXPECT_CALL(*mockAppMgrServiceInner_, ClearUpApplicationData(_, _, _)).Times(1).WillOnce(Invoke(mockHandler)); + + appMgrService_->ClearUpApplicationData(testAppName); + + sem.Wait(); + + EXPECT_TRUE(testResult); + } +} + +/* + * Feature: AppMgrService + * Function: IsBackgroundRunningRestricted + * SubFunction: NA + * FunctionPoints: AppMgrService => AppMgrServiceInner: IsBackgroundRunningRestricted + * CaseDescription: Check IsBackgroundRunningRestricted. + */ +HWTEST_F(AppMgrServiceModuleTest, IsBackgroundRunningRestricted_001, TestSize.Level1) +{ + ASSERT_TRUE(appMgrService_); + ASSERT_TRUE(mockAppMgrServiceInner_); + + std::string testAppName("testApp"); + bool testResult = false; + Semaphore sem(0); + + auto mockHandler = [&testResult, testAppName, &sem](const std::string &appName) { + testResult = (appName == testAppName); + sem.Post(); + return ERR_OK; + }; + + for (int i = 0; i < COUNT; ++i) { + testResult = false; + + EXPECT_CALL(*mockAppMgrServiceInner_, IsBackgroundRunningRestricted(_)).Times(1).WillOnce(Invoke(mockHandler)); + + auto result = appMgrService_->IsBackgroundRunningRestricted(testAppName); + + sem.Wait(); + + EXPECT_TRUE(testResult); + EXPECT_EQ(result, ERR_OK); + } +} + +/* + * Feature: AppMgrService + * Function: GetAllRunningProcesses + * SubFunction: NA + * FunctionPoints: AppMgrService => AppMgrServiceInner: GetAllRunningProcesses + * CaseDescription: Check GetAllRunningProcesses. + */ +HWTEST_F(AppMgrServiceModuleTest, GetAllRunningProcesses_001, TestSize.Level1) +{ + ASSERT_TRUE(appMgrService_); + ASSERT_TRUE(mockAppMgrServiceInner_); + + auto testRunningProcessInfo = std::make_shared(); + ASSERT_TRUE(testRunningProcessInfo); + + int32_t testPid = 456; + std::string testProcessName = "testProcess"; + + Semaphore sem(0); + auto mockHandler = [testProcessName, testPid, &sem](std::shared_ptr &runningProcessInfo) { + auto &it = runningProcessInfo->appProcessInfos.emplace_back(); + it.processName_ = testProcessName; + it.pid_ = testPid; + sem.Post(); + return ERR_OK; + }; + + for (int i = 0; i < COUNT; ++i) { + testRunningProcessInfo->appProcessInfos.clear(); + EXPECT_CALL(*mockAppMgrServiceInner_, GetAllRunningProcesses(_)).Times(1).WillOnce(Invoke(mockHandler)); + + auto result = appMgrService_->GetAllRunningProcesses(testRunningProcessInfo); + sem.Wait(); + + EXPECT_EQ(testRunningProcessInfo->appProcessInfos.size(), size_t(1)); + EXPECT_EQ(testRunningProcessInfo->appProcessInfos[0].processName_, testProcessName); + EXPECT_EQ(testRunningProcessInfo->appProcessInfos[0].pid_, testPid); + EXPECT_EQ(result, ERR_OK); + } +} + +/* + * Feature: AppMgrService + * Function: KillApplication + * SubFunction: NA + * FunctionPoints: AppMgrService => AppMgrServiceInner: KillApplication + * CaseDescription: Check KillApplication task post from AppMgrService to AppMgrServiceInner. + */ +HWTEST_F(AppMgrServiceModuleTest, KillApplication_001, TestSize.Level1) +{ + ASSERT_TRUE(appMgrService_); + ASSERT_TRUE(mockAppMgrServiceInner_); + + std::string testBundleName("testApp"); + bool testResult = false; + Semaphore sem(0); + + auto mockHandler = [&testResult, testBundleName, &sem](const std::string &bundleName) { + testResult = (bundleName == testBundleName); + sem.Post(); + return 0; + }; + + for (int i = 0; i < COUNT; ++i) { + testResult = false; + + EXPECT_CALL(*mockAppMgrServiceInner_, KillApplication(_)).Times(1).WillOnce(Invoke(mockHandler)); + + int ret = appMgrService_->GetAmsMgr()->KillApplication(testBundleName); + + sem.Wait(); + + EXPECT_TRUE(testResult); + EXPECT_EQ(ret, 0); + } +} + +/* + * Feature: AppMgrService + * Function: QueryServiceState + * SubFunction: AppMgrService => AppMgrServiceInner: QueryAppSpawnConnectionState + * FunctionPoints: NA + * CaseDescription: Check QueryServiceState. + */ +HWTEST_F(AppMgrServiceModuleTest, QueryServiceState_001, TestSize.Level1) +{ + ASSERT_TRUE(appMgrService_); + ASSERT_TRUE(mockAppMgrServiceInner_); + + SpawnConnectionState testSpawnConnectionState = SpawnConnectionState::STATE_CONNECTED; + Semaphore sem(0); + + auto mockHandler = [&]() { + sem.Post(); + return testSpawnConnectionState; + }; + + for (int i = 0; i < COUNT; ++i) { + EXPECT_CALL(*mockAppMgrServiceInner_, QueryAppSpawnConnectionState()).Times(1).WillOnce(Invoke(mockHandler)); + + auto serviceState = appMgrService_->QueryServiceState(); + + sem.Wait(); + + EXPECT_EQ(serviceState.connectionState, testSpawnConnectionState); + } +} + +/* + * Feature: AppMgrService + * Function: GetAmsMgr + * SubFunction: NA + * FunctionPoints: NA + * CaseDescription: Check GetAmsMgr. + */ +HWTEST_F(AppMgrServiceModuleTest, GetAmsMgr_001, TestSize.Level1) +{ + ASSERT_TRUE(appMgrService_); + + auto amsMgr = appMgrService_->GetAmsMgr(); + + EXPECT_TRUE(amsMgr); +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/test/moduletest/common/ams/app_recent_list_test/BUILD.gn b/services/test/moduletest/common/ams/app_recent_list_test/BUILD.gn new file mode 100755 index 000000000..47e254cf6 --- /dev/null +++ b/services/test/moduletest/common/ams/app_recent_list_test/BUILD.gn @@ -0,0 +1,36 @@ +# 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/mstappmgrservice" +ohos_moduletest("AmsAppRecentListModuleTest") { + module_out_path = module_output_path + + include_dirs = [ + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include/hilog/", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + ] + sources = [ "ams_app_recent_list_module_test.cpp" ] + + deps = [ "${services_path}/test/moduletest/common/ams:appmgr_mst_source" ] + + external_deps = [ "ipc:ipc_core" ] +} + +group("moduletest") { + testonly = true + + deps = [ ":AmsAppRecentListModuleTest" ] +} diff --git a/services/test/moduletest/common/ams/app_recent_list_test/ams_app_recent_list_module_test.cpp b/services/test/moduletest/common/ams/app_recent_list_test/ams_app_recent_list_module_test.cpp new file mode 100644 index 000000000..a9640bc16 --- /dev/null +++ b/services/test/moduletest/common/ams/app_recent_list_test/ams_app_recent_list_module_test.cpp @@ -0,0 +1,336 @@ +/* + * 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. + */ + +#define private public +#include "app_mgr_service_inner.h" +#undef private + +#include +#include + +#include "app_log_wrapper.h" +#include "refbase.h" +#include "iremote_object.h" +#include "mock_bundle_manager.h" +#include "mock_ability_token.h" +#include "mock_app_scheduler.h" +#include "mock_app_spawn_client.h" + +using namespace testing::ext; +using testing::_; +using testing::Return; +using testing::SetArgReferee; + +namespace OHOS { +namespace AppExecFwk { +namespace { + +const int32_t INDEX_NUM_1 = 1; +const int32_t INDEX_NUM_2 = 2; +const int32_t INDEX_NUM_3 = 3; +const int32_t INDEX_NUM_10 = 10; +const std::string TEST_APP_NAME = "test_app_"; +const std::string TEST_ABILITY_NAME = "test_ability_"; + +} // namespace + +class AmsAppRecentListModuleTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + +protected: + const std::shared_ptr GetApplicationByIndex(const int32_t index) const; + const std::shared_ptr CreateAppRunningRecordByIndex(const int32_t index) const; + void CreateAppRecentList(const int32_t appNum); + + std::unique_ptr serviceInner_; + sptr mockToken_; + sptr mockBundleMgr; +}; + +void AmsAppRecentListModuleTest::SetUpTestCase() +{} + +void AmsAppRecentListModuleTest::TearDownTestCase() +{} + +void AmsAppRecentListModuleTest::SetUp() +{ + serviceInner_.reset(new (std::nothrow) AppMgrServiceInner()); + mockBundleMgr = new (std::nothrow) BundleMgrService(); + serviceInner_->SetBundleManager(mockBundleMgr); +} + +void AmsAppRecentListModuleTest::TearDown() +{} + +const std::shared_ptr AmsAppRecentListModuleTest::GetApplicationByIndex(const int32_t index) const +{ + std::shared_ptr appInfo = std::make_shared(); + appInfo->name = TEST_APP_NAME + std::to_string(index); + return appInfo; +} + +const std::shared_ptr AmsAppRecentListModuleTest::CreateAppRunningRecordByIndex( + const int32_t index) const +{ + std::shared_ptr appInfo = std::make_shared(); + appInfo->name = TEST_APP_NAME + std::to_string(index); + auto appRunningRecord = serviceInner_->GetAppRunningRecordByAppName(appInfo->name); + EXPECT_NE(nullptr, appRunningRecord); + return appRunningRecord; +} + +void AmsAppRecentListModuleTest::CreateAppRecentList(const int32_t appNum) +{ + for (int32_t i = 0; i < appNum; i++) { + std::shared_ptr appInfo = std::make_shared(); + std::shared_ptr abilityInfo = std::make_shared(); + appInfo->name = TEST_APP_NAME + std::to_string(i); + appInfo->bundleName = appInfo->name; + appInfo->process = appInfo->name; + abilityInfo->name = TEST_ABILITY_NAME + std::to_string(i); + abilityInfo->applicationName = appInfo->name; + pid_t pid = i; + sptr token = new (std::nothrow) MockAbilityToken(); + MockAppSpawnClient *mockedSpawnClient = new MockAppSpawnClient(); + + EXPECT_CALL(*mockedSpawnClient, StartProcess(_, _)) + .Times(1) + .WillOnce(DoAll(SetArgReferee<1>(pid), Return(ERR_OK))); + + serviceInner_->SetAppSpawnClient(std::unique_ptr(mockedSpawnClient)); + serviceInner_->LoadAbility(token, nullptr, abilityInfo, appInfo); + } + return; +} + +/* + * Feature: Ams + * Function: AppRecentList + * SubFunction: create + * FunctionPoints: Add app to RecentAppList when start a same process failed. + * EnvConditions: AppRecentList is empty. + * CaseDescription: Verity ams add app to AppRecentList failed when start a same process. + */ +HWTEST_F(AmsAppRecentListModuleTest, Create_Recent_List_001, TestSize.Level0) +{ + APP_LOGI("Create_Recent_List_001 start"); + EXPECT_TRUE(serviceInner_->GetRecentAppList().empty()); + CreateAppRecentList(INDEX_NUM_10); + EXPECT_EQ(INDEX_NUM_10, static_cast(serviceInner_->GetRecentAppList().size())); + + // Load ability_2 again, fail to add. + std::shared_ptr appInfo = std::make_shared(); + std::shared_ptr abilityInfo = std::make_shared(); + appInfo->name = TEST_APP_NAME + std::to_string(INDEX_NUM_2); + abilityInfo->name = TEST_ABILITY_NAME + std::to_string(INDEX_NUM_2); + abilityInfo->applicationName = TEST_APP_NAME + std::to_string(INDEX_NUM_2); + + sptr token = new MockAbilityToken(); + MockAppSpawnClient *mockedSpawnClient = new MockAppSpawnClient(); + + serviceInner_->SetAppSpawnClient(std::unique_ptr(mockedSpawnClient)); + serviceInner_->LoadAbility(token, nullptr, abilityInfo, appInfo); + EXPECT_EQ(INDEX_NUM_10, static_cast(serviceInner_->GetRecentAppList().size())); + APP_LOGI("Create_Recent_List_001 end"); +} + +/* + * Feature: Ams + * Function: AppRecentList + * SubFunction: create + * FunctionPoints: Add app to RecentAppList when start a new process success. + * EnvConditions: AppRecentList is empty. + * CaseDescription: Verity ams can add app to AppRecentList success when start a new process success. + */ +HWTEST_F(AmsAppRecentListModuleTest, Create_Recent_List_002, TestSize.Level0) +{ + APP_LOGI("Create_Recent_List_002 start"); + EXPECT_TRUE(serviceInner_->GetRecentAppList().empty()); + CreateAppRecentList(INDEX_NUM_10); + EXPECT_EQ(INDEX_NUM_10, static_cast(serviceInner_->GetRecentAppList().size())); + + // Load ability_11 , add successful. + std::shared_ptr appInfo = std::make_shared(); + std::shared_ptr abilityInfo = std::make_shared(); + appInfo->name = TEST_APP_NAME + std::to_string(INDEX_NUM_10 + INDEX_NUM_1); + appInfo->bundleName = appInfo->name; + abilityInfo->name = TEST_ABILITY_NAME + std::to_string(INDEX_NUM_10 + INDEX_NUM_1); + abilityInfo->applicationName = TEST_APP_NAME + std::to_string(INDEX_NUM_10 + INDEX_NUM_1); + pid_t pid = static_cast(INDEX_NUM_10 + INDEX_NUM_1); + sptr token = new MockAbilityToken(); + MockAppSpawnClient *mockedSpawnClient = new MockAppSpawnClient(); + EXPECT_CALL(*mockedSpawnClient, StartProcess(_, _)).Times(1).WillOnce(DoAll(SetArgReferee<1>(pid), Return(ERR_OK))); + + serviceInner_->SetAppSpawnClient(std::unique_ptr(mockedSpawnClient)); + serviceInner_->LoadAbility(token, nullptr, abilityInfo, appInfo); + EXPECT_EQ(INDEX_NUM_10 + INDEX_NUM_1, static_cast(serviceInner_->GetRecentAppList().size())); + APP_LOGI("Create_Recent_List_002 end"); +} + +/* + * Feature: Ams + * Function: AppRecentList + * SubFunction: update + * FunctionPoints: Remove app from RecentAppList when app terminated. + * EnvConditions: AppRecentList has application. + * CaseDescription: Verity ams can remove app from AppRecentList when app terminated. + */ +HWTEST_F(AmsAppRecentListModuleTest, Update_Recent_List_001, TestSize.Level0) +{ + APP_LOGI("Update_Recent_List_001 start"); + EXPECT_TRUE(serviceInner_->GetRecentAppList().empty()); + CreateAppRecentList(INDEX_NUM_10); + EXPECT_EQ(INDEX_NUM_10, static_cast(serviceInner_->GetRecentAppList().size())); + + auto appRecord = CreateAppRunningRecordByIndex(INDEX_NUM_10 - INDEX_NUM_1); + appRecord->SetState(ApplicationState::APP_STATE_BACKGROUND); + auto p = appRecord->GetRecordId(); + sptr mockAppScheduler = new MockAppScheduler(); + sptr client = iface_cast(mockAppScheduler.GetRefPtr()); + appRecord->SetApplicationClient(client); + serviceInner_->ApplicationTerminated(p); + EXPECT_EQ(INDEX_NUM_10 - INDEX_NUM_1, static_cast(serviceInner_->GetRecentAppList().size())); + APP_LOGI("Update_Recent_List_001 end"); +} + +/* + * Feature: Ams + * Function: AppRecentList + * SubFunction: update + * FunctionPoints: Remove app from AppRecentList when app died. + * EnvConditions: AppRecentList has application. + * CaseDescription: Verity ams can remove app from AppRecentList when app died. + */ +HWTEST_F(AmsAppRecentListModuleTest, Update_Recent_List_002, TestSize.Level0) +{ + APP_LOGI("Update_Recent_List_002 start"); + EXPECT_TRUE(serviceInner_->GetRecentAppList().empty()); + CreateAppRecentList(INDEX_NUM_10); + EXPECT_EQ(INDEX_NUM_10, static_cast(serviceInner_->GetRecentAppList().size())); + + auto appRecord = CreateAppRunningRecordByIndex(INDEX_NUM_10 - INDEX_NUM_3); + sptr mockAppScheduler = new MockAppScheduler(); + sptr client = iface_cast(mockAppScheduler.GetRefPtr()); + appRecord->SetApplicationClient(client); + sptr object = client->AsObject(); + wptr app = object; + serviceInner_->OnRemoteDied(app); + EXPECT_EQ(INDEX_NUM_10 - INDEX_NUM_1, static_cast(serviceInner_->GetRecentAppList().size())); + APP_LOGI("Update_Recent_List_002 end"); +} + +/* + * Feature: Ams + * Function: AppRecentList + * SubFunction: remove + * FunctionPoints: Remove app from AppRecentList. + * EnvConditions: AppRecentList has application. + * CaseDescription: Verity ams can remove app from AppRecentList when call remove app from RecentList. + */ +HWTEST_F(AmsAppRecentListModuleTest, Remove_Recent_List_001, TestSize.Level0) +{ + APP_LOGI("Remove_Recent_List_001 start"); + EXPECT_TRUE(serviceInner_->GetRecentAppList().empty()); + CreateAppRecentList(INDEX_NUM_10); + EXPECT_EQ(INDEX_NUM_10, static_cast(serviceInner_->GetRecentAppList().size())); + + std::shared_ptr appInfo = std::make_shared(); + appInfo->name = TEST_APP_NAME + std::to_string(INDEX_NUM_10 - INDEX_NUM_1); + appInfo->bundleName = appInfo->name; + + auto appRecord = CreateAppRunningRecordByIndex(INDEX_NUM_10 - INDEX_NUM_1); + sptr mockAppScheduler = new MockAppScheduler(); + sptr client = iface_cast(mockAppScheduler.GetRefPtr()); + appRecord->SetApplicationClient(client); + EXPECT_CALL(*mockAppScheduler, ScheduleProcessSecurityExit()).Times(1); + + serviceInner_->RemoveAppFromRecentList(appInfo->name, appInfo->bundleName); // specify process condition + EXPECT_EQ(INDEX_NUM_10 - INDEX_NUM_1, static_cast(serviceInner_->GetRecentAppList().size())); + APP_LOGI("Remove_Recent_List_001 end"); +} + +/* + * Feature: Ams + * Function: AppRecentList + * SubFunction: remove + * FunctionPoints: Remove app from AppRecentList. + * EnvConditions: AppRecentList has application. + * CaseDescription: Verity ams can remove all app from AppRecentList. + */ +HWTEST_F(AmsAppRecentListModuleTest, Remove_Recent_List_002, TestSize.Level0) +{ + APP_LOGI("Remove_Recent_List_002 start"); + EXPECT_TRUE(serviceInner_->GetRecentAppList().empty()); + CreateAppRecentList(INDEX_NUM_10); + EXPECT_EQ(INDEX_NUM_10, static_cast(serviceInner_->GetRecentAppList().size())); + for (int32_t i = 0; i < INDEX_NUM_10; i++) { + std::shared_ptr appInfo = std::make_shared(); + appInfo->name = TEST_APP_NAME + std::to_string(i); + appInfo->bundleName = appInfo->name; + + auto appRecord = CreateAppRunningRecordByIndex(i); + sptr mockAppScheduler = new MockAppScheduler(); + sptr client = iface_cast(mockAppScheduler.GetRefPtr()); + appRecord->SetApplicationClient(client); + EXPECT_CALL(*mockAppScheduler, ScheduleProcessSecurityExit()).Times(1); + serviceInner_->RemoveAppFromRecentList(appInfo->name, appInfo->bundleName); // specify process condition + } + EXPECT_TRUE(serviceInner_->GetRecentAppList().empty()); + APP_LOGI("Remove_Recent_List_002 end"); +} + +/* + * Feature: Ams + * Function: AppRecentList + * SubFunction: clear + * FunctionPoints: Clear AppRecentList. + * EnvConditions: AppRecentList has application. + * CaseDescription: Verity ams can clear AppRecentList after removing some apps. + */ +HWTEST_F(AmsAppRecentListModuleTest, Clear_Recent_List_001, TestSize.Level0) +{ + APP_LOGI("Clear_Recent_List_002 start"); + EXPECT_TRUE(serviceInner_->GetRecentAppList().empty()); + CreateAppRecentList(INDEX_NUM_10); + EXPECT_EQ(INDEX_NUM_10, static_cast(serviceInner_->GetRecentAppList().size())); + + for (int32_t i = 0; i < INDEX_NUM_10; i++) { + std::shared_ptr appInfo = std::make_shared(); + appInfo->name = TEST_APP_NAME + std::to_string(i); + appInfo->bundleName = appInfo->name; + + auto appRecord = CreateAppRunningRecordByIndex(i); + sptr mockAppScheduler = new MockAppScheduler(); + sptr client = iface_cast(mockAppScheduler.GetRefPtr()); + + if (appRecord) { + appRecord->SetApplicationClient(client); + } + + EXPECT_CALL(*mockAppScheduler, ScheduleProcessSecurityExit()).Times(1); + serviceInner_->RemoveAppFromRecentList(appInfo->name, appInfo->bundleName); // specify process condition + } + serviceInner_->ClearRecentAppList(); + EXPECT_TRUE(serviceInner_->GetRecentAppList().empty()); + APP_LOGI("Clear_Recent_List_002 end"); +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/test/moduletest/common/ams/app_running_record_test/BUILD.gn b/services/test/moduletest/common/ams/app_running_record_test/BUILD.gn new file mode 100755 index 000000000..11ad84309 --- /dev/null +++ b/services/test/moduletest/common/ams/app_running_record_test/BUILD.gn @@ -0,0 +1,37 @@ +# 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/mstappmgrservice" + +ohos_moduletest("AmsAppRunningRecordModuleTest") { + module_out_path = module_output_path + + include_dirs = [ + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include/hilog/", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + ] + sources = [ "ams_app_running_record_module_test.cpp" ] + + deps = [ "${services_path}/test/moduletest/common/ams:appmgr_mst_source" ] + + external_deps = [ "ipc:ipc_core" ] +} + +group("moduletest") { + testonly = true + + deps = [ ":AmsAppRunningRecordModuleTest" ] +} 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 new file mode 100644 index 000000000..163a90011 --- /dev/null +++ b/services/test/moduletest/common/ams/app_running_record_test/ams_app_running_record_module_test.cpp @@ -0,0 +1,477 @@ +/* + * 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_running_record.h" +#include +#include +#include "iremote_object.h" +#include "app_record_id.h" +#include "app_scheduler_proxy.h" +#include "app_scheduler_host.h" +#include "app_mgr_service_inner.h" +#include "mock_application.h" +#include "ability_info.h" +#include "application_info.h" +#include "mock_ability_token.h" + +using namespace testing::ext; +using OHOS::iface_cast; +using OHOS::IRemoteObject; +using OHOS::sptr; +using testing::_; +using testing::Invoke; +using testing::InvokeWithoutArgs; + +namespace OHOS { +namespace AppExecFwk { + +class AmsAppRunningRecordModuleTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + +protected: + std::string GetTestAppName(const unsigned long num) const + { + if (num < appName_.size()) { + return appName_[num]; + } + return ""; + } + + std::string GetTestAbilityName(const unsigned long num) const + { + if (num < abilityName_.size()) { + return abilityName_[num]; + } + return ""; + } + + 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!"; + sptr client = iface_cast(mockApplication); + record->SetApplicationClient(client); + + std::string applicationName(GetTestAppName(index)); + ApplicationInfo info; + info.name = applicationName; + std::string processInfoName(GetTestAppName(index)); + pid_t pidId = 123; + ProcessInfo processInfo(processInfoName, pidId); + + AppLaunchData launchData; + launchData.SetApplicationInfo(info); + launchData.SetProcessInfo(processInfo); + + EXPECT_CALL(*mockApplication, ScheduleLaunchApplication(_)) + .Times(1) + .WillOnce(Invoke(mockApplication.GetRefPtr(), &MockApplication::LaunchApplication)); + record->LaunchApplication(); + mockApplication->Wait(); + + bool isEqual = mockApplication->CompareAppLaunchData(launchData); + EXPECT_EQ(isEqual, true) << testPoint << ",fail"; + } + + void CheckAppRunningRecording(const std::shared_ptr appInfo, + 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!"; + auto abilityRecord = record->GetAbilityRunningRecord(GetTestAbilityName(index)); + int32_t id = record->GetRecordId(); + auto name = record->GetName(); + sptr token = abilityRecord->GetToken(); + auto abilityName = abilityRecord->GetName(); + std::string processName = GetTestAppName(index); + + auto appRecordFromServ = + service_->GetOrCreateAppRunningRecord(token, appInfo, abilityInfo, processName, 0, result); + EXPECT_TRUE(appRecordFromServ); + auto abilityRecordFromServ = appRecordFromServ->GetAbilityRunningRecord(GetTestAbilityName(index)); + int32_t idFromServ = appRecordFromServ->GetRecordId(); + sptr tokenFromServ = abilityRecordFromServ->GetToken(); + auto nameFromServ = appRecordFromServ->GetName(); + auto abilityNameFromServ = abilityRecordFromServ->GetName(); + ASSERT_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!"; + EXPECT_EQ(abilityName, abilityNameFromServ) << "fail, app record name is not equal!"; + } + + std::unique_ptr service_; + + sptr GetMockToken() const + { + return mockToken_; + } + +private: + std::vector appName_ = { + "test_app_name1", "test_app_name2", "test_app_name3", "test_app_name4", "test_app_name5"}; + std::vector abilityName_ = { + "test_ability_name1", "test_ability_name2", "test_ability_name3", "test_ability_name4", "test_ability_name5"}; + sptr mockToken_; +}; + +void AmsAppRunningRecordModuleTest::SetUpTestCase() +{} + +void AmsAppRunningRecordModuleTest::TearDownTestCase() +{} + +void AmsAppRunningRecordModuleTest::SetUp() +{ + service_.reset(new (std::nothrow) AppMgrServiceInner()); + mockToken_ = new (std::nothrow) MockAbilityToken(); +} + +void AmsAppRunningRecordModuleTest::TearDown() +{} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: ApprunningRecord + * FunctionPoints: run application and use Iapplication LaunchApplication and + * ScheduleForegroundRunning interface to control application, + * check whether function is good or not + * EnvConditions: system running normally + * CaseDescription: 1. start application + * 2. use Iapplication LaunchApplication and ScheduleForegroundRunning interface + */ +HWTEST_F(AmsAppRunningRecordModuleTest, ApplicationStart_001, TestSize.Level0) +{ + // init AppRunningRecord + unsigned long index = 0L; + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(index); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(index); + std::string processName = GetTestAppName(index); + RecordQueryResult result; + auto record = service_->GetOrCreateAppRunningRecord(GetMockToken(), appInfo, abilityInfo, processName, 0, result); + ASSERT_TRUE(record != nullptr) << ",create apprunningrecord fail!"; + ASSERT_FALSE(result.appExists) << ",result is wrong!"; + + // check apprunningrecord + int32_t id = record->GetRecordId(); + CheckAppRunningRecording(appInfo, abilityInfo, record, index, result); + + // LaunchApplication + sptr mockApplication(new MockApplication()); + std::string testPoint = "ApplicationStart_001"; + CheckLaunchApplication(mockApplication, index, record, testPoint); + + EXPECT_CALL(*mockApplication, ScheduleForegroundApplication()) + .Times(1) + .WillOnce(InvokeWithoutArgs(mockApplication.GetRefPtr(), &MockApplication::Post)); + // application enter in foreground and check the result + record->ScheduleForegroundRunning(); + mockApplication->Wait(); + + // update application state and check the state + record->SetState(ApplicationState::APP_STATE_FOREGROUND); + RecordQueryResult newResult; + auto newRecord = + 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_EQ(stateFromRec, ApplicationState::APP_STATE_FOREGROUND); + + // clear apprunningrecord + record->SetState(ApplicationState::APP_STATE_BACKGROUND); + service_->ApplicationTerminated(id); + record = service_->GetAppRunningRecordByAppRecordId(id); + EXPECT_EQ(nullptr, record); +} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: ApprunningRecord + * FunctionPoints: run multi application at the same time, then use Iapplication + * LaunchApplication and ScheduleForegroundRunning interface to control + * application, check whether function is good or not + * EnvConditions: system running normally + * CaseDescription: 1. start 5 application at the same time + * 2. use Iapplication LaunchApplication and ScheduleForegroundRunning interface + */ +HWTEST_F(AmsAppRunningRecordModuleTest, MultiApplicationStart_002, TestSize.Level1) +{ + unsigned long count = 5; + for (unsigned long i = 0; i < count; i++) { + // init AppRunningRecord + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(i); + std::string processName = GetTestAppName(i); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(i); + RecordQueryResult result; + auto record = + service_->GetOrCreateAppRunningRecord(GetMockToken(), appInfo, abilityInfo, processName, 0, result); + ASSERT_TRUE(record != nullptr) << "create apprunningrecord fail!"; + ASSERT_FALSE(result.appExists) << "result is wrong!"; + + // check abilityrunningrecord & apprunningrecord + int32_t id = record->GetRecordId(); + CheckAppRunningRecording(appInfo, abilityInfo, record, i, result); + + // LaunchApplication + sptr mockApplication(new MockApplication()); + std::string testPoint = "multiApplicationStart_002"; + CheckLaunchApplication(mockApplication, i, record, testPoint); + + // clear apprunningrecord + record->SetState(ApplicationState::APP_STATE_BACKGROUND); + service_->ApplicationTerminated(id); + record = service_->GetAppRunningRecordByAppRecordId(id); + EXPECT_EQ(nullptr, record); + } +} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: ApprunningRecord + * FunctionPoints: run application, then use Iapplication LaunchApplication and ScheduleTrimMemory + * interface to control application,check whether function is good or not + * EnvConditions: system running normally + * CaseDescription: 1. start application + * 2. use Iapplication LaunchApplication and ScheduleTrimMemory interface + */ +HWTEST_F(AmsAppRunningRecordModuleTest, ScheduleTrimMemory_003, TestSize.Level1) +{ + ASSERT_TRUE(service_ != nullptr) << "init service fail!"; + + // init AppRunningRecord + unsigned long index = 0; + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(index); + std::string processName = GetTestAppName(index); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(index); + RecordQueryResult result; + auto record = service_->GetOrCreateAppRunningRecord(GetMockToken(), appInfo, abilityInfo, processName, 0, result); + ASSERT_TRUE(record != nullptr) << "create apprunningrecord fail!"; + ASSERT_FALSE(result.appExists) << "result is wrong!"; + + // LaunchApplication + sptr mockApplication(new MockApplication()); + std::string testPoint = "ScheduleTrimMemory_003"; + CheckLaunchApplication(mockApplication, index, record, testPoint); + + EXPECT_CALL(*mockApplication, ScheduleShrinkMemory(_)) + .Times(1) + .WillOnce(Invoke(mockApplication.GetRefPtr(), &MockApplication::ShrinkMemory)); + // set ScheduleTrimMemory API + record->ScheduleTrimMemory(); + mockApplication->Wait(); + int level = mockApplication->GetShrinkLevel(); + EXPECT_EQ(level, 0) << "fail, level is wrong!"; + + // clear apprunningrecord + record->SetState(ApplicationState::APP_STATE_BACKGROUND); + int32_t id = record->GetRecordId(); + service_->ApplicationTerminated(id); + record = service_->GetAppRunningRecordByAppRecordId(id); + EXPECT_EQ(nullptr, record); +} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: ApprunningRecord + * FunctionPoints: run application, then use Iapplication LaunchApplication and LowMemoryWarning + * interface to control application,check whether function is good or not + * EnvConditions: system running normally + * CaseDescription: 1. start application + * 2. use Iapplication LaunchApplication and LowMemoryWarning interface + */ +HWTEST_F(AmsAppRunningRecordModuleTest, LowMemoryWarning_004, TestSize.Level1) +{ + ASSERT_TRUE(service_ != nullptr) << "init service fail!"; + + // init AppRunningRecord + unsigned long index = 0; + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(index); + std::string processName = GetTestAppName(index); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(index); + RecordQueryResult result; + auto record = service_->GetOrCreateAppRunningRecord(GetMockToken(), appInfo, abilityInfo, processName, 0, result); + ASSERT_TRUE(record != nullptr) << "create apprunningrecord fail!"; + ASSERT_FALSE(result.appExists) << "result is wrong!"; + + // LaunchApplication + sptr mockApplication(new MockApplication()); + std::string testPoint = "LowMemoryWarning_004"; + CheckLaunchApplication(mockApplication, index, record, testPoint); + + EXPECT_CALL(*mockApplication, ScheduleLowMemory()) + .Times(1) + .WillOnce(InvokeWithoutArgs(mockApplication.GetRefPtr(), &MockApplication::Post)); + // set LowMemoryWarning + record->LowMemoryWarning(); + mockApplication->Wait(); + + // clear apprunningrecord + record->SetState(ApplicationState::APP_STATE_BACKGROUND); + int32_t id = record->GetRecordId(); + service_->ApplicationTerminated(id); + record = service_->GetAppRunningRecordByAppRecordId(id); + EXPECT_EQ(nullptr, record); +} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: ApprunningRecord + * FunctionPoints: run application and quit repeatly, then check whether function is good or not + * EnvConditions: system running normally + * CaseDescription: 1. start application + * 2. use Iapplication LaunchApplication and ScheduleForegroundRunning interface + * 3. use ScheduleBackgroundRunning interface + * 4. use ScheduleTerminate and OnApplicationTerminated to stop application + * 5. repeat 1~4 10000 times + */ +HWTEST_F(AmsAppRunningRecordModuleTest, ApplicationStartAndQuit_005, TestSize.Level2) +{ + ASSERT_TRUE(service_ != nullptr) << "init service fail!"; + + unsigned long index = 0; + int startCount = 10000; + for (int i = 0; i < startCount; i++) { + // init AppRunningRecord + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(index); + std::string processName = GetTestAppName(index); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(index); + RecordQueryResult result; + auto record = + service_->GetOrCreateAppRunningRecord(GetMockToken(), appInfo, abilityInfo, processName, 0, result); + ASSERT_TRUE(record != nullptr) << "create apprunningrecord fail!"; + + // LaunchApplication + sptr mockApplication(new MockApplication()); + std::string testPoint = "ApplicationStartAndQuit_005"; + CheckLaunchApplication(mockApplication, index, record, testPoint); + + EXPECT_CALL(*mockApplication, ScheduleForegroundApplication()) + .Times(1) + .WillOnce(InvokeWithoutArgs(mockApplication.GetRefPtr(), &MockApplication::Post)); + // set foreground and update foreground state + record->ScheduleForegroundRunning(); + mockApplication->Wait(); + record->SetState(ApplicationState::APP_STATE_FOREGROUND); + auto stateFromRec = record->GetState(); + EXPECT_EQ(stateFromRec, ApplicationState::APP_STATE_FOREGROUND); + + EXPECT_CALL(*mockApplication, ScheduleBackgroundApplication()) + .Times(1) + .WillOnce(InvokeWithoutArgs(mockApplication.GetRefPtr(), &MockApplication::Post)); + // set background and update foreground state + record->ScheduleBackgroundRunning(); + mockApplication->Wait(); + record->SetState(ApplicationState::APP_STATE_BACKGROUND); + stateFromRec = record->GetState(); + EXPECT_EQ(stateFromRec, ApplicationState::APP_STATE_BACKGROUND); + + EXPECT_CALL(*mockApplication, ScheduleTerminateApplication()) + .Times(1) + .WillOnce(InvokeWithoutArgs(mockApplication.GetRefPtr(), &MockApplication::Post)); + // set application terminate + record->ScheduleTerminate(); + mockApplication->Wait(); + + // clear apprunnningrecord + int32_t id = record->GetRecordId(); + service_->ApplicationTerminated(id); + record = service_->GetAppRunningRecordByAppRecordId(id); + EXPECT_EQ(nullptr, record); + } +} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: ApprunningRecord + * FunctionPoints: run application, make application foreground and background repeatly, + * then check whether function is good or not + * EnvConditions: system running normally + * CaseDescription: 1. start application + * 2. use Iapplication LaunchApplication and ScheduleForegroundRunning interface + * 3. use ScheduleBackgroundRunning and SetState to update state + * 4. repeat 1~4 10000 times + */ +HWTEST_F(AmsAppRunningRecordModuleTest, ApplicationStatusChange_006, TestSize.Level2) +{ + ASSERT_TRUE(service_ != nullptr) << "init service fail!"; + + // init AppRunningRecord + unsigned long index = 0; + auto abilityInfo = std::make_shared(); + abilityInfo->name = GetTestAbilityName(index); + std::string processName = GetTestAppName(index); + auto appInfo = std::make_shared(); + appInfo->name = GetTestAppName(index); + RecordQueryResult result; + auto record = service_->GetOrCreateAppRunningRecord(GetMockToken(), appInfo, abilityInfo, processName, 0, result); + ASSERT_TRUE(record != nullptr) << "create apprunningrecord fail!"; + + // LaunchApplication + sptr mockApplication(new MockApplication()); + std::string testPoint = "ApplicationStatusChange_006"; + CheckLaunchApplication(mockApplication, index, record, testPoint); + int startCount = 10000; + for (int i = 0; i < startCount; i++) { + EXPECT_CALL(*mockApplication, ScheduleForegroundApplication()) + .Times(1) + .WillOnce(InvokeWithoutArgs(mockApplication.GetRefPtr(), &MockApplication::Post)); + // set foreground and update foreground state + record->ScheduleForegroundRunning(); + mockApplication->Wait(); + record->SetState(ApplicationState::APP_STATE_FOREGROUND); + auto stateFromRec = record->GetState(); + EXPECT_EQ(stateFromRec, ApplicationState::APP_STATE_FOREGROUND); + + EXPECT_CALL(*mockApplication, ScheduleBackgroundApplication()) + .Times(1) + .WillOnce(InvokeWithoutArgs(mockApplication.GetRefPtr(), &MockApplication::Post)); + // set background and update background state + record->ScheduleBackgroundRunning(); + mockApplication->Wait(); + record->SetState(ApplicationState::APP_STATE_BACKGROUND); + stateFromRec = record->GetState(); + EXPECT_EQ(stateFromRec, ApplicationState::APP_STATE_BACKGROUND); + } + int32_t id = record->GetRecordId(); + service_->ApplicationTerminated(id); + auto stateFromRec = record->GetState(); + EXPECT_EQ(stateFromRec, ApplicationState::APP_STATE_TERMINATED); +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/test/moduletest/common/ams/app_service_flow_test/BUILD.gn b/services/test/moduletest/common/ams/app_service_flow_test/BUILD.gn new file mode 100755 index 000000000..73866b9fd --- /dev/null +++ b/services/test/moduletest/common/ams/app_service_flow_test/BUILD.gn @@ -0,0 +1,35 @@ +# 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/mstappmgrservice" + +ohos_moduletest("AmsAppServiceFlowModuleTest") { + module_out_path = module_output_path + + include_dirs = + [ "//base/hiviewdfx/hilog/interfaces/native/innerkits/include/" ] + sources = [ "ams_app_service_flow_module_test.cpp" ] + + deps = [ "${services_path}/test/moduletest/common/ams:appmgr_mst_source" ] + + external_deps = [ "ipc:ipc_core" ] +} + +group("moduletest") { + testonly = true + + deps = [ ":AmsAppServiceFlowModuleTest" ] +} diff --git a/services/test/moduletest/common/ams/app_service_flow_test/ams_app_service_flow_module_test.cpp b/services/test/moduletest/common/ams/app_service_flow_test/ams_app_service_flow_module_test.cpp new file mode 100644 index 000000000..94545828a --- /dev/null +++ b/services/test/moduletest/common/ams/app_service_flow_test/ams_app_service_flow_module_test.cpp @@ -0,0 +1,711 @@ +/* + * 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 "iremote_object.h" +#include "refbase.h" + +#include "app_launch_data.h" +#include "app_log_wrapper.h" +#include "app_mgr_service_inner.h" +#include "mock_ability_token.h" +#include "mock_app_scheduler.h" +#include "mock_app_spawn_client.h" + +using namespace testing::ext; +using testing::_; +using testing::Return; +using testing::SetArgReferee; + +namespace OHOS { +namespace AppExecFwk { +namespace { + +const uint32_t CYCLE_NUMBER = 10; + +} // namespace + +struct TestApplicationPreRunningRecord { + TestApplicationPreRunningRecord( + const std::shared_ptr &appRecord, const sptr &mockAppScheduler) + : appRecord_(appRecord), mockAppScheduler_(mockAppScheduler) + {} + sptr GetToken(const std::string &abilityName) const + { + auto abilityRecord = appRecord_->GetAbilityRunningRecord(abilityName); + return abilityRecord ? abilityRecord->GetToken() : nullptr; + } + + std::shared_ptr GetAbility(const std::string &abilityName) const + { + return appRecord_->GetAbilityRunningRecord(abilityName); + } + + virtual ~TestApplicationPreRunningRecord() + {} + + std::shared_ptr appRecord_; + sptr mockAppScheduler_; + static pid_t g_pid; +}; + +pid_t TestApplicationPreRunningRecord::g_pid = 0; + +class AmsAppServiceFlowModuleTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + +protected: + sptr TestCreateApplicationClient(const std::shared_ptr &appRecord) const; + TestApplicationPreRunningRecord TestCreateApplicationRecordAndSetState(const std::string &abilityName, + const std::string &appName, const AbilityState abilityState, const ApplicationState appState) const; + +protected: + std::unique_ptr serviceInner_; +}; + +void AmsAppServiceFlowModuleTest::SetUpTestCase() +{} + +void AmsAppServiceFlowModuleTest::TearDownTestCase() +{} + +void AmsAppServiceFlowModuleTest::SetUp() +{ + serviceInner_.reset(new (std::nothrow) AppMgrServiceInner()); +} + +void AmsAppServiceFlowModuleTest::TearDown() +{} + +sptr AmsAppServiceFlowModuleTest::TestCreateApplicationClient( + const std::shared_ptr &appRecord) const +{ + if (appRecord->GetApplicationClient()) { + return nullptr; + } + sptr mockAppScheduler = new (std::nothrow) MockAppScheduler(); + sptr client = iface_cast(mockAppScheduler.GetRefPtr()); + appRecord->SetApplicationClient(client); + return mockAppScheduler; +} + +// create one application that include one ability, and set state +TestApplicationPreRunningRecord AmsAppServiceFlowModuleTest::TestCreateApplicationRecordAndSetState( + const std::string &abilityName, const std::string &appName, const AbilityState abilityState, + const ApplicationState appState) const +{ + RecordQueryResult result; + AbilityInfo abilityInfo; + ApplicationInfo appInfo; + + appInfo.name = appName; + appInfo.bundleName = appName; // specify process condition + abilityInfo.name = abilityName; + sptr token = new (std::nothrow) MockAbilityToken(); + auto appRecord = serviceInner_->GetOrCreateAppRunningRecord(token, + std::make_shared(appInfo), + std::make_shared(abilityInfo), + appInfo.bundleName, + 0, + result); + EXPECT_NE(appRecord, nullptr); + if (!result.appExists && appRecord) { + appRecord->GetPriorityObject()->SetPid(TestApplicationPreRunningRecord::g_pid++); + } + auto abilityRecord = appRecord->GetAbilityRunningRecordByToken(token); + EXPECT_NE(abilityRecord, nullptr); + abilityRecord->SetState(abilityState); + appRecord->SetState(appState); + sptr mockAppScheduler = TestCreateApplicationClient(appRecord); + TestApplicationPreRunningRecord testAppPreRecord(appRecord, mockAppScheduler); + return testAppPreRecord; +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: ServiceFlow + * FunctionPoints: BackKey + * CaseDescription: when two abilities on foreground, previous ability in another app, simulate press back key. + */ +HWTEST_F(AmsAppServiceFlowModuleTest, ServiceFlow_BackKey_001, TestSize.Level0) +{ + APP_LOGI("AmsAppServiceFlowModuleTest ServiceFlow_BackKey_001 start"); + TestApplicationPreRunningRecord testAppA = TestCreateApplicationRecordAndSetState( + "abilityA1", "appA", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + TestCreateApplicationRecordAndSetState("abilityA2", + testAppA.appRecord_->GetName(), + AbilityState::ABILITY_STATE_FOREGROUND, + ApplicationState::APP_STATE_FOREGROUND); + // The previous app and ability + TestApplicationPreRunningRecord testAppB = TestCreateApplicationRecordAndSetState( + "abilityB1", "appB", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + TestCreateApplicationRecordAndSetState("abilityB2", + testAppB.appRecord_->GetName(), + AbilityState::ABILITY_STATE_BACKGROUND, + ApplicationState::APP_STATE_BACKGROUND); + + EXPECT_CALL(*(testAppB.mockAppScheduler_), ScheduleForegroundApplication()).Times(1); + EXPECT_CALL(*(testAppA.mockAppScheduler_), ScheduleBackgroundApplication()).Times(1); + + // simulate press back key + serviceInner_->UpdateAbilityState(testAppB.GetToken("abilityB1"), AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->ApplicationForegrounded(testAppB.appRecord_->GetRecordId()); + serviceInner_->UpdateAbilityState(testAppA.GetToken("abilityA1"), AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->UpdateAbilityState(testAppA.GetToken("abilityA2"), AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(testAppA.appRecord_->GetRecordId()); + + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, testAppB.GetAbility("abilityB1")->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, testAppB.GetAbility("abilityB2")->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testAppB.appRecord_->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, testAppA.GetAbility("abilityA1")->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, testAppA.GetAbility("abilityA2")->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_BACKGROUND, testAppA.appRecord_->GetState()); + APP_LOGI("AmsAppServiceFlowModuleTest ServiceFlow_BackKey_001 end"); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: ServiceFlow + * FunctionPoints: BackKey + * CaseDescription: when two abilities on foreground, previous ability in another app, simulate press back key twice. + */ +HWTEST_F(AmsAppServiceFlowModuleTest, ServiceFlow_BackKey_002, TestSize.Level0) +{ + APP_LOGI("AmsAppServiceFlowModuleTest ServiceFlow_BackKey_002 start"); + TestApplicationPreRunningRecord testAppA = TestCreateApplicationRecordAndSetState( + "abilityA1", "appA", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + TestApplicationPreRunningRecord testAppB = TestCreateApplicationRecordAndSetState( + "abilityB1", "appB", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + TestApplicationPreRunningRecord testappC = TestCreateApplicationRecordAndSetState( + "abilityC1", "appC", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + + EXPECT_CALL(*(testAppB.mockAppScheduler_), ScheduleForegroundApplication()).Times(1); + EXPECT_CALL(*(testAppA.mockAppScheduler_), ScheduleBackgroundApplication()).Times(1); + // simulate press back key + serviceInner_->UpdateAbilityState(testAppB.GetToken("abilityB1"), AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->ApplicationForegrounded(testAppB.appRecord_->GetRecordId()); + serviceInner_->UpdateAbilityState(testAppA.GetToken("abilityA1"), AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(testAppA.appRecord_->GetRecordId()); + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, testAppB.GetAbility("abilityB1")->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testAppB.appRecord_->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, testAppA.GetAbility("abilityA1")->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_BACKGROUND, testAppA.appRecord_->GetState()); + + EXPECT_CALL(*(testappC.mockAppScheduler_), ScheduleForegroundApplication()).Times(1); + EXPECT_CALL(*(testAppB.mockAppScheduler_), ScheduleBackgroundApplication()).Times(1); + // simulate press back key again + serviceInner_->UpdateAbilityState(testappC.GetToken("abilityC1"), AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->ApplicationForegrounded(testappC.appRecord_->GetRecordId()); + serviceInner_->UpdateAbilityState(testAppB.GetToken("abilityB1"), AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(testAppB.appRecord_->GetRecordId()); + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, testappC.GetAbility("abilityC1")->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testappC.appRecord_->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, testAppA.GetAbility("abilityA1")->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_BACKGROUND, testAppA.appRecord_->GetState()); + APP_LOGI("AmsAppServiceFlowModuleTest ServiceFlow_BackKey_002 end"); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: ServiceFlow + * FunctionPoints: BackKey + * CaseDescription: app have three abilities , previous ability in same app, simulate press back key. + */ +HWTEST_F(AmsAppServiceFlowModuleTest, ServiceFlow_BackKey_003, TestSize.Level0) +{ + APP_LOGI("AmsAppServiceFlowModuleTest ServiceFlow_BackKey_003 start"); + TestApplicationPreRunningRecord testAppA = TestCreateApplicationRecordAndSetState( + "abilityA1", "appA", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + TestCreateApplicationRecordAndSetState("abilityA2", + testAppA.appRecord_->GetName(), + AbilityState::ABILITY_STATE_BACKGROUND, + ApplicationState::APP_STATE_FOREGROUND); + TestCreateApplicationRecordAndSetState("abilityA3", + testAppA.appRecord_->GetName(), + AbilityState::ABILITY_STATE_BACKGROUND, + ApplicationState::APP_STATE_FOREGROUND); + + // simulate press back key + serviceInner_->UpdateAbilityState(testAppA.GetToken("abilityA2"), AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->UpdateAbilityState(testAppA.GetToken("abilityA3"), AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->UpdateAbilityState(testAppA.GetToken("abilityA1"), AbilityState::ABILITY_STATE_BACKGROUND); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, testAppA.GetAbility("abilityA1")->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, testAppA.GetAbility("abilityA2")->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, testAppA.GetAbility("abilityA3")->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testAppA.appRecord_->GetState()); + APP_LOGI("AmsAppServiceFlowModuleTest ServiceFlow_BackKey_003 end"); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: ServiceFlow + * FunctionPoints: BackKey + * CaseDescription:app with two abilities on foreground, previous ability in another app, simulate press back and exit. + */ +HWTEST_F(AmsAppServiceFlowModuleTest, ServiceFlow_BackKey_004, TestSize.Level0) +{ + APP_LOGI("AmsAppServiceFlowModuleTest ServiceFlow_BackKey_004 start"); + TestApplicationPreRunningRecord testAppA = TestCreateApplicationRecordAndSetState( + "abilityA1", "appA", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + TestCreateApplicationRecordAndSetState("abilityA2", + testAppA.appRecord_->GetName(), + AbilityState::ABILITY_STATE_FOREGROUND, + ApplicationState::APP_STATE_FOREGROUND); + // The previous app and ability + TestApplicationPreRunningRecord testAppB = TestCreateApplicationRecordAndSetState( + "abilityB1", "appB", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + TestCreateApplicationRecordAndSetState("abilityB2", + testAppB.appRecord_->GetName(), + AbilityState::ABILITY_STATE_BACKGROUND, + ApplicationState::APP_STATE_BACKGROUND); + + EXPECT_CALL(*(testAppB.mockAppScheduler_), ScheduleForegroundApplication()).Times(1); + EXPECT_CALL(*(testAppA.mockAppScheduler_), ScheduleBackgroundApplication()).Times(1); + EXPECT_CALL(*(testAppA.mockAppScheduler_), ScheduleCleanAbility(_)).Times(2); + EXPECT_CALL(*(testAppA.mockAppScheduler_), ScheduleTerminateApplication()).Times(1); + + // simulate press back key + serviceInner_->UpdateAbilityState(testAppB.GetToken("abilityB2"), AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->UpdateAbilityState(testAppB.GetToken("abilityB1"), AbilityState::ABILITY_STATE_FOREGROUND); + + serviceInner_->ApplicationForegrounded(testAppB.appRecord_->GetRecordId()); + + serviceInner_->UpdateAbilityState(testAppA.GetToken("abilityA1"), AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->UpdateAbilityState(testAppA.GetToken("abilityA2"), AbilityState::ABILITY_STATE_BACKGROUND); + + serviceInner_->ApplicationBackgrounded(testAppA.appRecord_->GetRecordId()); + + serviceInner_->TerminateAbility(testAppA.GetToken("abilityA1")); + serviceInner_->AbilityTerminated(testAppA.GetToken("abilityA1")); + serviceInner_->TerminateAbility(testAppA.GetToken("abilityA2")); + serviceInner_->AbilityTerminated(testAppA.GetToken("abilityA2")); + serviceInner_->ApplicationTerminated(testAppA.appRecord_->GetRecordId()); + + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, testAppB.GetAbility("abilityB1")->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, testAppB.GetAbility("abilityB2")->GetState()); + + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testAppB.appRecord_->GetState()); + + EXPECT_EQ(testAppA.GetAbility("abilityA1"), nullptr); + EXPECT_EQ(testAppA.GetAbility("abilityA2"), nullptr); + EXPECT_EQ(ApplicationState::APP_STATE_TERMINATED, testAppA.appRecord_->GetState()); + APP_LOGI("AmsAppServiceFlowModuleTest ServiceFlow_BackKey_004 end"); +} + +/* + * Feature: AMS + * AR_AMS_ENV04_003 + * Function: AppLifeCycle + * SubFunction: ServiceFlow + * FunctionPoints: BackKey + * CaseDescription: Three applications,only one on foreground, previous ability in another app, + simulate press back key twice. + */ +HWTEST_F(AmsAppServiceFlowModuleTest, ServiceFlow_BackKey_005, TestSize.Level0) +{ + APP_LOGI("AmsAppServiceFlowModuleTest ServiceFlow_BackKey_005 start"); + TestApplicationPreRunningRecord testAppA = TestCreateApplicationRecordAndSetState( + "abilityA1", "appA", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + TestApplicationPreRunningRecord testAppB = TestCreateApplicationRecordAndSetState( + "abilityB1", "appB", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + TestApplicationPreRunningRecord testappC = TestCreateApplicationRecordAndSetState( + "abilityC1", "appC", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + + EXPECT_CALL(*(testAppB.mockAppScheduler_), ScheduleForegroundApplication()).Times(1); + EXPECT_CALL(*(testAppA.mockAppScheduler_), ScheduleBackgroundApplication()).Times(1); + EXPECT_CALL(*(testAppA.mockAppScheduler_), ScheduleCleanAbility(_)).Times(1); + EXPECT_CALL(*(testAppA.mockAppScheduler_), ScheduleTerminateApplication()).Times(1); + + // simulate press back key, AppA to backgroud and exit. + serviceInner_->UpdateAbilityState(testAppB.GetToken("abilityB1"), AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->ApplicationForegrounded(testAppB.appRecord_->GetRecordId()); + serviceInner_->UpdateAbilityState(testAppA.GetToken("abilityA1"), AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(testAppA.appRecord_->GetRecordId()); + serviceInner_->TerminateAbility(testAppA.GetToken("abilityA1")); + serviceInner_->AbilityTerminated(testAppA.GetToken("abilityA1")); + serviceInner_->ApplicationTerminated(testAppA.appRecord_->GetRecordId()); + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, testAppB.GetAbility("abilityB1")->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testAppB.appRecord_->GetState()); + EXPECT_EQ(testAppA.GetAbility("abilityA1"), nullptr); + EXPECT_EQ(ApplicationState::APP_STATE_TERMINATED, testAppA.appRecord_->GetState()); + + EXPECT_CALL(*(testappC.mockAppScheduler_), ScheduleForegroundApplication()).Times(1); + EXPECT_CALL(*(testAppB.mockAppScheduler_), ScheduleBackgroundApplication()).Times(1); + EXPECT_CALL(*(testAppB.mockAppScheduler_), ScheduleCleanAbility(_)).Times(1); + EXPECT_CALL(*(testAppB.mockAppScheduler_), ScheduleTerminateApplication()).Times(1); + // simulate press back key again + serviceInner_->UpdateAbilityState(testappC.GetToken("abilityC1"), AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->ApplicationForegrounded(testappC.appRecord_->GetRecordId()); + serviceInner_->UpdateAbilityState(testAppB.GetToken("abilityB1"), AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(testAppB.appRecord_->GetRecordId()); + serviceInner_->TerminateAbility(testAppB.GetToken("abilityB1")); + serviceInner_->AbilityTerminated(testAppB.GetToken("abilityB1")); + serviceInner_->ApplicationTerminated(testAppB.appRecord_->GetRecordId()); + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, testappC.GetAbility("abilityC1")->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testappC.appRecord_->GetState()); + EXPECT_EQ(testAppB.GetAbility("abilityB1"), nullptr); + EXPECT_EQ(ApplicationState::APP_STATE_TERMINATED, testAppB.appRecord_->GetState()); + APP_LOGI("AmsAppServiceFlowModuleTest ServiceFlow_BackKey_005 end"); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: ServiceFlow + * FunctionPoints: ScreenOff + * CaseDescription: when two applications with two abilities on foreground, simulate press screenoff key. + */ +HWTEST_F(AmsAppServiceFlowModuleTest, ServiceFlow_ScreenOff_001, TestSize.Level0) +{ + APP_LOGI("AmsAppServiceFlowModuleTest ServiceFlow_ScreenOff_001 start"); + TestApplicationPreRunningRecord testAppA = TestCreateApplicationRecordAndSetState( + "abilityA1", "appA", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + // The previous app and ability + TestApplicationPreRunningRecord testAppB = TestCreateApplicationRecordAndSetState( + "abilityB1", "appB", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + + EXPECT_CALL(*(testAppB.mockAppScheduler_), ScheduleBackgroundApplication()).Times(1); + EXPECT_CALL(*(testAppB.mockAppScheduler_), ScheduleCleanAbility(_)).Times(1); + EXPECT_CALL(*(testAppB.mockAppScheduler_), ScheduleTerminateApplication()).Times(1); + EXPECT_CALL(*(testAppA.mockAppScheduler_), ScheduleBackgroundApplication()).Times(1); + EXPECT_CALL(*(testAppA.mockAppScheduler_), ScheduleCleanAbility(_)).Times(1); + EXPECT_CALL(*(testAppA.mockAppScheduler_), ScheduleTerminateApplication()).Times(1); + + // simulate press screenOff key + serviceInner_->UpdateAbilityState(testAppB.GetToken("abilityB1"), AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(testAppB.appRecord_->GetRecordId()); + serviceInner_->TerminateAbility(testAppB.GetToken("abilityB1")); + serviceInner_->AbilityTerminated(testAppB.GetToken("abilityB1")); + serviceInner_->ApplicationTerminated(testAppB.appRecord_->GetRecordId()); + serviceInner_->UpdateAbilityState(testAppA.GetToken("abilityA1"), AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(testAppA.appRecord_->GetRecordId()); + serviceInner_->TerminateAbility(testAppA.GetToken("abilityA1")); + serviceInner_->AbilityTerminated(testAppA.GetToken("abilityA1")); + serviceInner_->ApplicationTerminated(testAppA.appRecord_->GetRecordId()); + + EXPECT_EQ(testAppA.GetAbility("abilityA1"), nullptr); + EXPECT_EQ(ApplicationState::APP_STATE_TERMINATED, testAppA.appRecord_->GetState()); + EXPECT_EQ(testAppB.GetAbility("abilityB1"), nullptr); + EXPECT_EQ(ApplicationState::APP_STATE_TERMINATED, testAppB.appRecord_->GetState()); + APP_LOGI("AmsAppServiceFlowModuleTest ServiceFlow_ScreenOff_001 end"); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: ServiceFlow + * FunctionPoints: ScreenOff + * CaseDescription: when two applications with two abilities on foreground, simulate press screenoff key. + */ +HWTEST_F(AmsAppServiceFlowModuleTest, ServiceFlow_ScreenOff_002, TestSize.Level0) +{ + APP_LOGI("AmsAppServiceFlowModuleTest ServiceFlow_ScreenOff_002 start"); + TestApplicationPreRunningRecord testAppA = TestCreateApplicationRecordAndSetState( + "abilityA1", "appA", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + TestCreateApplicationRecordAndSetState("abilityA2", + testAppA.appRecord_->GetName(), + AbilityState::ABILITY_STATE_FOREGROUND, + ApplicationState::APP_STATE_FOREGROUND); + // The previous app and ability + TestApplicationPreRunningRecord testAppB = TestCreateApplicationRecordAndSetState( + "abilityB1", "appB", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + TestCreateApplicationRecordAndSetState("abilityB2", + testAppB.appRecord_->GetName(), + AbilityState::ABILITY_STATE_BACKGROUND, + ApplicationState::APP_STATE_BACKGROUND); + + EXPECT_CALL(*(testAppA.mockAppScheduler_), ScheduleBackgroundApplication()).Times(1); + + // simulate press screenOff key + serviceInner_->UpdateAbilityState(testAppB.GetToken("abilityB1"), AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->UpdateAbilityState(testAppB.GetToken("abilityB2"), AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(testAppB.appRecord_->GetRecordId()); + serviceInner_->UpdateAbilityState(testAppA.GetToken("abilityA1"), AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->UpdateAbilityState(testAppA.GetToken("abilityA2"), AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(testAppA.appRecord_->GetRecordId()); + + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, testAppB.GetAbility("abilityB1")->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, testAppB.GetAbility("abilityB2")->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_BACKGROUND, testAppB.appRecord_->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, testAppA.GetAbility("abilityA1")->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, testAppA.GetAbility("abilityA2")->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_BACKGROUND, testAppA.appRecord_->GetState()); + APP_LOGI("AmsAppServiceFlowModuleTest ServiceFlow_ScreenOff_002 end"); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: ServiceFlow + * FunctionPoints: ScreenOff + * CaseDescription: when two applications with two abilities on foreground, simulate press screenoff key. + */ +HWTEST_F(AmsAppServiceFlowModuleTest, ServiceFlow_ScreenOff_003, TestSize.Level0) +{ + APP_LOGI("AmsAppServiceFlowModuleTest ServiceFlow_ScreenOff_003 start"); + TestApplicationPreRunningRecord testAppA = TestCreateApplicationRecordAndSetState( + "abilityA1", "appA", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + TestCreateApplicationRecordAndSetState("abilityA2", + testAppA.appRecord_->GetName(), + AbilityState::ABILITY_STATE_BACKGROUND, + ApplicationState::APP_STATE_FOREGROUND); + // The previous app and ability + TestApplicationPreRunningRecord testAppB = TestCreateApplicationRecordAndSetState( + "abilityB1", "appB", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_BACKGROUND); + + EXPECT_CALL(*(testAppA.mockAppScheduler_), ScheduleBackgroundApplication()).Times(1); + EXPECT_CALL(*(testAppA.mockAppScheduler_), ScheduleCleanAbility(_)).Times(2); + EXPECT_CALL(*(testAppA.mockAppScheduler_), ScheduleTerminateApplication()).Times(1); + EXPECT_CALL(*(testAppB.mockAppScheduler_), ScheduleCleanAbility(_)).Times(1); + EXPECT_CALL(*(testAppB.mockAppScheduler_), ScheduleTerminateApplication()).Times(1); + + // simulate press screenOff key + serviceInner_->UpdateAbilityState(testAppB.GetToken("abilityB1"), AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(testAppB.appRecord_->GetRecordId()); + serviceInner_->TerminateAbility(testAppB.GetToken("abilityB1")); + serviceInner_->AbilityTerminated(testAppB.GetToken("abilityB1")); + serviceInner_->ApplicationTerminated(testAppB.appRecord_->GetRecordId()); + serviceInner_->UpdateAbilityState(testAppA.GetToken("abilityA1"), AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(testAppA.appRecord_->GetRecordId()); + serviceInner_->TerminateAbility(testAppA.GetToken("abilityA1")); + serviceInner_->AbilityTerminated(testAppA.GetToken("abilityA1")); + serviceInner_->TerminateAbility(testAppA.GetToken("abilityA2")); + serviceInner_->AbilityTerminated(testAppA.GetToken("abilityA2")); + serviceInner_->ApplicationTerminated(testAppA.appRecord_->GetRecordId()); + + EXPECT_EQ(testAppA.GetAbility("abilityA1"), nullptr); + EXPECT_EQ(testAppA.GetAbility("abilityA2"), nullptr); + EXPECT_EQ(ApplicationState::APP_STATE_TERMINATED, testAppA.appRecord_->GetState()); + EXPECT_EQ(testAppB.GetAbility("abilityB1"), nullptr); + EXPECT_EQ(ApplicationState::APP_STATE_TERMINATED, testAppB.appRecord_->GetState()); + APP_LOGI("AmsAppServiceFlowModuleTest ServiceFlow_ScreenOff_003 end"); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: ServiceFlow + * FunctionPoints: ScreenOff + * CaseDescription: when two applications with two abilities on foreground, simulate press screenoff key. + */ +HWTEST_F(AmsAppServiceFlowModuleTest, ServiceFlow_ScreenOff_004, TestSize.Level0) +{ + APP_LOGI("AmsAppServiceFlowModuleTest ServiceFlow_ScreenOff_004 start"); + TestApplicationPreRunningRecord testAppA = TestCreateApplicationRecordAndSetState( + "abilityA1", "appA", AbilityState::ABILITY_STATE_FOREGROUND, ApplicationState::APP_STATE_FOREGROUND); + TestCreateApplicationRecordAndSetState("abilityA2", + testAppA.appRecord_->GetName(), + AbilityState::ABILITY_STATE_BACKGROUND, + ApplicationState::APP_STATE_FOREGROUND); + // The previous app and ability + TestApplicationPreRunningRecord testAppB = TestCreateApplicationRecordAndSetState( + "abilityB1", "appB", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + TestCreateApplicationRecordAndSetState("abilityB2", + testAppB.appRecord_->GetName(), + AbilityState::ABILITY_STATE_BACKGROUND, + ApplicationState::APP_STATE_BACKGROUND); + + EXPECT_CALL(*(testAppA.mockAppScheduler_), ScheduleBackgroundApplication()).Times(1); + EXPECT_CALL(*(testAppB.mockAppScheduler_), ScheduleCleanAbility(_)).Times(2); + EXPECT_CALL(*(testAppB.mockAppScheduler_), ScheduleTerminateApplication()).Times(1); + + // simulate press screenOff key + serviceInner_->UpdateAbilityState(testAppB.GetToken("abilityB1"), AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(testAppB.appRecord_->GetRecordId()); + serviceInner_->TerminateAbility(testAppB.GetToken("abilityB1")); + serviceInner_->AbilityTerminated(testAppB.GetToken("abilityB1")); + serviceInner_->TerminateAbility(testAppB.GetToken("abilityB2")); + serviceInner_->AbilityTerminated(testAppB.GetToken("abilityB2")); + serviceInner_->ApplicationTerminated(testAppB.appRecord_->GetRecordId()); + serviceInner_->UpdateAbilityState(testAppA.GetToken("abilityA1"), AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(testAppA.appRecord_->GetRecordId()); + + EXPECT_EQ(testAppB.GetAbility("abilityB1"), nullptr); + EXPECT_EQ(testAppB.GetAbility("abilityB2"), nullptr); + EXPECT_EQ(ApplicationState::APP_STATE_TERMINATED, testAppB.appRecord_->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, testAppA.GetAbility("abilityA1")->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, testAppA.GetAbility("abilityA2")->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_BACKGROUND, testAppA.appRecord_->GetState()); + APP_LOGI("AmsAppServiceFlowModuleTest ServiceFlow_ScreenOff_004 end"); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: ServiceFlow + * FunctionPoints: ScreenOn + * CaseDescription: when an application with three abilities on foreground, simulate press screenon key. + */ +HWTEST_F(AmsAppServiceFlowModuleTest, ServiceFlow_ScreenOn_001, TestSize.Level0) +{ + APP_LOGI("AmsAppServiceFlowModuleTest ServiceFlow_ScreenOn_001 start"); + TestApplicationPreRunningRecord testAppA = TestCreateApplicationRecordAndSetState( + "abilityA1", "appA", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + TestCreateApplicationRecordAndSetState("abilityA2", + testAppA.appRecord_->GetName(), + AbilityState::ABILITY_STATE_BACKGROUND, + ApplicationState::APP_STATE_BACKGROUND); + TestCreateApplicationRecordAndSetState("abilityA3", + testAppA.appRecord_->GetName(), + AbilityState::ABILITY_STATE_BACKGROUND, + ApplicationState::APP_STATE_BACKGROUND); + + EXPECT_CALL(*(testAppA.mockAppScheduler_), ScheduleForegroundApplication()).Times(1); + + // simulate press ScreenOn key + serviceInner_->UpdateAbilityState(testAppA.GetToken("abilityA1"), AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->ApplicationForegrounded(testAppA.appRecord_->GetRecordId()); + + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, testAppA.GetAbility("abilityA1")->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, testAppA.GetAbility("abilityA2")->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_BACKGROUND, testAppA.GetAbility("abilityA3")->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testAppA.appRecord_->GetState()); + APP_LOGI("AmsAppServiceFlowModuleTest ServiceFlow_ScreenOn_001 end"); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: ServiceFlow + * FunctionPoints: ScreenOn + * CaseDescription: when an application with three abilities on foreground, simulate press screenon key. + */ +HWTEST_F(AmsAppServiceFlowModuleTest, ServiceFlow_ScreenOn_002, TestSize.Level0) +{ + APP_LOGI("AmsAppServiceFlowModuleTest ServiceFlow_ScreenOn_002 start"); + TestApplicationPreRunningRecord testAppA = TestCreateApplicationRecordAndSetState( + "abilityA1", "appA", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + TestCreateApplicationRecordAndSetState("abilityA2", + testAppA.appRecord_->GetName(), + AbilityState::ABILITY_STATE_BACKGROUND, + ApplicationState::APP_STATE_BACKGROUND); + TestCreateApplicationRecordAndSetState("abilityA3", + testAppA.appRecord_->GetName(), + AbilityState::ABILITY_STATE_BACKGROUND, + ApplicationState::APP_STATE_BACKGROUND); + + EXPECT_CALL(*(testAppA.mockAppScheduler_), ScheduleForegroundApplication()).Times(1); + + // simulate press ScreenOn key + serviceInner_->UpdateAbilityState(testAppA.GetToken("abilityA1"), AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->UpdateAbilityState(testAppA.GetToken("abilityA2"), AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->UpdateAbilityState(testAppA.GetToken("abilityA3"), AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->ApplicationForegrounded(testAppA.appRecord_->GetRecordId()); + + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, testAppA.GetAbility("abilityA1")->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, testAppA.GetAbility("abilityA2")->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, testAppA.GetAbility("abilityA3")->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testAppA.appRecord_->GetState()); + APP_LOGI("AmsAppServiceFlowModuleTest ServiceFlow_ScreenOn_002 end"); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: ServiceFlow + * FunctionPoints: ScreenOn + * CaseDescription: when an application with two abilities on foreground, simulate press screenon key. + */ +HWTEST_F(AmsAppServiceFlowModuleTest, ServiceFlow_ScreenOn_003, TestSize.Level0) +{ + APP_LOGI("AmsAppServiceFlowModuleTest ServiceFlow_ScreenOn_003 start"); + TestApplicationPreRunningRecord testAppA = TestCreateApplicationRecordAndSetState( + "abilityA1", "appA", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + TestCreateApplicationRecordAndSetState("abilityA2", + testAppA.appRecord_->GetName(), + AbilityState::ABILITY_STATE_BACKGROUND, + ApplicationState::APP_STATE_BACKGROUND); + TestApplicationPreRunningRecord testAppB = TestCreateApplicationRecordAndSetState( + "abilityB1", "appB", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + TestCreateApplicationRecordAndSetState("abilityB2", + testAppB.appRecord_->GetName(), + AbilityState::ABILITY_STATE_BACKGROUND, + ApplicationState::APP_STATE_BACKGROUND); + + EXPECT_CALL(*(testAppA.mockAppScheduler_), ScheduleForegroundApplication()).Times(1); + EXPECT_CALL(*(testAppB.mockAppScheduler_), ScheduleForegroundApplication()).Times(1); + + // simulate press ScreenOn key + serviceInner_->UpdateAbilityState(testAppA.GetToken("abilityA1"), AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->UpdateAbilityState(testAppA.GetToken("abilityA2"), AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->UpdateAbilityState(testAppB.GetToken("abilityB1"), AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->UpdateAbilityState(testAppB.GetToken("abilityB2"), AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->ApplicationForegrounded(testAppA.appRecord_->GetRecordId()); + serviceInner_->ApplicationForegrounded(testAppB.appRecord_->GetRecordId()); + + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, testAppA.GetAbility("abilityA1")->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, testAppA.GetAbility("abilityA2")->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testAppA.appRecord_->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, testAppB.GetAbility("abilityB1")->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, testAppB.GetAbility("abilityB2")->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testAppB.appRecord_->GetState()); + APP_LOGI("AmsAppServiceFlowModuleTest ServiceFlow_ScreenOn_003 end"); +} + +/* + * Feature: AMS + * Function: AppLifeCycle + * SubFunction: ServiceFlow + * FunctionPoints: ScreenOn + * CaseDescription: an application with two abilities on foreground, simulate press screenon and screenoff 1000 times. + */ +HWTEST_F(AmsAppServiceFlowModuleTest, ServiceFlow_ScreenOnAndOff_001, TestSize.Level0) +{ + APP_LOGI("AmsAppServiceFlowModuleTest ServiceFlow_ScreenOnAndOff_001 start"); + TestApplicationPreRunningRecord testAppA = TestCreateApplicationRecordAndSetState( + "abilityA1", "appA", AbilityState::ABILITY_STATE_BACKGROUND, ApplicationState::APP_STATE_BACKGROUND); + TestCreateApplicationRecordAndSetState("abilityA2", + testAppA.appRecord_->GetName(), + AbilityState::ABILITY_STATE_BACKGROUND, + ApplicationState::APP_STATE_BACKGROUND); + + EXPECT_CALL(*(testAppA.mockAppScheduler_), ScheduleForegroundApplication()).Times(CYCLE_NUMBER + 1); + EXPECT_CALL(*(testAppA.mockAppScheduler_), ScheduleBackgroundApplication()).Times(CYCLE_NUMBER); + + for (uint32_t i = 0; i < CYCLE_NUMBER; i++) { + // simulate press ScreenOn key + serviceInner_->UpdateAbilityState(testAppA.GetToken("abilityA1"), AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->UpdateAbilityState(testAppA.GetToken("abilityA2"), AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->ApplicationForegrounded(testAppA.appRecord_->GetRecordId()); + + // simulate press ScreenOff key + serviceInner_->UpdateAbilityState(testAppA.GetToken("abilityA1"), AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->UpdateAbilityState(testAppA.GetToken("abilityA2"), AbilityState::ABILITY_STATE_BACKGROUND); + serviceInner_->ApplicationBackgrounded(testAppA.appRecord_->GetRecordId()); + } + + // simulate press ScreenOn key + serviceInner_->UpdateAbilityState(testAppA.GetToken("abilityA1"), AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->UpdateAbilityState(testAppA.GetToken("abilityA2"), AbilityState::ABILITY_STATE_FOREGROUND); + serviceInner_->ApplicationForegrounded(testAppA.appRecord_->GetRecordId()); + + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, testAppA.GetAbility("abilityA1")->GetState()); + EXPECT_EQ(AbilityState::ABILITY_STATE_FOREGROUND, testAppA.GetAbility("abilityA2")->GetState()); + EXPECT_EQ(ApplicationState::APP_STATE_FOREGROUND, testAppA.appRecord_->GetState()); + APP_LOGI("AmsAppServiceFlowModuleTest ServiceFlow_ScreenOnAndOff_001 end"); +} + +} // namespace AppExecFwk +} // namespace OHOS diff --git a/services/test/moduletest/common/ams/ipc_ams_mgr_test/BUILD.gn b/services/test/moduletest/common/ams/ipc_ams_mgr_test/BUILD.gn new file mode 100755 index 000000000..ff3815b76 --- /dev/null +++ b/services/test/moduletest/common/ams/ipc_ams_mgr_test/BUILD.gn @@ -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. + +import("//build/test.gni") +import("//foundation/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/mstappmgrservice" + +ohos_moduletest("AmsIpcAmsmgrModuleTest") { + module_out_path = module_output_path + + include_dirs = [ + "//foundation/aafwk/standard/interfaces/innerkits/base/include", + "//foundation/aafwk/standard/interfaces/innerkits/want/include", + "//foundation/appexecfwk/standard/services/appmgr/include", + "//foundation/distributedschedule/dmsfwk/services/dtbschedmgr/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core/include", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + ] + sources = [ "ams_ipc_ams_mgr_module_test.cpp" ] + + deps = [ + "${libs_path}/libeventhandler:libeventhandler_target", + "${services_path}/appmgr/test:appmgr_test_source", + "${services_path}/test/moduletest/common/ams:appmgr_mst_source", + ] + + external_deps = [ "ipc:ipc_core" ] +} + +group("moduletest") { + testonly = true + + deps = [ ":AmsIpcAmsmgrModuleTest" ] +} diff --git a/services/test/moduletest/common/ams/ipc_ams_mgr_test/ams_ipc_ams_mgr_module_test.cpp b/services/test/moduletest/common/ams/ipc_ams_mgr_test/ams_ipc_ams_mgr_module_test.cpp new file mode 100644 index 000000000..8ef635292 --- /dev/null +++ b/services/test/moduletest/common/ams/ipc_ams_mgr_test/ams_ipc_ams_mgr_module_test.cpp @@ -0,0 +1,427 @@ +/* + * 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 + +#define private public +#include "app_mgr_client.h" +#undef private +#include "mock_ability_token.h" +#include "mock_application.h" +#include "mock_iapp_state_callback.h" +#include "iremote_object.h" +#include "app_record_id.h" +#include "ams_mgr_proxy.h" +#include "mock_app_mgr_service.h" +#include "mock_app_service_mgr.h" +#include "mock_app_mgr_service_inner.h" +#include "app_mgr_service_event_handler.h" +#include "ams_mgr_scheduler.h" +#include "app_mgr_proxy.h" +#include "app_scheduler_proxy.h" + +using namespace testing::ext; +using OHOS::iface_cast; +using OHOS::sptr; +using testing::_; +using testing::Invoke; +using testing::InvokeWithoutArgs; + +namespace OHOS { +namespace AppExecFwk { + +namespace { + +const int32_t COUNT = 1000; + +} // namespace + +class AmsIpcAmsmgrModuleTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + std::shared_ptr GetApplicationInfo(const std::string &appName) const; + std::shared_ptr GetAbilityInfo( + const std::string &abilityIndex, const std::string &name, const std::string &applicationName) const; + + sptr GetAbilityToken() + { + mockToken_ = new (std::nothrow) MockAbilityToken(); + return mockToken_; + } + + std::shared_ptr GetMockAppMgrServiceInner(); + std::shared_ptr GetAmsEventHandler(); + +protected: + sptr mockToken_ = nullptr; + sptr token_; + std::unique_ptr client_; + + std::shared_ptr mockAppMgrServiceInner_; + std::shared_ptr amsEventHandler_; +}; + +class MockMockAppMgrService : public MockAppMgrService { +public: + MOCK_METHOD0(GetAmsMgr, sptr()); + MOCK_METHOD1(ClearUpApplicationData, void(const std::string &)); + MOCK_METHOD1(IsBackgroundRunningRestricted, int(const std::string &appName)); + MOCK_METHOD1(GetAllRunningProcesses, int(std::shared_ptr &)); +}; + +void AmsIpcAmsmgrModuleTest::SetUpTestCase() +{} + +void AmsIpcAmsmgrModuleTest::TearDownTestCase() +{} + +void AmsIpcAmsmgrModuleTest::SetUp() +{ + token_ = new (std::nothrow) MockAbilityToken(); +} + +void AmsIpcAmsmgrModuleTest::TearDown() +{ + amsEventHandler_.reset(); + mockAppMgrServiceInner_.reset(); +} + +std::shared_ptr AmsIpcAmsmgrModuleTest::GetApplicationInfo(const std::string &appName) const +{ + auto appInfo = std::make_shared(); + appInfo->name = appName; + return appInfo; +} + +std::shared_ptr AmsIpcAmsmgrModuleTest::GetAbilityInfo( + const std::string &abilityIndex, const std::string &name, const std::string &applicationName) const +{ + auto abilityInfo = std::make_shared(); + abilityInfo->name = name + abilityIndex; + abilityInfo->applicationName = applicationName; + return abilityInfo; +} + +std::shared_ptr AmsIpcAmsmgrModuleTest::GetMockAppMgrServiceInner() +{ + if (!mockAppMgrServiceInner_) { + mockAppMgrServiceInner_ = std::make_shared(); + } + return mockAppMgrServiceInner_; +} + +std::shared_ptr AmsIpcAmsmgrModuleTest::GetAmsEventHandler() +{ + if (!amsEventHandler_) { + auto mockAppMgrServiceInner = GetMockAppMgrServiceInner(); + amsEventHandler_ = + std::make_shared(EventRunner::Create("AmsMgrSchedulerTest"), mockAppMgrServiceInner); + } + return amsEventHandler_; +} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: AmsmgrIPCInterface + * FunctionPoints: test loadAbility API,then check the function whether is good or not + * EnvConditions: system running normally + * CaseDescription: excute loadAbility API 1000 times + */ +HWTEST_F(AmsIpcAmsmgrModuleTest, ExcuteAmsmgrIPCInterface_001, TestSize.Level3) +{ + auto abilityInfo = GetAbilityInfo("0", "MainAbility", "com.ohos.test.helloworld"); + auto appInfo = GetApplicationInfo("com.ohos.test.helloworld"); + auto mockAppMgrServiceInner = GetMockAppMgrServiceInner(); + auto amsEventHandler = GetAmsEventHandler(); + std::unique_ptr amsMgrScheduler = + std::make_unique(mockAppMgrServiceInner, amsEventHandler); + + sptr mockMockAppMgr(new MockMockAppMgrService()); + sptr appMgrClient = iface_cast(mockMockAppMgr); + + auto mockHandler = [&]() -> sptr { + mockMockAppMgr->Post(); + return sptr(amsMgrScheduler.get()); + }; + + EXPECT_CALL(*mockMockAppMgr, GetAmsMgr()).Times(1).WillOnce(Invoke(mockHandler)); + + auto amsMgrScheduler_ = appMgrClient->GetAmsMgr(); + mockMockAppMgr->Wait(); + sptr token = new MockAbilityToken(); + + for (int i = 0; i < COUNT; i++) { + EXPECT_CALL(*mockAppMgrServiceInner, LoadAbility(_, _, _, _)) + .WillOnce(InvokeWithoutArgs(mockAppMgrServiceInner.get(), &MockAppMgrServiceInner::Post)); + amsMgrScheduler_->LoadAbility(token_, nullptr, abilityInfo, appInfo); + mockAppMgrServiceInner->Wait(); + } + + mockAppMgrServiceInner.reset(); + amsMgrScheduler.release(); +} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: AmsmgrIPCInterface + * FunctionPoints: test terminateAbility API,then check the function whether is good or not + * EnvConditions: system running normally + * CaseDescription: excute terminateAbility API 1000 times + */ +HWTEST_F(AmsIpcAmsmgrModuleTest, ExcuteAmsmgrIPCInterface_002, TestSize.Level3) +{ + auto mockAppMgrServiceInner = GetMockAppMgrServiceInner(); + auto amsEventHandler = GetAmsEventHandler(); + std::unique_ptr amsMgrScheduler = + std::make_unique(mockAppMgrServiceInner, amsEventHandler); + + sptr mockMockAppMgr(new MockMockAppMgrService()); + sptr appMgrClient = iface_cast(mockMockAppMgr); + + auto mockHandler = [&]() -> sptr { + mockMockAppMgr->Post(); + return sptr(amsMgrScheduler.get()); + }; + + EXPECT_CALL(*mockMockAppMgr, GetAmsMgr()).Times(1).WillOnce(Invoke(mockHandler)); + + auto amsMgrScheduler_ = appMgrClient->GetAmsMgr(); + mockMockAppMgr->Wait(); + sptr token = new MockAbilityToken(); + + for (int i = 0; i < COUNT; i++) { + EXPECT_CALL(*mockAppMgrServiceInner, TerminateAbility(_)) + .WillOnce(InvokeWithoutArgs(mockAppMgrServiceInner.get(), &MockAppMgrServiceInner::Post)); + amsMgrScheduler_->TerminateAbility(token_); + mockAppMgrServiceInner->Wait(); + } + + mockAppMgrServiceInner.reset(); + amsMgrScheduler.release(); +} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: AmsmgrIPCInterface + * FunctionPoints: test updateAbilityState API,then check the function whether is good or not + * EnvConditions: system running normally + * CaseDescription: excute updateAbilityState API 1000 times + */ +HWTEST_F(AmsIpcAmsmgrModuleTest, ExcuteAmsmgrIPCInterface_003, TestSize.Level3) +{ + auto mockAppMgrServiceInner = GetMockAppMgrServiceInner(); + auto amsEventHandler = GetAmsEventHandler(); + std::unique_ptr amsMgrScheduler = + std::make_unique(mockAppMgrServiceInner, amsEventHandler); + + sptr mockMockAppMgr(new MockMockAppMgrService()); + sptr appMgrClient = iface_cast(mockMockAppMgr); + + auto mockHandler = [&]() -> sptr { + mockMockAppMgr->Post(); + return sptr(amsMgrScheduler.get()); + }; + + EXPECT_CALL(*mockMockAppMgr, GetAmsMgr()).Times(1).WillOnce(Invoke(mockHandler)); + + auto amsMgrScheduler_ = appMgrClient->GetAmsMgr(); + mockMockAppMgr->Wait(); + + sptr token = new MockAbilityToken(); + AbilityState abilityState = AbilityState::ABILITY_STATE_BEGIN; + + for (int i = 0; i < COUNT; i++) { + EXPECT_CALL(*mockAppMgrServiceInner, UpdateAbilityState(_, _)) + .WillOnce(InvokeWithoutArgs(mockAppMgrServiceInner.get(), &MockAppMgrServiceInner::Post)); + amsMgrScheduler_->UpdateAbilityState(token, abilityState); + mockAppMgrServiceInner->Wait(); + } + + mockAppMgrServiceInner.reset(); + amsMgrScheduler.release(); +} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: AmsmgrIPCInterface + * FunctionPoints: test registerappstatecallback API,then check the function whether is good or not + * EnvConditions: system running normally + * CaseDescription: excute registerappstatecallback API 1000 times + */ +HWTEST_F(AmsIpcAmsmgrModuleTest, ExcuteAmsmgrIPCInterface_004, TestSize.Level3) +{ + auto mockAppMgrServiceInner = GetMockAppMgrServiceInner(); + auto amsEventHandler = GetAmsEventHandler(); + std::unique_ptr amsMgrScheduler = + std::make_unique(mockAppMgrServiceInner, amsEventHandler); + sptr callback = new MockAppStateCallback(); + + sptr mockMockAppMgr(new MockMockAppMgrService()); + sptr appMgrClient = iface_cast(mockMockAppMgr); + + auto mockHandler = [&]() -> sptr { + mockMockAppMgr->Post(); + return sptr(amsMgrScheduler.get()); + }; + + EXPECT_CALL(*mockMockAppMgr, GetAmsMgr()).Times(1).WillOnce(Invoke(mockHandler)); + + auto amsMgrScheduler_ = appMgrClient->GetAmsMgr(); + mockMockAppMgr->Wait(); + + for (int i = 0; i < COUNT; i++) { + EXPECT_CALL(*mockAppMgrServiceInner, RegisterAppStateCallback(_)) + .WillOnce(InvokeWithoutArgs(mockAppMgrServiceInner.get(), &MockAppMgrServiceInner::Post)); + amsMgrScheduler_->RegisterAppStateCallback(callback); + mockAppMgrServiceInner->Wait(); + } + + mockAppMgrServiceInner.reset(); + amsMgrScheduler.release(); +} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: AmsmgrIPCInterface + * FunctionPoints: test AbilityBehaviorAnalysis API,then check the function whether is good or not + * EnvConditions: system running normally + * CaseDescription: excute AbilityBehaviorAnalysis API 1000 times + */ +HWTEST_F(AmsIpcAmsmgrModuleTest, ExcuteAmsmgrIPCInterface_005, TestSize.Level3) +{ + const int32_t visibility = 1; + const int32_t perceptibility = 1; + const int32_t connectionState = 1; + + auto mockAppMgrServiceInner = GetMockAppMgrServiceInner(); + auto amsEventHandler = GetAmsEventHandler(); + std::unique_ptr amsMgrScheduler = + std::make_unique(mockAppMgrServiceInner, amsEventHandler); + + sptr mockMockAppMgr(new MockMockAppMgrService()); + sptr appMgrClient = iface_cast(mockMockAppMgr); + + auto mockHandler = [&]() -> sptr { + mockMockAppMgr->Post(); + return sptr(amsMgrScheduler.get()); + }; + + EXPECT_CALL(*mockMockAppMgr, GetAmsMgr()).Times(1).WillOnce(Invoke(mockHandler)); + + auto amsMgrScheduler_ = appMgrClient->GetAmsMgr(); + mockMockAppMgr->Wait(); + sptr token = new MockAbilityToken(); + + for (int i = 0; i < COUNT; i++) { + EXPECT_CALL(*mockAppMgrServiceInner, AbilityBehaviorAnalysis(_, _, _, _, _)) + .WillOnce(InvokeWithoutArgs(mockAppMgrServiceInner.get(), &MockAppMgrServiceInner::Post)); + amsMgrScheduler_->AbilityBehaviorAnalysis(token, nullptr, visibility, perceptibility, connectionState); + mockAppMgrServiceInner->Wait(); + } + + mockAppMgrServiceInner.reset(); + amsMgrScheduler.release(); +} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: AmsmgrIPCInterface + * FunctionPoints: test KillApplication API,then check the function whether is good or not + * EnvConditions: system running normally + * CaseDescription: excute KillApplication API 1000 times + */ +HWTEST_F(AmsIpcAmsmgrModuleTest, ExcuteAmsmgrIPCInterface_006, TestSize.Level3) +{ + const std::string bundleName = "p1"; + auto mockAppMgrServiceInner = GetMockAppMgrServiceInner(); + auto amsEventHandler = GetAmsEventHandler(); + std::unique_ptr amsMgrScheduler = + std::make_unique(mockAppMgrServiceInner, amsEventHandler); + + sptr mockMockAppMgr(new MockMockAppMgrService()); + sptr appMgrClient = iface_cast(mockMockAppMgr); + + auto mockHandler = [&]() -> sptr { + mockMockAppMgr->Post(); + return sptr(amsMgrScheduler.get()); + }; + + EXPECT_CALL(*mockMockAppMgr, GetAmsMgr()).Times(1).WillOnce(Invoke(mockHandler)); + + auto amsMgrScheduler_ = appMgrClient->GetAmsMgr(); + mockMockAppMgr->Wait(); + + for (int i = 0; i < COUNT; i++) { + EXPECT_CALL(*mockAppMgrServiceInner, KillApplication(_)) + .WillOnce(InvokeWithoutArgs(mockAppMgrServiceInner.get(), &MockAppMgrServiceInner::Post4Int)); + amsMgrScheduler_->KillApplication(bundleName); + mockAppMgrServiceInner->Wait(); + } + + mockAppMgrServiceInner.reset(); + amsMgrScheduler.release(); +} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: AmsmgrIPCInterface + * FunctionPoints: test KillProcessByAbilityToken API,then check the function whether is good or not + * EnvConditions: system running normally + * CaseDescription: excute KillProcessByAbilityToken API 1000 times + */ +HWTEST_F(AmsIpcAmsmgrModuleTest, ExcuteAmsmgrIPCInterface_007, TestSize.Level3) +{ + auto mockAppMgrServiceInner = GetMockAppMgrServiceInner(); + auto amsEventHandler = GetAmsEventHandler(); + std::unique_ptr amsMgrScheduler = + std::make_unique(mockAppMgrServiceInner, amsEventHandler); + + sptr mockMockAppMgr(new MockMockAppMgrService()); + sptr appMgrClient = iface_cast(mockMockAppMgr); + + auto mockHandler = [&]() -> sptr { + mockMockAppMgr->Post(); + return sptr(amsMgrScheduler.get()); + }; + + EXPECT_CALL(*mockMockAppMgr, GetAmsMgr()).Times(1).WillOnce(Invoke(mockHandler)); + + auto amsMgrScheduler_ = appMgrClient->GetAmsMgr(); + mockMockAppMgr->Wait(); + sptr token = new MockAbilityToken(); + + for (int i = 0; i < COUNT; i++) { + EXPECT_CALL(*mockAppMgrServiceInner, KillProcessByAbilityToken(_)) + .WillOnce(InvokeWithoutArgs(mockAppMgrServiceInner.get(), &MockAppMgrServiceInner::Post)); + amsMgrScheduler_->KillProcessByAbilityToken(token); + mockAppMgrServiceInner->Wait(); + } + + mockAppMgrServiceInner.reset(); + amsMgrScheduler.release(); +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/test/moduletest/common/ams/ipc_app_mgr_test/BUILD.gn b/services/test/moduletest/common/ams/ipc_app_mgr_test/BUILD.gn new file mode 100755 index 000000000..74507d6ac --- /dev/null +++ b/services/test/moduletest/common/ams/ipc_app_mgr_test/BUILD.gn @@ -0,0 +1,35 @@ +# 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/mstappmgrservice" + +ohos_moduletest("AmsIpcAppmgrModuleTest") { + module_out_path = module_output_path + + include_dirs = [] + + sources = [ "ams_ipc_app_mgr_module_test.cpp" ] + + deps = [ "${services_path}/test/moduletest/common/ams:appmgr_mst_source" ] + + external_deps = [ "ipc:ipc_core" ] +} + +group("moduletest") { + testonly = true + + deps = [ ":AmsIpcAppmgrModuleTest" ] +} diff --git a/services/test/moduletest/common/ams/ipc_app_mgr_test/ams_ipc_app_mgr_module_test.cpp b/services/test/moduletest/common/ams/ipc_app_mgr_test/ams_ipc_app_mgr_module_test.cpp new file mode 100644 index 000000000..98dbf3d63 --- /dev/null +++ b/services/test/moduletest/common/ams/ipc_app_mgr_test/ams_ipc_app_mgr_module_test.cpp @@ -0,0 +1,315 @@ +/* + * 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_mgr_proxy.h" +#include "app_scheduler_proxy.h" +#include "app_record_id.h" + +#include "mock_app_mgr_service.h" +#include "mock_application.h" +#include "mock_ability_token.h" + +using namespace testing::ext; +using namespace OHOS::AppExecFwk; +using OHOS::iface_cast; +using OHOS::sptr; +using testing::_; +using testing::Invoke; +using testing::InvokeWithoutArgs; + +namespace { + +const int32_t COUNT = 10000; + +} // namespace + +class AmsIpcAppmgrModuleTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); +}; + +void AmsIpcAppmgrModuleTest::SetUpTestCase() +{} + +void AmsIpcAppmgrModuleTest::TearDownTestCase() +{} + +void AmsIpcAppmgrModuleTest::SetUp() +{} + +void AmsIpcAppmgrModuleTest::TearDown() +{} + +class MockMockAppMgrService : public MockAppMgrService { +public: + MOCK_METHOD0(GetAmsMgr, sptr()); + MOCK_METHOD1(ClearUpApplicationData, void(const std::string &)); + MOCK_METHOD1(IsBackgroundRunningRestricted, int(const std::string &bundleName)); + MOCK_METHOD1(GetAllRunningProcesses, int(std::shared_ptr &)); +}; + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: AppmgrIPCInterface + * FunctionPoints: test attachApplication API,then check the function whether is good or not + * EnvConditions: system running normally + * CaseDescription: excute attachApplication API 10000 times + */ +HWTEST_F(AmsIpcAppmgrModuleTest, ExcuteAppmgrIPCInterface_001, TestSize.Level3) +{ + for (int i = 0; i < COUNT; i++) { + sptr mockAppMgr(new MockAppMgrService()); + sptr appMgrClient = iface_cast(mockAppMgr); + sptr app(new MockApplication()); + + EXPECT_CALL(*mockAppMgr, AttachApplication(_)) + .WillOnce(InvokeWithoutArgs(mockAppMgr.GetRefPtr(), &MockAppMgrService::Post)); + appMgrClient->AttachApplication(app); + mockAppMgr->Wait(); + } +} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: AppmgrIPCInterface + * FunctionPoints: test applicationForegrounded API,then check the function whether is good or not + * EnvConditions: system running normally + * CaseDescription: excute applicationForegrounded API 10000 times + */ +HWTEST_F(AmsIpcAppmgrModuleTest, ExcuteAppmgrIPCInterface_002, TestSize.Level3) +{ + for (int i = 0; i < COUNT; i++) { + sptr mockAppMgr(new MockAppMgrService()); + sptr appMgrClient = iface_cast(mockAppMgr); + auto recordId = AppRecordId::Create(); + + EXPECT_CALL(*mockAppMgr, ApplicationForegrounded(_)) + .WillOnce(InvokeWithoutArgs(mockAppMgr.GetRefPtr(), &MockAppMgrService::Post)); + appMgrClient->ApplicationForegrounded(recordId); + mockAppMgr->Wait(); + } +} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: AppmgrIPCInterface + * FunctionPoints: test applicationBackgrounded API,then check the function whether is good or not + * EnvConditions: system running normally + * CaseDescription: excute applicationBackgrounded API 10000 times + */ +HWTEST_F(AmsIpcAppmgrModuleTest, ExcuteAppmgrIPCInterface_003, TestSize.Level3) +{ + for (int i = 0; i < COUNT; i++) { + sptr mockAppMgr(new MockAppMgrService()); + sptr appMgrClient = iface_cast(mockAppMgr); + auto recordId = AppRecordId::Create(); + + EXPECT_CALL(*mockAppMgr, ApplicationBackgrounded(_)) + .WillOnce(InvokeWithoutArgs(mockAppMgr.GetRefPtr(), &MockAppMgrService::Post)); + appMgrClient->ApplicationBackgrounded(recordId); + mockAppMgr->Wait(); + } +} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: AppmgrIPCInterface + * FunctionPoints: test ApplicationTerminated API,then check the function whether is good or not + * EnvConditions: system running normally + * CaseDescription: excute ApplicationTerminated API 10000 times + */ +HWTEST_F(AmsIpcAppmgrModuleTest, ExcuteAppmgrIPCInterface_004, TestSize.Level3) +{ + for (int i = 0; i < COUNT; i++) { + sptr mockAppMgr(new MockAppMgrService()); + sptr appMgrClient = iface_cast(mockAppMgr); + auto recordId = AppRecordId::Create(); + + EXPECT_CALL(*mockAppMgr, ApplicationTerminated(_)) + .WillOnce(InvokeWithoutArgs(mockAppMgr.GetRefPtr(), &MockAppMgrService::Post)); + appMgrClient->ApplicationTerminated(recordId); + mockAppMgr->Wait(); + } +} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: AppmgrIPCInterface + * FunctionPoints: test AbilityCleaned API,then check the function whether is good or not + * EnvConditions: system running normally + * CaseDescription: excute AbilityClenaed API 10000 times + */ +HWTEST_F(AmsIpcAppmgrModuleTest, ExcuteAppmgrIPCInterface_005, TestSize.Level3) +{ + for (int i = 0; i < COUNT; i++) { + sptr mockAppMgr(new MockAppMgrService()); + sptr appMgrClient = iface_cast(mockAppMgr); + sptr token = new MockAbilityToken; + + EXPECT_CALL(*mockAppMgr, AbilityCleaned(_)) + .WillOnce(InvokeWithoutArgs(mockAppMgr.GetRefPtr(), &MockAppMgrService::Post)); + appMgrClient->AbilityCleaned(token); + mockAppMgr->Wait(); + } +} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: AppmgrIPCInterface + * FunctionPoints: test GetAmsMgr API,then check the function whether is good or not + * EnvConditions: system running normally + * CaseDescription: excute KillApplication API 10000 times + */ +HWTEST_F(AmsIpcAppmgrModuleTest, ExcuteAppmgrIPCInterface_006, TestSize.Level3) +{ + for (int i = 0; i < COUNT; i++) { + sptr mockMockAppMgr(new MockMockAppMgrService()); + sptr appMgrClient = iface_cast(mockMockAppMgr); + + auto mockHandler = [&]() -> sptr { + mockMockAppMgr->Post(); + return sptr(nullptr); + }; + + EXPECT_CALL(*mockMockAppMgr, GetAmsMgr()).Times(1).WillOnce(Invoke(mockHandler)); + + appMgrClient->GetAmsMgr(); + + mockMockAppMgr->Wait(); + } +} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: AppmgrIPCInterface + * FunctionPoints: test ClearUpApplicationData API,then check the function whether is good or not + * EnvConditions: system running normally + * CaseDescription: excute ClearUpApplicationData API 10000 times + */ +HWTEST_F(AmsIpcAppmgrModuleTest, ExcuteAppmgrIPCInterface_007, TestSize.Level3) +{ + for (int i = 0; i < COUNT; i++) { + sptr mockMockAppMgr(new MockMockAppMgrService()); + sptr appMgrClient = iface_cast(mockMockAppMgr); + std::string testBundleName("testApp"); + bool testResult = false; + + auto mockHandler = [&](const std::string &name) { + testResult = (name == testBundleName); + mockMockAppMgr->Post(); + }; + + EXPECT_CALL(*mockMockAppMgr, ClearUpApplicationData(_)).WillOnce(Invoke(mockHandler)); + + appMgrClient->ClearUpApplicationData(testBundleName); + mockMockAppMgr->Wait(); + + EXPECT_TRUE(testResult); + } +} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: AppmgrIPCInterface + * FunctionPoints: test IsBackgroundRunningRestricted API,then check the function whether is good or not + * EnvConditions: system running normally + * CaseDescription: excute IsBackgroundRunningRestricted API 10000 times + */ +HWTEST_F(AmsIpcAppmgrModuleTest, ExcuteAppmgrIPCInterface_008, TestSize.Level3) +{ + for (int i = 0; i < COUNT; i++) { + sptr mockMockAppMgr(new MockMockAppMgrService()); + sptr appMgrClient = iface_cast(mockMockAppMgr); + std::string testBundleName("testApp"); + bool testResult = false; + + auto mockHandler = [&](const std::string &name) { + testResult = (name == testBundleName); + mockMockAppMgr->Post(); + return 0; + }; + + EXPECT_CALL(*mockMockAppMgr, IsBackgroundRunningRestricted(_)).WillOnce(Invoke(mockHandler)); + + appMgrClient->IsBackgroundRunningRestricted(testBundleName); + mockMockAppMgr->Wait(); + + EXPECT_TRUE(testResult); + } +} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: AppmgrIPCInterface + * FunctionPoints: test GetAllRunningProcesses API,then check the function whether is good or not + * EnvConditions: system running normally + * CaseDescription: excute GetAllRunningProcesses API 10000 times + */ +HWTEST_F(AmsIpcAppmgrModuleTest, ExcuteAppmgrIPCInterface_09, TestSize.Level3) +{ + const std::string testBundleName_1("testApp1"); + pid_t testApp1Pid = 1001; + const std::string testBundleName_2("testApp2"); + pid_t testApp2Pid = 1002; + + for (int i = 0; i < COUNT; i++) { + sptr mockMockAppMgr(new MockMockAppMgrService()); + sptr appMgrClient = iface_cast(mockMockAppMgr); + auto allRunningProcessInfo = std::make_shared(); + + auto mockHandler = [&](std::shared_ptr &result) { + result->appProcessInfos.clear(); + + auto &r1 = result->appProcessInfos.emplace_back(); + r1.processName_ = testBundleName_1; + r1.pid_ = testApp1Pid; + + auto &r2 = result->appProcessInfos.emplace_back(); + r2.processName_ = testBundleName_2; + r2.pid_ = testApp2Pid; + + mockMockAppMgr->Post(); + + return 0; + }; + + EXPECT_CALL(*mockMockAppMgr, GetAllRunningProcesses(_)).WillOnce(Invoke(mockHandler)); + + appMgrClient->GetAllRunningProcesses(allRunningProcessInfo); + mockMockAppMgr->Wait(); + + EXPECT_TRUE(allRunningProcessInfo->appProcessInfos.size() == 2); + EXPECT_EQ(allRunningProcessInfo->appProcessInfos[0].processName_, testBundleName_1); + EXPECT_EQ(allRunningProcessInfo->appProcessInfos[0].pid_, testApp1Pid); + EXPECT_EQ(allRunningProcessInfo->appProcessInfos[1].processName_, testBundleName_2); + EXPECT_EQ(allRunningProcessInfo->appProcessInfos[1].pid_, testApp2Pid); + } +} diff --git a/services/test/moduletest/common/ams/ipc_app_scheduler_test/BUILD.gn b/services/test/moduletest/common/ams/ipc_app_scheduler_test/BUILD.gn new file mode 100755 index 000000000..d63e279c4 --- /dev/null +++ b/services/test/moduletest/common/ams/ipc_app_scheduler_test/BUILD.gn @@ -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. + +import("//build/test.gni") +import("//foundation/appexecfwk/standard/appexecfwk.gni") + +module_output_path = "appexecfwk_standard/mstappmgrservice" + +ohos_moduletest("AmsIpcAppSchedulerModuleTest") { + module_out_path = module_output_path + + include_dirs = [] + sources = [ "ams_ipc_app_scheduler_module_test.cpp" ] + + deps = [ "${services_path}/test/moduletest/common/ams:appmgr_mst_source" ] + + external_deps = [ "ipc:ipc_core" ] +} + +group("moduletest") { + testonly = true + + deps = [ ":AmsIpcAppSchedulerModuleTest" ] +} diff --git a/services/test/moduletest/common/ams/ipc_app_scheduler_test/ams_ipc_app_scheduler_module_test.cpp b/services/test/moduletest/common/ams/ipc_app_scheduler_test/ams_ipc_app_scheduler_module_test.cpp new file mode 100644 index 000000000..356d2ba86 --- /dev/null +++ b/services/test/moduletest/common/ams/ipc_app_scheduler_test/ams_ipc_app_scheduler_module_test.cpp @@ -0,0 +1,327 @@ +/* + * 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 "semaphore_ex.h" +#include "app_scheduler_proxy.h" +#include "app_scheduler_host.h" + +#include "mock_ability_token.h" +#include "mock_application.h" +#include "mock_app_scheduler.h" + +using namespace testing::ext; +using namespace OHOS::AppExecFwk; +using OHOS::iface_cast; +using OHOS::sptr; +using testing::_; +using testing::Invoke; +using testing::InvokeWithoutArgs; + +namespace { + +const int32_t COUNT = 10000; + +} // namespace + +class AmsIpcAppSchedulerModuleTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + sptr GetMockToken() const + { + return mock_token_; + } + +private: + sptr mock_token_; +}; + +void AmsIpcAppSchedulerModuleTest::SetUpTestCase() +{} + +void AmsIpcAppSchedulerModuleTest::TearDownTestCase() +{} + +void AmsIpcAppSchedulerModuleTest::SetUp() +{} + +void AmsIpcAppSchedulerModuleTest::TearDown() +{} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: IApplicationScheduler + * FunctionPoints: test ScheduleForegroundApplication API,then check the function whether is good or not + * EnvConditions: system running normally + * CaseDescription: excute ScheduleForegroundApplication API 10000 times + */ +HWTEST_F(AmsIpcAppSchedulerModuleTest, ExcuteApplicationIPCInterface_001, TestSize.Level3) +{ + for (int i = 0; i < COUNT; i++) { + sptr mockApplication(new MockApplication()); + sptr client = iface_cast(mockApplication); + + EXPECT_CALL(*mockApplication, ScheduleForegroundApplication()) + .Times(1) + .WillOnce(InvokeWithoutArgs(mockApplication.GetRefPtr(), &MockApplication::Post)); + client->ScheduleForegroundApplication(); + mockApplication->Wait(); + } +} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: IApplicationScheduler + * FunctionPoints: test ScheduleBackgroundApplication API,then check the function whether is good or not + * EnvConditions: system running normally + * CaseDescription: excute ScheduleBackgroundApplication API 10000 times + */ +HWTEST_F(AmsIpcAppSchedulerModuleTest, ExcuteApplicationIPCInterface_002, TestSize.Level3) +{ + for (int i = 0; i < COUNT; i++) { + sptr mockApplication(new MockApplication()); + sptr client = iface_cast(mockApplication); + + EXPECT_CALL(*mockApplication, ScheduleBackgroundApplication()) + .Times(1) + .WillOnce(InvokeWithoutArgs(mockApplication.GetRefPtr(), &MockApplication::Post)); + client->ScheduleBackgroundApplication(); + mockApplication->Wait(); + } +} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: IApplicationScheduler + * FunctionPoints: test ScheduleTerminateApplication API,then check the function whether is good or not + * EnvConditions: system running normally + * CaseDescription: excute ScheduleTerminateApplication API 10000 times + */ +HWTEST_F(AmsIpcAppSchedulerModuleTest, ExcuteApplicationIPCInterface_003, TestSize.Level3) +{ + for (int i = 0; i < COUNT; i++) { + sptr mockApplication(new MockApplication()); + sptr client = iface_cast(mockApplication); + + EXPECT_CALL(*mockApplication, ScheduleTerminateApplication()) + .Times(1) + .WillOnce(InvokeWithoutArgs(mockApplication.GetRefPtr(), &MockApplication::Post)); + client->ScheduleTerminateApplication(); + mockApplication->Wait(); + } +} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: IApplicationScheduler + * FunctionPoints: test ScheduleTrimMemory API,then check the function whether is good or not + * EnvConditions: system running normally + * CaseDescription: excute ScheduleTrimMemory API 10000 times + */ +HWTEST_F(AmsIpcAppSchedulerModuleTest, ExcuteApplicationIPCInterface_004, TestSize.Level3) +{ + for (int i = 0; i < COUNT; i++) { + sptr mockApplication(new MockApplication()); + sptr client = iface_cast(mockApplication); + + EXPECT_CALL(*mockApplication, ScheduleShrinkMemory(_)) + .Times(1) + .WillOnce(Invoke(mockApplication.GetRefPtr(), &MockApplication::ShrinkMemory)); + int level = 1; + client->ScheduleShrinkMemory(level); + mockApplication->Wait(); + int getLevel = mockApplication->GetShrinkLevel(); + EXPECT_EQ(getLevel, level) << "excute fail, index is " << i; + } +} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: IApplicationScheduler + * FunctionPoints: test scheduleLowMemory API,then check the function whether is good or not + * EnvConditions: system running normally + * CaseDescription: excute LowMemoryWarning API 10000 times + */ +HWTEST_F(AmsIpcAppSchedulerModuleTest, ExcuteApplicationIPCInterface_005, TestSize.Level3) +{ + for (int i = 0; i < COUNT; i++) { + sptr mockApplication(new MockApplication()); + sptr client = iface_cast(mockApplication); + + EXPECT_CALL(*mockApplication, ScheduleLowMemory()) + .Times(1) + .WillOnce(InvokeWithoutArgs(mockApplication.GetRefPtr(), &MockApplication::Post)); + client->ScheduleLowMemory(); + mockApplication->Wait(); + } +} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: IApplicationScheduler + * FunctionPoints: test scheduleProfileChanged API,then check the function whether is good or not + * EnvConditions: system running normally + * CaseDescription: excute scheduleProfileChanged API 10000 times + */ +HWTEST_F(AmsIpcAppSchedulerModuleTest, ExcuteApplicationIPCInterface_006, TestSize.Level3) +{ + for (int i = 0; i < COUNT; i++) { + sptr mockApplication(new MockApplication()); + sptr client = iface_cast(mockApplication); + + std::string profileName("mockProfile"); + Profile profile(profileName); + + EXPECT_CALL(*mockApplication, ScheduleProfileChanged(_)) + .Times(1) + .WillOnce(Invoke(mockApplication.GetRefPtr(), &MockApplication::ProfileChanged)); + client->ScheduleProfileChanged(profile); + mockApplication->Wait(); + bool result = mockApplication->CompareProfile(profile); + EXPECT_EQ(result, true) << "excute fail, index is " << i; + } +} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: IApplicationScheduler + * FunctionPoints: test ScheduleLaunchAbility API,then check the function whether is good or not + * EnvConditions: system running normally + * CaseDescription: excute ScheduleLaunchAbility API 10000 times + */ +HWTEST_F(AmsIpcAppSchedulerModuleTest, ExcuteApplicationIPCInterface_007, TestSize.Level3) +{ + for (int i = 0; i < COUNT; i++) { + sptr mockApplication(new MockApplication()); + sptr client = iface_cast(mockApplication); + + std::string abilityName("mockAbilityInfo"); + AbilityInfo info; + info.name = abilityName; + + EXPECT_CALL(*mockApplication, ScheduleLaunchAbility(_, _)) + .Times(1) + .WillOnce(Invoke(mockApplication.GetRefPtr(), &MockApplication::LaunchAbility)); + client->ScheduleLaunchAbility(info, GetMockToken()); + mockApplication->Wait(); + bool result = mockApplication->CompareAbilityInfo(info); + EXPECT_EQ(result, true) << "excute fail, index is " << i; + } +} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: IApplicationScheduler + * FunctionPoints: test ScheduleLaunchApplication API,then check the function whether is good or not + * EnvConditions: system running normally + * CaseDescription: excute ScheduleLaunchApplication API 10000 times + */ +HWTEST_F(AmsIpcAppSchedulerModuleTest, ExcuteApplicationIPCInterface_008, TestSize.Level3) +{ + for (int i = 0; i < COUNT; i++) { + sptr mockApplication(new MockApplication()); + sptr client = iface_cast(mockApplication); + + std::string applicationName("mockApplicationInfo"); + ApplicationInfo applicationInfo; + applicationInfo.name = applicationName; + std::string profileName("mockProfile"); + Profile profile(profileName); + std::string processName("mockProcessInfo"); + ProcessInfo processInfo(processName, 123); + + AppLaunchData launchData; + launchData.SetApplicationInfo(applicationInfo); + launchData.SetProfile(profile); + launchData.SetProcessInfo(processInfo); + + EXPECT_CALL(*mockApplication, ScheduleLaunchApplication(_)) + .Times(1) + .WillOnce(Invoke(mockApplication.GetRefPtr(), &MockApplication::LaunchApplication)); + client->ScheduleLaunchApplication(launchData); + mockApplication->Wait(); + + bool isEqual = mockApplication->CompareAppLaunchData(launchData); + ASSERT_EQ(true, isEqual) << "excute fail, index is " << i; + } +} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: IApplicationScheduler + * FunctionPoints: test ScheduleCleanAbility API,then check the function whether is good or not + * EnvConditions: system running normally + * CaseDescription: excute ScheduleCleanAbility API 10000 times + */ +HWTEST_F(AmsIpcAppSchedulerModuleTest, ExcuteApplicationIPCInterface_009, TestSize.Level3) +{ + for (int i = 0; i < COUNT; i++) { + sptr mockApplication(new MockApplication()); + sptr client = iface_cast(mockApplication); + + std::string abilityName("mockAbilityInfo"); + + EXPECT_CALL(*mockApplication, ScheduleCleanAbility(_)) + .Times(1) + .WillOnce(InvokeWithoutArgs(mockApplication.GetRefPtr(), &MockApplication::Post)); + client->ScheduleCleanAbility(GetMockToken()); + mockApplication->Wait(); + } +} + +/* + * Feature: ApplicationFramework + * Function: AppManagerService + * SubFunction: IApplicationScheduler + * FunctionPoints: test ScheduleConfigurationUpdated API,then check the function whether is good or not + * EnvConditions: system running normally + * CaseDescription: excute ScheduleConfigurationUpdated API 10000 times + */ +HWTEST_F(AmsIpcAppSchedulerModuleTest, ExcuteApplicationIPCInterface_010, TestSize.Level3) +{ + OHOS::Semaphore sem(0); + Configuration testConfig("testConfig"); + + for (int i = 0; i < COUNT; i++) { + sptr mockAppScheduler(new MockAppScheduler()); + sptr client = iface_cast(mockAppScheduler); + bool testResult = false; + + auto mockHandler = [&](const Configuration &config) { + testResult = (config.GetName() == testConfig.GetName()); + sem.Post(); + }; + + EXPECT_CALL(*mockAppScheduler, ScheduleConfigurationUpdated(_)).Times(1).WillOnce(Invoke(mockHandler)); + + client->ScheduleConfigurationUpdated(testConfig); + + sem.Wait(); + + EXPECT_TRUE(testResult); + } +} diff --git a/services/test/moduletest/common/ams/service_app_spawn_client_test/BUILD.gn b/services/test/moduletest/common/ams/service_app_spawn_client_test/BUILD.gn new file mode 100755 index 000000000..bb5a28da8 --- /dev/null +++ b/services/test/moduletest/common/ams/service_app_spawn_client_test/BUILD.gn @@ -0,0 +1,38 @@ +# 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/mstappmgrservice" + +ohos_moduletest("AmsServiceAppSpawnClientModuleTest") { + module_out_path = module_output_path + + include_dirs = [ + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + ] + defines = [ "usleep(time) = MockSleep(time)" ] + + sources = [ "ams_service_app_spawn_client_module_test.cpp" ] + + deps = [ "${services_path}/test/moduletest/common/ams:appmgr_mst_source" ] + + external_deps = [ "ipc:ipc_core" ] +} + +group("moduletest") { + testonly = true + + deps = [ ":AmsServiceAppSpawnClientModuleTest" ] +} diff --git a/services/test/moduletest/common/ams/service_app_spawn_client_test/ams_service_app_spawn_client_module_test.cpp b/services/test/moduletest/common/ams/service_app_spawn_client_test/ams_service_app_spawn_client_module_test.cpp new file mode 100644 index 000000000..d50d759ce --- /dev/null +++ b/services/test/moduletest/common/ams/service_app_spawn_client_test/ams_service_app_spawn_client_module_test.cpp @@ -0,0 +1,703 @@ +/* + * 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 // std::chrono::seconds +#include + +#include "securec.h" + +// redefine private and protected since testcase need to invoke and test private function +#define private public +#define protected public +#include "app_mgr_service.h" +#undef private +#undef protected + +#include "app_log_wrapper.h" +#include "mock_app_spawn_socket.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; +using testing::_; +using testing::AtLeast; +using testing::InSequence; +using testing::Invoke; +using testing::Return; + +namespace { + +const uint32_t CYCLE_NUMBER = 10; +const int32_t PID_VALUE = 13579; +const int32_t CONNECT_RETRY_MAX_TIMES = 15; + +} // namespace + +// this function is only used to mock sleep method so mst can run without delay. +int MockSleep([[maybe_unused]] uint32_t seconds) +{ + return 0; +} + +class MockedAppSpawnSocket : public AppSpawnSocket { +public: + MockedAppSpawnSocket() + {} + + ~MockedAppSpawnSocket() + {} + + int32_t OpenAppSpawnConnection() override + { + APP_LOGI("MockedAppSpawnSocket::OpenAppSpawnConnection ready to openConnection!"); + gHasConnected_ = true; + if (!gConnectSuccess_) { + APP_LOGE("MockedAppSpawnSocket::OpenAppSpawnConnection mock case failed to openConnection!"); + return ERR_APPEXECFWK_CONNECT_APPSPAWN_FAILED; + } + return ERR_OK; + } + + void CloseAppSpawnConnection() override + { + APP_LOGI("MockedAppSpawnSocket::CloseAppSpawnConnection ready to openConnection!"); + } + + int32_t WriteMessage([[maybe_unused]] const void *buf, [[maybe_unused]] int32_t len) override + { + if (!gHasConnected_) { + APP_LOGE("MockedAppSpawnSocket::WriteMessage mock case not openConnection!"); + return ERR_APPEXECFWK_BAD_APPSPAWN_SOCKET; + } + if (!gConnectSuccess_) { + APP_LOGE("MockedAppSpawnSocket::WriteMessage mock case failed to openConnection!"); + return ERR_APPEXECFWK_CONNECT_APPSPAWN_FAILED; + } + if (!gWriteMessageSuccess_) { + APP_LOGE("MockedAppSpawnSocket::WriteMessage mock case failed to writeMessage!"); + return ERR_APPEXECFWK_SOCKET_WRITE_FAILED; + } + return ERR_OK; + } + + int32_t ReadMessage(void *buf, [[maybe_unused]] int32_t len) override + { + if (!gHasConnected_) { + APP_LOGE("MockedAppSpawnSocket::ReadMessage mock case not openConnection!"); + return ERR_APPEXECFWK_BAD_APPSPAWN_SOCKET; + } + if (!gConnectSuccess_) { + APP_LOGE("MockedAppSpawnSocket::ReadMessage mock case failed to openConnection!"); + return ERR_APPEXECFWK_CONNECT_APPSPAWN_FAILED; + } + if (!gReadMessageSuccess_) { + APP_LOGE("MockedAppSpawnSocket::ReadMessage mock case failed to readMessage!"); + return ERR_APPEXECFWK_SOCKET_READ_FAILED; + } + AppSpawnPidMsg msg; + msg.pid = PID_VALUE; + if (memcpy_s(buf, sizeof(msg), msg.pidBuf, sizeof(msg)) != EOK) { + return ERR_APPEXECFWK_ASSEMBLE_START_MSG_FAILED; + } + return ERR_OK; + } + + static bool gConnectSuccess_; + static bool gHasConnected_; + static bool gWriteMessageSuccess_; + static bool gReadMessageSuccess_; +}; + +bool MockedAppSpawnSocket::gHasConnected_ = false; +bool MockedAppSpawnSocket::gConnectSuccess_ = true; +bool MockedAppSpawnSocket::gWriteMessageSuccess_ = true; +bool MockedAppSpawnSocket::gReadMessageSuccess_ = true; + +class MockedAppMgrServiceInner : public AppMgrServiceInner { +public: + MockedAppMgrServiceInner() + : socket_(std::make_shared()), appSpawnClient_(std::make_unique()) + { + appSpawnClient_->SetSocket(socket_); + } + + virtual ~MockedAppMgrServiceInner() + {} + int32_t OpenAppSpawnConnection() override + { + if (appSpawnClient_.get() != nullptr) { + return appSpawnClient_->OpenConnection(); + } + return ERR_APPEXECFWK_BAD_APPSPAWN_CLIENT; + } + + SpawnConnectionState QueryAppSpawnConnectionState() const override + { + if (appSpawnClient_) { + return appSpawnClient_->QueryConnectionState(); + } + return SpawnConnectionState::STATE_NOT_CONNECT; + } + + void CloseAppSpawnConnection() const override + { + if (appSpawnClient_) { + appSpawnClient_->CloseConnection(); + } + } + +private: + std::shared_ptr socket_; + std::unique_ptr appSpawnClient_; +}; + +class AmsServiceAppSpawnClientModuleTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); +}; + +void AmsServiceAppSpawnClientModuleTest::SetUpTestCase() +{} + +void AmsServiceAppSpawnClientModuleTest::TearDownTestCase() +{} + +void AmsServiceAppSpawnClientModuleTest::SetUp() +{ + MockedAppSpawnSocket::gHasConnected_ = false; + MockedAppSpawnSocket::gConnectSuccess_ = true; + MockedAppSpawnSocket::gWriteMessageSuccess_ = true; + MockedAppSpawnSocket::gReadMessageSuccess_ = true; +} + +void AmsServiceAppSpawnClientModuleTest::TearDown() +{} + +/* + * Feature: AppMgrService + * Function: AppSpawnClient + * SubFunction: NA + * FunctionPoints: Create AppSpawnClient and connect to AppSpawnDaemon + * EnvConditions: NA + * CaseDescription: Test if AppMgrService act normal when create appspawnclient and connect to AppSpawnDaemon. + */ +HWTEST_F(AmsServiceAppSpawnClientModuleTest, ConnectAppSpawnDaemon_001, TestSize.Level2) +{ + APP_LOGI("ConnectAppSpawnDaemon_001 start"); + std::shared_ptr appMgrService = std::make_shared(); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appMgrService->QueryServiceState().connectionState); + std::shared_ptr amsInner = std::make_shared(); + appMgrService->SetInnerService(amsInner); + for (uint32_t i = 0; i < CYCLE_NUMBER; i++) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + appMgrService->OnStart(); + ASSERT_EQ(SpawnConnectionState::STATE_CONNECTED, appMgrService->QueryServiceState().connectionState); + ASSERT_EQ(SpawnConnectionState::STATE_CONNECTED, amsInner->QueryAppSpawnConnectionState()); + appMgrService->OnStop(); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appMgrService->QueryServiceState().connectionState); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, amsInner->QueryAppSpawnConnectionState()); + } + APP_LOGI("ConnectAppSpawnDaemon_001 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnClient + * SubFunction: NA + * FunctionPoints: Create AppSpawnClient and connect to AppSpawnDaemon in AppMgrService_002 + * EnvConditions: NA + * CaseDescription: Test if AppMgrService act normal when create appspawnclient and failed connect to AppSpawnDaemon. + */ +HWTEST_F(AmsServiceAppSpawnClientModuleTest, ConnectAppSpawnDaemon_002, TestSize.Level2) +{ + APP_LOGI("ConnectAppSpawnDaemon_002 start"); + std::shared_ptr appMgrService = std::make_shared(); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appMgrService->QueryServiceState().connectionState); + std::shared_ptr amsInner = std::make_shared(); + appMgrService->SetInnerService(amsInner); + for (uint32_t i = 0; i < CYCLE_NUMBER; i++) { + MockedAppSpawnSocket::gConnectSuccess_ = false; + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + appMgrService->OnStart(); + EXPECT_EQ(SpawnConnectionState::STATE_CONNECT_FAILED, appMgrService->QueryServiceState().connectionState); + EXPECT_EQ(SpawnConnectionState::STATE_CONNECT_FAILED, amsInner->QueryAppSpawnConnectionState()); + appMgrService->OnStop(); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appMgrService->QueryServiceState().connectionState); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, amsInner->QueryAppSpawnConnectionState()); + MockedAppSpawnSocket::gConnectSuccess_ = true; + appMgrService->OnStart(); + ASSERT_EQ(SpawnConnectionState::STATE_CONNECTED, appMgrService->QueryServiceState().connectionState); + ASSERT_EQ(SpawnConnectionState::STATE_CONNECTED, amsInner->QueryAppSpawnConnectionState()); + appMgrService->OnStop(); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appMgrService->QueryServiceState().connectionState); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, amsInner->QueryAppSpawnConnectionState()); + } + APP_LOGI("ConnectAppSpawnDaemon_002 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnClient + * SubFunction: NA + * FunctionPoints: AppSpawnClient connect to AppSpawnDaemon + * EnvConditions: NA + * CaseDescription: Test if AppSpawnClient act normal when connect to AppSpawnDaemon twice. + */ +HWTEST_F(AmsServiceAppSpawnClientModuleTest, ConnectAppSpawnDaemon_003, TestSize.Level2) +{ + APP_LOGI("ConnectAppSpawnDaemon_003 start"); + std::shared_ptr appMgrService = std::make_shared(); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appMgrService->QueryServiceState().connectionState); + std::shared_ptr amsInner = std::make_shared(); + appMgrService->SetInnerService(amsInner); + for (uint32_t i = 0; i < CYCLE_NUMBER; i++) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + appMgrService->OnStart(); + ASSERT_EQ(SpawnConnectionState::STATE_CONNECTED, appMgrService->QueryServiceState().connectionState); + ASSERT_EQ(SpawnConnectionState::STATE_CONNECTED, amsInner->QueryAppSpawnConnectionState()); + appMgrService->OnStart(); + EXPECT_EQ(SpawnConnectionState::STATE_CONNECTED, appMgrService->QueryServiceState().connectionState); + EXPECT_EQ(SpawnConnectionState::STATE_CONNECTED, amsInner->QueryAppSpawnConnectionState()); + appMgrService->OnStop(); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appMgrService->QueryServiceState().connectionState); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, amsInner->QueryAppSpawnConnectionState()); + } + APP_LOGI("ConnectAppSpawnDaemon_003 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnClient + * SubFunction: NA + * FunctionPoints: AppSpawnClient connect to AppSpawnDaemon + * EnvConditions: NA + * CaseDescription: Test if AppSpawnClient act normal when connect to AppSpawnDaemon successfully. + */ +HWTEST_F(AmsServiceAppSpawnClientModuleTest, ConnectAppSpawnDaemon_004, TestSize.Level1) +{ + APP_LOGI("ConnectAppSpawnDaemon_004 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr mockedAppSpawnSocket = std::make_shared(); + appSpawnClient->SetSocket(mockedAppSpawnSocket); + for (uint32_t i = 0; i < CYCLE_NUMBER; i++) { + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appSpawnClient->QueryConnectionState()); + EXPECT_EQ(ERR_OK, appSpawnClient->OpenConnection()); + EXPECT_EQ(SpawnConnectionState::STATE_CONNECTED, appSpawnClient->QueryConnectionState()); + EXPECT_EQ(ERR_OK, mockedAppSpawnSocket->OpenAppSpawnConnection()); + appSpawnClient->CloseConnection(); + } + APP_LOGI("ConnectAppSpawnDaemon_004 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnClient + * SubFunction: NA + * FunctionPoints: AppSpawnClient request normal process + * EnvConditions: NA + * CaseDescription: Test if AppSpawnClient act normal when successfully to send normal request message. + */ +HWTEST_F(AmsServiceAppSpawnClientModuleTest, ConnectAppSpawnDaemon_005, TestSize.Level1) +{ + APP_LOGI("ConnectAppSpawnDaemon_005 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr mockedAppSpawnSocket = std::make_shared(); + appSpawnClient->SetSocket(mockedAppSpawnSocket); + for (uint32_t i = 0; i < CYCLE_NUMBER; i++) { + EXPECT_EQ(ERR_OK, appSpawnClient->OpenConnection()); + AppSpawnStartMsg params = {10001, 10001, {10001, 10002}, "processName", "soPath"}; + int32_t pid = PID_VALUE; + int32_t newPid = 0; + appSpawnClient->StartProcess(params, newPid); + EXPECT_EQ(pid, newPid); + EXPECT_EQ(ERR_OK, mockedAppSpawnSocket->OpenAppSpawnConnection()); + } + appSpawnClient->CloseConnection(); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appSpawnClient->QueryConnectionState()); + APP_LOGI("ConnectAppSpawnDaemon_005 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnClient + * SubFunction: NA + * FunctionPoints: AppSpawnClient request normal process + * EnvConditions: NA + * CaseDescription: Test if AppSpawnClient act normal when connect daemon successfully but failed + * to start process when try to send abnormal request message with wrong AppName. + */ +HWTEST_F(AmsServiceAppSpawnClientModuleTest, ConnectAppSpawnDaemon_006, TestSize.Level1) +{ + APP_LOGI("ConnectAppSpawnDaemon_006 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr mockedAppSpawnSocket = std::make_shared(); + appSpawnClient->SetSocket(mockedAppSpawnSocket); + std::string illegalAppName = "01234567890123456789012345678901234567890123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789012345678901234567890123456789" + "0123456789012345"; // The length is 256. + for (uint32_t i = 0; i < CYCLE_NUMBER; i++) { + EXPECT_EQ(ERR_OK, appSpawnClient->OpenConnection()); + AppSpawnStartMsg params = {10001, 10001, {10001, 10002}, "processName", illegalAppName}; + int32_t newPid = 0; + ErrCode result = appSpawnClient->StartProcess(params, newPid); + EXPECT_EQ(ERR_APPEXECFWK_ASSEMBLE_START_MSG_FAILED, result); + EXPECT_EQ(ERR_OK, mockedAppSpawnSocket->OpenAppSpawnConnection()); + } + appSpawnClient->CloseConnection(); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appSpawnClient->QueryConnectionState()); + APP_LOGI("ConnectAppSpawnDaemon_006 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnClient + * SubFunction: NA + * FunctionPoints: AppSpawnClient request normal process + * EnvConditions: NA + * CaseDescription: Test if AppSpawnClient act normal when connect daemon successfully but failed + * to start process when try to send abnormal request message with wrong ClsName. + */ +HWTEST_F(AmsServiceAppSpawnClientModuleTest, ConnectAppSpawnDaemon_007, TestSize.Level1) +{ + APP_LOGI("ConnectAppSpawnDaemon_007 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr mockedAppSpawnSocket = std::make_shared(); + + std::string illegalClsName = "01234567890123456789012345678901234567890123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789012345678901234567890123456789" + "0123456789012345"; // The length is 256. + appSpawnClient->SetSocket(mockedAppSpawnSocket); + for (uint32_t i = 0; i < CYCLE_NUMBER; i++) { + EXPECT_EQ(ERR_OK, appSpawnClient->OpenConnection()); + + AppSpawnStartMsg params = {10001, 10001, {10001, 10002}, "processName", illegalClsName}; + int32_t newPid = 0; + ErrCode result = appSpawnClient->StartProcess(params, newPid); + EXPECT_EQ(ERR_APPEXECFWK_ASSEMBLE_START_MSG_FAILED, result); + EXPECT_EQ(ERR_OK, mockedAppSpawnSocket->OpenAppSpawnConnection()); + } + appSpawnClient->CloseConnection(); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appSpawnClient->QueryConnectionState()); + APP_LOGI("ConnectAppSpawnDaemon_007 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnClient + * SubFunction: NA + * FunctionPoints: AppSpawnClient request normal process + * EnvConditions: NA + * CaseDescription: Test if AppSpawnClient act normal when connect daemon successfully but failed to start + * process when try to send abnormal request message with wrong FuncName. + */ +HWTEST_F(AmsServiceAppSpawnClientModuleTest, ConnectAppSpawnDaemon_008, TestSize.Level1) +{ + APP_LOGI("ConnectAppSpawnDaemon_008 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr mockedAppSpawnSocket = std::make_shared(); + + std::string illegalFuncName = "0123456789012345678901234567890123456789012345678901234567890123456789012345678" + "0123456789012345678901234567890123456789012345678901234567890123456789012345678" + "0123456789012345678901234567890123456789012345678901234567890123456789012345678" + "0123456789012345999"; // The length is 256. + appSpawnClient->SetSocket(mockedAppSpawnSocket); + for (uint32_t i = 0; i < CYCLE_NUMBER; i++) { + EXPECT_EQ(ERR_OK, appSpawnClient->OpenConnection()); + + AppSpawnStartMsg params = {10001, 10001, {10001, 10002}, "processName", illegalFuncName}; + int32_t newPid = 0; + ErrCode result = appSpawnClient->StartProcess(params, newPid); + EXPECT_EQ(ERR_APPEXECFWK_ASSEMBLE_START_MSG_FAILED, result); + EXPECT_EQ(ERR_OK, mockedAppSpawnSocket->OpenAppSpawnConnection()); + } + appSpawnClient->CloseConnection(); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appSpawnClient->QueryConnectionState()); + APP_LOGI("ConnectAppSpawnDaemon_008 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnClient + * SubFunction: NA + * FunctionPoints: AppSpawnClient request normal process + * EnvConditions: NA + * CaseDescription: Test if AppSpawnClient act normal when connect daemon successfully but failed to start + * process when try to send abnormal request message with wrong argnum. + */ +HWTEST_F(AmsServiceAppSpawnClientModuleTest, ConnectAppSpawnDaemon_009, TestSize.Level1) +{ + APP_LOGI("ConnectAppSpawnDaemon_009 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr mockedAppSpawnSocket = std::make_shared(); + appSpawnClient->SetSocket(mockedAppSpawnSocket); + for (uint32_t i = 0; i < CYCLE_NUMBER; i++) { + EXPECT_EQ(ERR_OK, appSpawnClient->OpenConnection()); + AppSpawnStartMsg params = {10001, 10001, {10001, 10002}, "processName", "soPath"}; + + int32_t newPid = 0; + ErrCode result = appSpawnClient->StartProcess(params, newPid); + EXPECT_EQ(ERR_OK, result); + EXPECT_EQ(ERR_OK, mockedAppSpawnSocket->OpenAppSpawnConnection()); + } + appSpawnClient->CloseConnection(); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appSpawnClient->QueryConnectionState()); + APP_LOGI("ConnectAppSpawnDaemon_009 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnClient + * SubFunction: NA + * FunctionPoints: AppSpawnClient request normal process + * EnvConditions: NA + * CaseDescription: Test if AppSpawnClient act normal when connect daemon successfully but failed to start + * process when try to send abnormal request message with wrong ArgName and ArgNum. + */ +HWTEST_F(AmsServiceAppSpawnClientModuleTest, ConnectAppSpawnDaemon_010, TestSize.Level1) +{ + APP_LOGI("ConnectAppSpawnDaemon_010 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr mockedAppSpawnSocket = std::make_shared(); + appSpawnClient->SetSocket(mockedAppSpawnSocket); + for (uint32_t i = 0; i < CYCLE_NUMBER; i++) { + EXPECT_EQ(ERR_OK, appSpawnClient->OpenConnection()); + AppSpawnStartMsg params = {10001, 10001, {10001, 10002}, "processName", "soPath"}; + + int32_t newPid = 0; + ErrCode result = appSpawnClient->StartProcess(params, newPid); + EXPECT_EQ(ERR_OK, result); + EXPECT_EQ(ERR_OK, mockedAppSpawnSocket->OpenAppSpawnConnection()); + } + appSpawnClient->CloseConnection(); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appSpawnClient->QueryConnectionState()); + APP_LOGI("ConnectAppSpawnDaemon_010 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnClient + * SubFunction: NA + * FunctionPoints: AppSpawnClient request normal process + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Test if AppSpawnClient act normal when failed to connect daemon at first but reconnect successfully. + */ +HWTEST_F(AmsServiceAppSpawnClientModuleTest, ReconnectAppSpawnDaemon_001, TestSize.Level0) +{ + APP_LOGI("ReconnectAppSpawnDaemon_001 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr mockedAppSpawnSocket = std::make_shared(); + appSpawnClient->SetSocket(mockedAppSpawnSocket); + AppSpawnStartMsg params = {10001, 10001, {10001, 10002}, "processName", "soPath"}; + + int32_t pid = PID_VALUE; + int32_t newPid = 0; + + EXPECT_CALL(*mockedAppSpawnSocket, OpenAppSpawnConnection()) + .WillOnce(Return(ERR_APPEXECFWK_CONNECT_APPSPAWN_FAILED)) + .WillRepeatedly(Return(ERR_OK)); + EXPECT_CALL(*mockedAppSpawnSocket, WriteMessage(_, _)).WillRepeatedly(Return(ERR_OK)); + EXPECT_CALL(*mockedAppSpawnSocket, ReadMessage(_, _)) + .WillRepeatedly(Invoke(mockedAppSpawnSocket.get(), &MockAppSpawnSocket::ReadImpl)); + + EXPECT_CALL(*mockedAppSpawnSocket, CloseAppSpawnConnection()).Times(1); + EXPECT_EQ(ERR_APPEXECFWK_CONNECT_APPSPAWN_FAILED, mockedAppSpawnSocket->OpenAppSpawnConnection()); + mockedAppSpawnSocket->SetExpectPid(pid); + auto returnCode = appSpawnClient->StartProcess(params, newPid); + EXPECT_EQ(pid, newPid); + EXPECT_EQ(ERR_OK, returnCode); + APP_LOGI("ReconnectAppSpawnDaemon_001 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnClient + * SubFunction: NA + * FunctionPoints: AppSpawnClient request normal process + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Test if AppSpawnClient act normal when failed to connect daemon but the last reconnect successfully. + */ +HWTEST_F(AmsServiceAppSpawnClientModuleTest, ReconnectAppSpawnDaemon_002, TestSize.Level0) +{ + APP_LOGI("ReconnectAppSpawnDaemon_002 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr mockedAppSpawnSocket = std::make_shared(); + appSpawnClient->SetSocket(mockedAppSpawnSocket); + AppSpawnStartMsg params = {10001, 10001, {10001, 10002}, "processName", "soPath"}; + + int32_t pid = PID_VALUE; + int32_t newPid = 0; + InSequence sequence; + + EXPECT_CALL(*mockedAppSpawnSocket, OpenAppSpawnConnection()) + .Times(CONNECT_RETRY_MAX_TIMES) + .WillRepeatedly(Return(ERR_APPEXECFWK_CONNECT_APPSPAWN_FAILED)) + .RetiresOnSaturation(); + EXPECT_CALL(*mockedAppSpawnSocket, OpenAppSpawnConnection()).WillOnce(Return(ERR_OK)); + EXPECT_CALL(*mockedAppSpawnSocket, WriteMessage(_, _)).WillRepeatedly(Return(ERR_OK)); + EXPECT_CALL(*mockedAppSpawnSocket, ReadMessage(_, _)) + .WillRepeatedly(Invoke(mockedAppSpawnSocket.get(), &MockAppSpawnSocket::ReadImpl)); + EXPECT_CALL(*mockedAppSpawnSocket, CloseAppSpawnConnection()).Times(AtLeast(1)); + mockedAppSpawnSocket->SetExpectPid(pid); + auto returnCode = appSpawnClient->StartProcessImpl(params, newPid); + EXPECT_EQ(pid, newPid); + EXPECT_EQ(ERR_OK, returnCode); + APP_LOGI("ReconnectAppSpawnDaemon_002 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnClient + * SubFunction: NA + * FunctionPoints: AppSpawnClient request normal process + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Test if AppSpawnClient act normal when failed to connect daemon and still fail to reconnect + * for the max times. + */ +HWTEST_F(AmsServiceAppSpawnClientModuleTest, ReconnectAppSpawnDaemon_003, TestSize.Level0) +{ + APP_LOGI("ReconnectAppSpawnDaemon_003 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr mockedAppSpawnSocket = std::make_shared(); + appSpawnClient->SetSocket(mockedAppSpawnSocket); + AppSpawnStartMsg params = {10001, 10001, {10001, 10002}, "processName", "soPath"}; + + int32_t pid = PID_VALUE; + int32_t newPid = 0; + InSequence sequence; + + EXPECT_CALL(*mockedAppSpawnSocket, OpenAppSpawnConnection()) + .Times(CONNECT_RETRY_MAX_TIMES + 1) + .WillRepeatedly(Return(ERR_APPEXECFWK_CONNECT_APPSPAWN_FAILED)); + mockedAppSpawnSocket->SetExpectPid(pid); + auto returnCode = appSpawnClient->StartProcessImpl(params, newPid); + EXPECT_NE(pid, newPid); + EXPECT_EQ(ERR_APPEXECFWK_CONNECT_APPSPAWN_FAILED, returnCode); + APP_LOGI("ReconnectAppSpawnDaemon_003 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnClient + * SubFunction: NA + * FunctionPoints: AppSpawnClient request normal process + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Test if AppSpawnClient act normal when failed to start process for ReadMessage, + * but the last is successful. + */ +HWTEST_F(AmsServiceAppSpawnClientModuleTest, ReconnectAppSpawnDaemon_004, TestSize.Level0) +{ + APP_LOGI("ReconnectAppSpawnDaemon_004 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr mockedAppSpawnSocket = std::make_shared(); + appSpawnClient->SetSocket(mockedAppSpawnSocket); + AppSpawnStartMsg params = {10001, 10001, {10001, 10002}, "processName", "soPath"}; + int32_t pid = PID_VALUE; + int32_t newPid = 0; + InSequence sequence; + + for (int32_t i = 0; i < CONNECT_RETRY_MAX_TIMES; i++) { + EXPECT_CALL(*mockedAppSpawnSocket, OpenAppSpawnConnection()).WillOnce(Return(ERR_OK)); + EXPECT_CALL(*mockedAppSpawnSocket, WriteMessage(_, _)) + .WillRepeatedly(Return(ERR_APPEXECFWK_SOCKET_WRITE_FAILED)) + .RetiresOnSaturation(); + EXPECT_CALL(*mockedAppSpawnSocket, ReadMessage(_, _)).WillRepeatedly(Return(ERR_OK)).RetiresOnSaturation(); + EXPECT_CALL(*mockedAppSpawnSocket, CloseAppSpawnConnection()).Times(1); + } + EXPECT_CALL(*mockedAppSpawnSocket, OpenAppSpawnConnection()).WillOnce(Return(ERR_OK)); + EXPECT_CALL(*mockedAppSpawnSocket, WriteMessage(_, _)).WillOnce(Return(ERR_OK)); + EXPECT_CALL(*mockedAppSpawnSocket, ReadMessage(_, _)) + .WillOnce(Invoke(mockedAppSpawnSocket.get(), &MockAppSpawnSocket::ReadImpl)); + EXPECT_CALL(*mockedAppSpawnSocket, CloseAppSpawnConnection()).Times(1); + + mockedAppSpawnSocket->SetExpectPid(pid); + auto returnCode = appSpawnClient->StartProcess(params, newPid); + EXPECT_EQ(pid, newPid); + EXPECT_EQ(ERR_OK, returnCode); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appSpawnClient->QueryConnectionState()); + APP_LOGI("ReconnectAppSpawnDaemon_004 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnClient + * SubFunction: NA + * FunctionPoints: AppSpawnClient request normal process + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Test if AppSpawnClient act normal when failed to connect daemon for ReadMessage. + */ +HWTEST_F(AmsServiceAppSpawnClientModuleTest, ReconnectAppSpawnDaemon_005, TestSize.Level0) +{ + APP_LOGI("ReconnectAppSpawnDaemon_005 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr mockedAppSpawnSocket = std::make_shared(); + appSpawnClient->SetSocket(mockedAppSpawnSocket); + AppSpawnStartMsg params = {10001, 10001, {10001, 10002}, "processName", "soPath"}; + int32_t newPid = 0; + + EXPECT_CALL(*mockedAppSpawnSocket, OpenAppSpawnConnection()).WillRepeatedly(Return(ERR_OK)); + EXPECT_CALL(*mockedAppSpawnSocket, WriteMessage(_, _)).WillRepeatedly(Return(ERR_OK)); + EXPECT_CALL(*mockedAppSpawnSocket, ReadMessage(_, _)).WillRepeatedly(Return(ERR_APPEXECFWK_SOCKET_READ_FAILED)); + EXPECT_CALL(*mockedAppSpawnSocket, CloseAppSpawnConnection()).Times(CONNECT_RETRY_MAX_TIMES + 1); + EXPECT_EQ(ERR_OK, mockedAppSpawnSocket->OpenAppSpawnConnection()); + auto returnCode = appSpawnClient->StartProcess(params, newPid); + EXPECT_EQ(ERR_APPEXECFWK_SOCKET_READ_FAILED, returnCode); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appSpawnClient->QueryConnectionState()); + APP_LOGI("ReconnectAppSpawnDaemon_005 end"); +} + +/* + * Feature: AppMgrService + * Function: AppSpawnClient + * SubFunction: NA + * FunctionPoints: AppSpawnClient request normal process + * EnvConditions: mobile that can run ohos test framework + * CaseDescription: Test if AppSpawnClient act normal when failed to connect daemon for + * ((CONNECT_RETRY_MAX_TIMES + 1) * (CONNECT_RETRY_MAX_TIMES + 1) - 1) times, + * but the last is successful. + */ +HWTEST_F(AmsServiceAppSpawnClientModuleTest, ReconnectAppSpawnDaemon_006, TestSize.Level0) +{ + APP_LOGI("ReconnectAppSpawnDaemon_006 start"); + std::shared_ptr appSpawnClient = std::make_shared(); + std::shared_ptr mockedAppSpawnSocket = std::make_shared(); + appSpawnClient->SetSocket(mockedAppSpawnSocket); + AppSpawnStartMsg params = {10001, 10001, {10001, 10002}, "processName", "soPath"}; + int32_t pid = PID_VALUE; + int32_t newPid = 0; + InSequence sequence; + + EXPECT_CALL(*mockedAppSpawnSocket, OpenAppSpawnConnection()) + .Times((CONNECT_RETRY_MAX_TIMES + 1) * (CONNECT_RETRY_MAX_TIMES + 1) - 1) + .WillRepeatedly(Return(ERR_APPEXECFWK_CONNECT_APPSPAWN_FAILED)) + .RetiresOnSaturation(); + EXPECT_CALL(*mockedAppSpawnSocket, OpenAppSpawnConnection()).WillOnce(Return(ERR_OK)); + EXPECT_CALL(*mockedAppSpawnSocket, WriteMessage(_, _)).WillRepeatedly(Return(ERR_OK)); + EXPECT_CALL(*mockedAppSpawnSocket, ReadMessage(_, _)) + .WillRepeatedly(Invoke(mockedAppSpawnSocket.get(), &MockAppSpawnSocket::ReadImpl)); + EXPECT_CALL(*mockedAppSpawnSocket, CloseAppSpawnConnection()).Times(AtLeast(1)); + mockedAppSpawnSocket->SetExpectPid(pid); + auto returnCode = appSpawnClient->StartProcess(params, newPid); + EXPECT_EQ(pid, newPid); + EXPECT_EQ(ERR_OK, returnCode); + EXPECT_EQ(SpawnConnectionState::STATE_NOT_CONNECT, appSpawnClient->QueryConnectionState()); + APP_LOGI("ReconnectAppSpawnDaemon_006 end"); +} \ No newline at end of file diff --git a/services/test/moduletest/common/ams/service_event_drive_test/BUILD.gn b/services/test/moduletest/common/ams/service_event_drive_test/BUILD.gn new file mode 100755 index 000000000..44cf48ceb --- /dev/null +++ b/services/test/moduletest/common/ams/service_event_drive_test/BUILD.gn @@ -0,0 +1,38 @@ +# 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/mstappmgrservice" + +ohos_moduletest("AmsServiceEventDriveModuleTest") { + module_out_path = module_output_path + + include_dirs = [ + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include/hilog/", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + ] + + sources = [ "ams_service_event_drive_module_test.cpp" ] + + deps = [ "${services_path}/test/moduletest/common/ams:appmgr_mst_source" ] + + external_deps = [ "ipc:ipc_core" ] +} + +group("moduletest") { + testonly = true + + deps = [ ":AmsServiceEventDriveModuleTest" ] +} diff --git a/services/test/moduletest/common/ams/service_event_drive_test/ams_service_event_drive_module_test.cpp b/services/test/moduletest/common/ams/service_event_drive_test/ams_service_event_drive_module_test.cpp new file mode 100644 index 000000000..ae18a3970 --- /dev/null +++ b/services/test/moduletest/common/ams/service_event_drive_test/ams_service_event_drive_module_test.cpp @@ -0,0 +1,577 @@ +/* + * 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. + */ + +// redefine private and protected since testcase need to invoke and test private function +#define private public +#define protected public +#include "app_mgr_service.h" +#undef private +#undef protected +#include +#include "semaphore_ex.h" +#include "app_log_wrapper.h" + +using namespace testing::ext; +using namespace OHOS::AppExecFwk; +using OHOS::Semaphore; + +namespace { + +const uint32_t CYCLE_NUMBER = 10000; + +} + +enum class AmsInnerState { + STATE_NO_OPERATION, + STATE_ABILITY_LOADED, + STATE_APPLICATION_FOREGROUNDED, + STATE_APPLICATION_BACKGROUNDED, + STATE_APPLICATION_TERMINATED, + STATE_APPLICATION_BACK_TO_FORE, + STATE_APPLICATION_FORE_TO_BACK, + STATE_APPLICATION_BACK_TO_TER, + STATE_APPLICATION_FORE_TO_TER, + STATE_APPLICATION_TER_TO_FORE, + STATE_APPLICATION_TER_TO_BACK, +}; + +class MockedAppMgrServiceInner : public AppMgrServiceInner { +public: + MockedAppMgrServiceInner() : lock_(0) + {} + ~MockedAppMgrServiceInner() + {} + + void ApplicationForegrounded([[maybe_unused]] const int32_t recordId) override + { + if (lastState_ == AmsInnerState::STATE_APPLICATION_BACKGROUNDED || + lastState_ == AmsInnerState::STATE_APPLICATION_FORE_TO_BACK || + lastState_ == AmsInnerState::STATE_APPLICATION_TER_TO_BACK) { + state_ = AmsInnerState::STATE_APPLICATION_BACK_TO_FORE; + } else if (lastState_ == AmsInnerState::STATE_APPLICATION_TERMINATED || + lastState_ == AmsInnerState::STATE_APPLICATION_BACK_TO_TER || + lastState_ == AmsInnerState::STATE_APPLICATION_FORE_TO_TER) { + state_ = AmsInnerState::STATE_APPLICATION_TER_TO_FORE; + } else { + state_ = AmsInnerState::STATE_APPLICATION_FOREGROUNDED; + } + + lastState_ = AmsInnerState::STATE_APPLICATION_FOREGROUNDED; + Post(); + } + + void ApplicationBackgrounded([[maybe_unused]] const int32_t recordId) override + { + if (lastState_ == AmsInnerState::STATE_APPLICATION_FOREGROUNDED || + lastState_ == AmsInnerState::STATE_APPLICATION_BACK_TO_FORE || + lastState_ == AmsInnerState::STATE_APPLICATION_TER_TO_FORE) { + state_ = AmsInnerState::STATE_APPLICATION_FORE_TO_BACK; + } else if (lastState_ == AmsInnerState::STATE_APPLICATION_TERMINATED || + lastState_ == AmsInnerState::STATE_APPLICATION_BACK_TO_TER || + lastState_ == AmsInnerState::STATE_APPLICATION_FORE_TO_TER) { + state_ = AmsInnerState::STATE_APPLICATION_TER_TO_BACK; + } else { + state_ = AmsInnerState::STATE_APPLICATION_BACKGROUNDED; + } + + lastState_ = AmsInnerState::STATE_APPLICATION_BACKGROUNDED; + Post(); + } + + void ApplicationTerminated([[maybe_unused]] const int32_t recordId) override + { + if (lastState_ == AmsInnerState::STATE_APPLICATION_FOREGROUNDED || + lastState_ == AmsInnerState::STATE_APPLICATION_BACK_TO_FORE || + lastState_ == AmsInnerState::STATE_APPLICATION_TER_TO_FORE) { + state_ = AmsInnerState::STATE_APPLICATION_FORE_TO_TER; + } else if (lastState_ == AmsInnerState::STATE_APPLICATION_BACKGROUNDED || + lastState_ == AmsInnerState::STATE_APPLICATION_FORE_TO_BACK || + lastState_ == AmsInnerState::STATE_APPLICATION_TER_TO_BACK) { + state_ = AmsInnerState::STATE_APPLICATION_BACK_TO_TER; + } else { + state_ = AmsInnerState::STATE_APPLICATION_TERMINATED; + } + + lastState_ = AmsInnerState::STATE_APPLICATION_TERMINATED; + Post(); + } + + void Wait() + { + lock_.Wait(); + } + + void SetWaitNum(const int waitNum) + { + count_ = waitNum; + currentCount_ = waitNum; + } + + AmsInnerState GetInnerServiceState() const + { + return state_; + } + + AmsInnerState SetInnerServiceState(const AmsInnerState &state) + { + state_ = state; + return state_; + } + + int32_t OpenAppSpawnConnection() override + { + return 0; + } + +private: + Semaphore lock_ = {0}; + int32_t count_ = 1; + int32_t currentCount_ = 1; + AmsInnerState state_ = AmsInnerState::STATE_NO_OPERATION; + AmsInnerState lastState_ = AmsInnerState::STATE_NO_OPERATION; + + void Post() + { + if (currentCount_ > 1) { + currentCount_--; + } else { + lock_.Post(); + currentCount_ = count_; + } + } +}; + +class AmsServiceEventDriveModuleTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + +protected: + std::shared_ptr appMgrService_; +}; + +void AmsServiceEventDriveModuleTest::SetUpTestCase() +{} + +void AmsServiceEventDriveModuleTest::TearDownTestCase() +{} + +void AmsServiceEventDriveModuleTest::SetUp() +{ + appMgrService_ = std::make_shared(); +} + +void AmsServiceEventDriveModuleTest::TearDown() +{ + appMgrService_.reset(); +} + +/* + * Feature: AppMgrService + * Function: EventDrive + * SubFunction: NA + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: NA + * CaseDescription: Verify if post application from background to foreground. + */ +HWTEST_F(AmsServiceEventDriveModuleTest, AmsServiceEventDrive_001, TestSize.Level2) +{ + APP_LOGI("AmsServiceEventDrive_001 start"); + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + int32_t recordId = 0; + int32_t waitCount = 2 * CYCLE_NUMBER; + innerService->SetWaitNum(waitCount); + for (uint32_t i = 0; i < CYCLE_NUMBER; i++) { + appMgrService_->ApplicationBackgrounded(recordId); + appMgrService_->ApplicationForegrounded(recordId); + } + innerService->Wait(); + EXPECT_EQ(AmsInnerState::STATE_APPLICATION_BACK_TO_FORE, innerService->GetInnerServiceState()); + APP_LOGI("AmsServiceEventDrive_001 end"); +} + +/* + * Feature: AppMgrService + * Function: EventDrive + * SubFunction: NA + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: NA + * CaseDescription: Verify if post application from foreground to background. + */ +HWTEST_F(AmsServiceEventDriveModuleTest, AmsServiceEventDrive_002, TestSize.Level2) +{ + APP_LOGI("AmsServiceEventDrive_002 start"); + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + int32_t recordId = 0; + int32_t waitCount = 2 * CYCLE_NUMBER; + innerService->SetWaitNum(waitCount); + for (uint32_t i = 0; i < CYCLE_NUMBER; i++) { + appMgrService_->ApplicationForegrounded(recordId); + appMgrService_->ApplicationBackgrounded(recordId); + } + innerService->Wait(); + EXPECT_EQ(AmsInnerState::STATE_APPLICATION_FORE_TO_BACK, innerService->GetInnerServiceState()); + APP_LOGI("AmsServiceEventDrive_002 end"); +} + +/* + * Feature: AppMgrService + * Function: EventDrive + * SubFunction: NA + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: NA + * CaseDescription: Verify if post application from background to terminate. + */ +HWTEST_F(AmsServiceEventDriveModuleTest, AmsServiceEventDrive_003, TestSize.Level1) +{ + APP_LOGI("AmsServiceEventDrive_003 start"); + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + int32_t recordId = 0; + int32_t waitCount = 2 * CYCLE_NUMBER; + innerService->SetWaitNum(waitCount); + for (uint32_t i = 0; i < CYCLE_NUMBER; i++) { + appMgrService_->ApplicationBackgrounded(recordId); + appMgrService_->ApplicationTerminated(recordId); + } + innerService->Wait(); + EXPECT_EQ(AmsInnerState::STATE_APPLICATION_BACK_TO_TER, innerService->GetInnerServiceState()); + APP_LOGI("AmsServiceEventDrive_003 end"); +} + +/* + * Feature: AppMgrService + * Function: EventDrive + * SubFunction: NA + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: NA + * CaseDescription: Verify if post application from foreground to terminated. + */ +HWTEST_F(AmsServiceEventDriveModuleTest, AmsServiceEventDrive_004, TestSize.Level2) +{ + APP_LOGI("AmsServiceEventDrive_004 start"); + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + int32_t recordId = 0; + int32_t waitCount = 2 * CYCLE_NUMBER; + innerService->SetWaitNum(waitCount); + for (uint32_t i = 0; i < CYCLE_NUMBER; i++) { + appMgrService_->ApplicationForegrounded(recordId); + appMgrService_->ApplicationTerminated(recordId); + } + innerService->Wait(); + EXPECT_EQ(AmsInnerState::STATE_APPLICATION_FORE_TO_TER, innerService->GetInnerServiceState()); + APP_LOGI("AmsServiceEventDrive_004 end"); +} + +/* + * Feature: AppMgrService + * Function: EventDrive + * SubFunction: NA + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: NA + * CaseDescription: Verify if post application from terminate to foreground. + */ +HWTEST_F(AmsServiceEventDriveModuleTest, AmsServiceEventDrive_005, TestSize.Level1) +{ + APP_LOGI("AmsServiceEventDrive_005 start"); + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + int32_t recordId = 0; + int32_t waitCount = 2 * CYCLE_NUMBER; + innerService->SetWaitNum(waitCount); + for (uint32_t i = 0; i < CYCLE_NUMBER; i++) { + appMgrService_->ApplicationTerminated(recordId); + appMgrService_->ApplicationForegrounded(recordId); + } + innerService->Wait(); + EXPECT_EQ(AmsInnerState::STATE_APPLICATION_TER_TO_FORE, innerService->GetInnerServiceState()); + APP_LOGI("AmsServiceEventDrive_005 end"); +} + +/* + * Feature: AppMgrService + * Function: EventDrive + * SubFunction: NA + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: NA + * CaseDescription: Verify if post application from terminate to background. + */ +HWTEST_F(AmsServiceEventDriveModuleTest, AmsServiceEventDrive_006, TestSize.Level2) +{ + APP_LOGI("AmsServiceEventDrive_006 start"); + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + int32_t recordId = 0; + int32_t waitCount = 2 * CYCLE_NUMBER; + innerService->SetWaitNum(waitCount); + for (uint32_t i = 0; i < CYCLE_NUMBER; i++) { + appMgrService_->ApplicationTerminated(recordId); + appMgrService_->ApplicationBackgrounded(recordId); + } + innerService->Wait(); + EXPECT_EQ(AmsInnerState::STATE_APPLICATION_TER_TO_BACK, innerService->GetInnerServiceState()); + APP_LOGI("AmsServiceEventDrive_006 end"); +} + +/* + * Feature: AppMgrService + * Function: EventDrive + * SubFunction: NA + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: NA + * CaseDescription: Verify if post application among terminate, background and foreground. + */ +HWTEST_F(AmsServiceEventDriveModuleTest, AmsServiceEventDrive_007, TestSize.Level1) +{ + APP_LOGI("AmsServiceEventDrive_007 start"); + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + int32_t recordId = 0; + int32_t waitCount = 3 * CYCLE_NUMBER; + innerService->SetWaitNum(waitCount); + for (uint32_t i = 0; i < CYCLE_NUMBER; i++) { + appMgrService_->ApplicationTerminated(recordId); + appMgrService_->ApplicationBackgrounded(recordId); + appMgrService_->ApplicationForegrounded(recordId); + } + innerService->Wait(); + EXPECT_EQ(AmsInnerState::STATE_APPLICATION_BACK_TO_FORE, innerService->GetInnerServiceState()); + APP_LOGI("AmsServiceEventDrive_007 end"); +} + +/* + * Feature: AppMgrService + * Function: EventDrive + * SubFunction: NA + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: NA + * CaseDescription: Verify if post application among terminate, background and foreground. + */ +HWTEST_F(AmsServiceEventDriveModuleTest, AmsServiceEventDrive_008, TestSize.Level1) +{ + APP_LOGI("AmsServiceEventDrive_008 start"); + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + int32_t recordId = 0; + int32_t waitCount = 3 * CYCLE_NUMBER; + innerService->SetWaitNum(waitCount); + for (uint32_t i = 0; i < CYCLE_NUMBER; i++) { + appMgrService_->ApplicationTerminated(recordId); + appMgrService_->ApplicationForegrounded(recordId); + appMgrService_->ApplicationBackgrounded(recordId); + } + innerService->Wait(); + EXPECT_EQ(AmsInnerState::STATE_APPLICATION_FORE_TO_BACK, innerService->GetInnerServiceState()); + APP_LOGI("AmsServiceEventDrive_008 end"); +} + +/* + * Feature: AppMgrService + * Function: EventDrive + * SubFunction: NA + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: NA + * CaseDescription: Verify if post application among terminate, background and foreground. + */ +HWTEST_F(AmsServiceEventDriveModuleTest, AmsServiceEventDrive_009, TestSize.Level1) +{ + APP_LOGI("AmsServiceEventDrive_009 start"); + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + int32_t recordId = 0; + int32_t waitCount = 3 * CYCLE_NUMBER; + innerService->SetWaitNum(waitCount); + for (uint32_t i = 0; i < CYCLE_NUMBER; i++) { + appMgrService_->ApplicationForegrounded(recordId); + appMgrService_->ApplicationTerminated(recordId); + appMgrService_->ApplicationBackgrounded(recordId); + } + innerService->Wait(); + EXPECT_EQ(AmsInnerState::STATE_APPLICATION_TER_TO_BACK, innerService->GetInnerServiceState()); + APP_LOGI("AmsServiceEventDrive_009 end"); +} + +/* + * Feature: AppMgrService + * Function: EventDrive + * SubFunction: NA + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: NA + * CaseDescription: Verify if post application among terminate, background and foreground. + */ +HWTEST_F(AmsServiceEventDriveModuleTest, AmsServiceEventDrive_010, TestSize.Level1) +{ + APP_LOGI("AmsServiceEventDrive_010 start"); + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + int32_t recordId = 0; + int32_t waitCount = 3 * CYCLE_NUMBER; + innerService->SetWaitNum(waitCount); + for (uint32_t i = 0; i < CYCLE_NUMBER; i++) { + appMgrService_->ApplicationForegrounded(recordId); + appMgrService_->ApplicationBackgrounded(recordId); + appMgrService_->ApplicationTerminated(recordId); + } + innerService->Wait(); + EXPECT_EQ(AmsInnerState::STATE_APPLICATION_BACK_TO_TER, innerService->GetInnerServiceState()); + APP_LOGI("AmsServiceEventDrive_010 end"); +} + +/* + * Feature: AppMgrService + * Function: EventDrive + * SubFunction: NA + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: NA + * CaseDescription: Verify if post application among terminate, background and foreground. + */ +HWTEST_F(AmsServiceEventDriveModuleTest, AmsServiceEventDrive_011, TestSize.Level1) +{ + APP_LOGI("AmsServiceEventDrive_011 start"); + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + int32_t recordId = 0; + int32_t waitCount = 3 * CYCLE_NUMBER; + innerService->SetWaitNum(waitCount); + for (uint32_t i = 0; i < CYCLE_NUMBER; i++) { + appMgrService_->ApplicationBackgrounded(recordId); + appMgrService_->ApplicationForegrounded(recordId); + appMgrService_->ApplicationTerminated(recordId); + } + innerService->Wait(); + EXPECT_EQ(AmsInnerState::STATE_APPLICATION_FORE_TO_TER, innerService->GetInnerServiceState()); + APP_LOGI("AmsServiceEventDrive_011 end"); +} + +/* + * Feature: AppMgrService + * Function: EventDrive + * SubFunction: NA + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: NA + * CaseDescription: Verify if post application among terminate, background and foreground. + */ +HWTEST_F(AmsServiceEventDriveModuleTest, AmsServiceEventDrive_012, TestSize.Level1) +{ + APP_LOGI("AmsServiceEventDrive_012 start"); + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + int32_t recordId = 0; + int32_t waitCount = 3 * CYCLE_NUMBER; + innerService->SetWaitNum(waitCount); + for (uint32_t i = 0; i < CYCLE_NUMBER; i++) { + appMgrService_->ApplicationBackgrounded(recordId); + appMgrService_->ApplicationTerminated(recordId); + appMgrService_->ApplicationForegrounded(recordId); + } + innerService->Wait(); + EXPECT_EQ(AmsInnerState::STATE_APPLICATION_TER_TO_FORE, innerService->GetInnerServiceState()); + APP_LOGI("AmsServiceEventDrive_012 end"); +} + +/* + * Feature: AppMgrService + * Function: EventDrive + * SubFunction: NA + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: NA + * CaseDescription: Verify if post application from terminate to terminate. + */ +HWTEST_F(AmsServiceEventDriveModuleTest, AmsServiceEventDrive_013, TestSize.Level1) +{ + APP_LOGI("AmsServiceEventDrive_013 start"); + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + int32_t recordId = 0; + int32_t waitCount = 2 * CYCLE_NUMBER; + innerService->SetWaitNum(waitCount); + for (uint32_t i = 0; i < CYCLE_NUMBER; i++) { + appMgrService_->ApplicationTerminated(recordId); + appMgrService_->ApplicationTerminated(recordId); + } + innerService->Wait(); + EXPECT_EQ(AmsInnerState::STATE_APPLICATION_TERMINATED, innerService->GetInnerServiceState()); + APP_LOGI("AmsServiceEventDrive_013 end"); +} + +/* + * Feature: AppMgrService + * Function: EventDrive + * SubFunction: NA + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: NA + * CaseDescription: Verify if post application from backgrounded to backgrounded. + */ +HWTEST_F(AmsServiceEventDriveModuleTest, AmsServiceEventDrive_014, TestSize.Level1) +{ + APP_LOGI("AmsServiceEventDrive_014 start"); + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + int32_t recordId = 0; + int32_t waitCount = 2 * CYCLE_NUMBER; + innerService->SetWaitNum(waitCount); + for (uint32_t i = 0; i < CYCLE_NUMBER; i++) { + appMgrService_->ApplicationBackgrounded(recordId); + appMgrService_->ApplicationBackgrounded(recordId); + } + innerService->Wait(); + EXPECT_EQ(AmsInnerState::STATE_APPLICATION_BACKGROUNDED, innerService->GetInnerServiceState()); + APP_LOGI("AmsServiceEventDrive_014 end"); +} + +/* + * Feature: AppMgrService + * Function: EventDrive + * SubFunction: NA + * FunctionPoints: AppMgrService event drive program model + * EnvConditions: NA + * CaseDescription: Verify if post application from terminate to terminate. + */ +HWTEST_F(AmsServiceEventDriveModuleTest, AmsServiceEventDrive_015, TestSize.Level1) +{ + APP_LOGI("AmsServiceEventDrive_015 start"); + std::shared_ptr innerService = std::make_shared(); + appMgrService_->SetInnerService(innerService); + appMgrService_->OnStart(); + int32_t recordId = 0; + int32_t waitCount = 2 * CYCLE_NUMBER; + innerService->SetWaitNum(waitCount); + for (uint32_t i = 0; i < CYCLE_NUMBER; i++) { + appMgrService_->ApplicationForegrounded(recordId); + appMgrService_->ApplicationForegrounded(recordId); + } + innerService->Wait(); + EXPECT_EQ(AmsInnerState::STATE_APPLICATION_FOREGROUNDED, innerService->GetInnerServiceState()); + APP_LOGI("AmsServiceEventDrive_015 end"); +} \ No newline at end of file diff --git a/services/test/moduletest/common/ams/service_start_process_test/BUILD.gn b/services/test/moduletest/common/ams/service_start_process_test/BUILD.gn new file mode 100755 index 000000000..44425783f --- /dev/null +++ b/services/test/moduletest/common/ams/service_start_process_test/BUILD.gn @@ -0,0 +1,35 @@ +# 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/mstappmgrservice" + +ohos_moduletest("AmsServiceStartModuleTest") { + module_out_path = module_output_path + + include_dirs = + [ "//base/hiviewdfx/hilog/interfaces/native/innerkits/include" ] + sources = [ "ams_service_start_process_module_test.cpp" ] + + deps = [ "${services_path}/test/moduletest/common/ams:appmgr_mst_source" ] + + external_deps = [ "ipc:ipc_core" ] +} + +group("moduletest") { + testonly = true + + deps = [ ":AmsServiceStartModuleTest" ] +} 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 new file mode 100644 index 000000000..eee1fba58 --- /dev/null +++ b/services/test/moduletest/common/ams/service_start_process_test/ams_service_start_process_module_test.cpp @@ -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. + */ + +// redefine private and protected since testcase need to invoke and test private function +#define private public +#define protected public +#include "app_mgr_service.h" +#undef private +#undef protected +#include +#include "app_log_wrapper.h" + +using namespace testing::ext; +using namespace OHOS::AppExecFwk; + +namespace { + +const int CYCLE_NUMBER = 10000; + +} // namespace + +class AppMgrServiceInnerMock : public AppMgrServiceInner { +public: + int32_t OpenAppSpawnConnection() override + { + return 0; + } +}; + +class AmsServiceStartModuleTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); +}; + +void AmsServiceStartModuleTest::SetUpTestCase() +{} + +void AmsServiceStartModuleTest::TearDownTestCase() +{} + +void AmsServiceStartModuleTest::SetUp() +{} + +void AmsServiceStartModuleTest::TearDown() +{} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: NA + * FunctionPoints: AppMgrService startup + * EnvConditions: NA + * CaseDescription: Verify if AppMgrService startup 10000 times. + */ +HWTEST_F(AmsServiceStartModuleTest, AmsStartupMoretimes_001, TestSize.Level1) +{ + APP_LOGI("AmsStartupMoretimes_001 start"); + std::shared_ptr appMgrService = std::make_shared(); + ASSERT_TRUE(appMgrService.get() != nullptr); + std::shared_ptr innerService = std::make_shared(); + appMgrService->SetInnerService(innerService); + EXPECT_EQ(ServiceRunningState::STATE_NOT_START, appMgrService->QueryServiceState().serviceRunningState); + + for (int i = 0; i < CYCLE_NUMBER; i++) { + appMgrService->OnStart(); + EXPECT_EQ(ServiceRunningState::STATE_RUNNING, appMgrService->QueryServiceState().serviceRunningState); + } + + appMgrService->OnStop(); + EXPECT_EQ(ServiceRunningState::STATE_NOT_START, appMgrService->QueryServiceState().serviceRunningState); + APP_LOGI("AmsStartupMoretimes_001 end"); +} + +/* + * Feature: AppMgrService + * Function: Service + * SubFunction: NA + * FunctionPoints: AppMgrService startup + * EnvConditions: NA + * CaseDescription: Verify if AppMgrService stop 10000 times. + */ +HWTEST_F(AmsServiceStartModuleTest, AmsStartupMoretimes_002, TestSize.Level1) +{ + APP_LOGI("AmsStartupMoretimes_002 start"); + std::shared_ptr appMgrService = std::make_shared(); + ASSERT_TRUE(appMgrService.get() != nullptr); + std::shared_ptr innerService = std::make_shared(); + appMgrService->SetInnerService(innerService); + EXPECT_EQ(ServiceRunningState::STATE_NOT_START, appMgrService->QueryServiceState().serviceRunningState); + + for (int i = 0; i < CYCLE_NUMBER; i++) { + appMgrService->OnStop(); + EXPECT_EQ(ServiceRunningState::STATE_NOT_START, appMgrService->QueryServiceState().serviceRunningState); + } + + appMgrService->OnStart(); + EXPECT_EQ(ServiceRunningState::STATE_RUNNING, appMgrService->QueryServiceState().serviceRunningState); + APP_LOGI("AmsStartupMoretimes_002 end"); +} diff --git a/services/test/moduletest/common/bms/BUILD.gn b/services/test/moduletest/common/bms/BUILD.gn new file mode 100755 index 000000000..8232e2b1e --- /dev/null +++ b/services/test/moduletest/common/bms/BUILD.gn @@ -0,0 +1,44 @@ +# 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("bms_module_test_config") { + cflags_cc = [ "-fexceptions" ] + + include_dirs = [ + "mock/include", + "//foundation/aafwk/standard/interfaces/innerkits/want/include/ohos/aafwk/content/", + "//foundation/aafwk/standard/interfaces/innerkits/base/include", + "//foundation/aafwk/standard/interfaces/innerkits/ability_manager/include", + "//foundation/distributedschedule/dmsfwk/services/dtbschedmgr/include", + "//foundation/aafwk/standard/services/abilitymgr/include", + "//foundation/aafwk/standard/services/common/include", + ] + + configs = [ + "${services_path}/test:services_module_test_config", + "${services_path}/bundlemgr:bundlemgr_config", + ] +} + +group("moduletest") { + testonly = true + + deps = [ + "bundle_installer_test:moduletest", + "bundle_parser_test:moduletest", + "bundle_uninstall_test:moduletest", + "service_start_process_test:moduletest", + ] +} diff --git a/services/test/moduletest/common/bms/bundle_installer_test/BUILD.gn b/services/test/moduletest/common/bms/bundle_installer_test/BUILD.gn new file mode 100755 index 000000000..1650677fb --- /dev/null +++ b/services/test/moduletest/common/bms/bundle_installer_test/BUILD.gn @@ -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. + +import("//build/test.gni") +import("//foundation/appexecfwk/standard/appexecfwk.gni") +import( + "//foundation/appexecfwk/standard/services/bundlemgr/appexecfwk_bundlemgr.gni") + +module_output_path = "appexecfwk_standard/mstbundlemgrservice" + +ohos_moduletest("BmsBundleInstallerModuleTest") { + module_out_path = module_output_path + + configs = [ + "${services_path}/test/moduletest/common/bms:bms_module_test_config", + "${libs_path}/libeventhandler:libeventhandler_config", + "${services_path}/bundlemgr:bundlemgr_common_config", + "${appexecfwk_path}/common:appexecfwk_common_config", + ] + + include_dirs = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core/include/bundlemgr", + "//foundation/aafwk/standard/interfaces/innerkits/want/include", + "//third_party/json/include", + "${services_path}/test/mock/include", + "//foundation/appexecfwk/standard/event/cesfwk/kits/native/include", + ] + + sources = [ + "${services_path}/bundlemgr/src/bundle_data_mgr.cpp", + "${services_path}/bundlemgr/src/bundle_data_storage.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/installd/installd_host_impl.cpp", + "${services_path}/bundlemgr/src/installd/installd_operator.cpp", + "${services_path}/bundlemgr/src/installd/installd_service.cpp", + ] + + sources += bundle_install_sources + + sources += [ + "${services_path}/test/mock/src/mock_status_receiver.cpp", + "${services_path}/test/mock/src/system_ability_helper.cpp", + ] + + sources += [ "bms_bundle_installer_module_test.cpp" ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${libs_path}/libeventhandler:libeventhandler_target", + "${services_path}/bundlemgr:bundle_parser", + "${services_path}/bundlemgr:parser_common", + "${services_path}/test/moduletest/utils:tool_common", + "//base/notification/ces_standard/cesfwk/kits/native:cesfwk_kits", + "//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/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + ] + + deps += bundle_install_deps + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("moduletest") { + testonly = true + + deps = [ ":BmsBundleInstallerModuleTest" ] +} 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 new file mode 100644 index 000000000..eeb925949 --- /dev/null +++ b/services/test/moduletest/common/bms/bundle_installer_test/bms_bundle_installer_module_test.cpp @@ -0,0 +1,1274 @@ +/* + * 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 "appexecfwk_errors.h" +#include "bundle_constants.h" +#include "bundle_data_mgr.h" +#include "bundle_data_storage.h" +#include "bundle_mgr_service.h" +#include "bundle_profile.h" +#include "common_tool.h" +#include "directory_ex.h" +#include "inner_bundle_info.h" +#include "installd/installd_service.h" +#include "installd_client.h" +#include "mock_status_receiver.h" + +using namespace testing::ext; +using namespace OHOS::AppExecFwk; +using namespace std::chrono_literals; +using namespace OHOS; +using OHOS::DelayedSingleton; +using OHOS::AAFwk::Want; + +namespace { +const std::string BUNDLE_TMPPATH = "/data/test/bms_bundle/"; +const std::string THIRD_BUNDLE_NAME = "com.third.hiworld.example"; +const std::string SYSTEM_BUNDLE_NAME = "com.system.hiworld.example"; +const std::string BUNDLE_CODE_PATH = "/data/accounts/account_0/applications/"; +const std::string BUNDLE_DATA_PATH = "/data/accounts/account_0/appdata/"; +const std::string ROOT_DIR = "/data/accounts"; +const std::string ERROR_SUFFIX = ".rpk"; +const int32_t ROOT_UID = 0; +} // namespace + +class BmsBundleInstallerModuleTest : public testing::Test { +public: + BmsBundleInstallerModuleTest(); + ~BmsBundleInstallerModuleTest(); + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + + void StartBundleMgrService() + { + if (!bms_) { + bms_ = DelayedSingleton::GetInstance(); + } + if (bms_) { + bms_->OnStart(); + } + } + + void StopBundleMgrService() + { + if (bms_) { + bms_->OnStop(); + bms_ = nullptr; + } + } + + void StartInstalld() + { + installdService_->Start(); + } + + void StopInstalld() + { + installdService_->Stop(); + InstalldClient::GetInstance()->ResetInstalldProxy(); + } + + std::shared_ptr GetBundleDataMgr() + { + return bms_->GetDataMgr(); + } + + bool GetServiceStatus() + { + return bms_->IsServiceReady(); + } + + void CheckBundleSaved(const InnerBundleInfo &innerBundleInfo) const; + void CheckBundleDeleted(const InnerBundleInfo &innerBundleInfo) const; + static void ClearJsonFile(); + void CheckFileExist(const std::string &bundleName) const; + void CheckFileExist(const std::string &bundleName, const std::string &modulePackage) const; + void CheckFileExist(const std::string &bundleName, const std::string &modulePackage, + const std::vector &abilityNames) const; + void CheckFileNonExist(const std::string &bundleName) const; + +protected: + nlohmann::json innerBundleInfoJson_ = R"( + { + "appFeature": "ohos_system_app", + "appType": 0, + "baseAbilityInfos": { + "com.system.hiworld.examples1com.system.hiworld.example.h2bmsSystemBundle_A1": { + "applicationName": "com.system.hiworld.examples1", + "bundleName": "com.system.hiworld.examples1", + "codePath": "", + "description": "", + "deviceCapabilities": [], + "deviceId": "", + "deviceTypes": [ + "tv", + "car" + ], + "iconPath": "$media:snowball", + "isLauncherAbility": false, + "isNativeAbility": true, + "kind": "page", + "label": "bmsSystemBundle_A1 Ability", + "launchMode": 0, + "libPath": "", + "moduleName": "bmsSystemBundle1", + "name": "bmsSystemBundle_A1", + "orientation": 0, + "package": "com.system.hiworld.example.h2", + "permissions": [], + "process": "", + "resourcePath": "", + "type": 1, + "uri": "", + "visible": true + } + }, + "baseApplicationInfo": { + "bundleName": "com.system.hiworld.examples1", + "cacheDir": "/data/accounts/account_0/appdata/com.system.hiworld.examples1/cache", + "codePath": "/data/accounts/account_0/applications/com.system.hiworld.examples1", + "dataBaseDir": "/data/accounts/account_0/appdata/com.system.hiworld.examples1/database", + "dataDir": "/data/accounts/account_0/appdata/com.system.hiworld.examples1/files", + "description": "", + "descriptionId": 0, + "deviceId": "PHONE-001", + "entryDir": "", + "iconId": 0, + "iconPath": "", + "isLauncherApp": false, + "isSystemApp": true, + "label": "", + "labelId": 0, + "moduleInfos": [], + "moduleSourceDirs": [], + "name": "com.system.hiworld.examples1", + "permissions": [], + "process": "", + "signatureKey": "", + "supportedModes": 0 + }, + "baseBundleInfo": { + "abilityInfos": [], + "appId": "", + "applicationInfo": { + "bundleName": "", + "cacheDir": "", + "codePath": "", + "dataBaseDir": "", + "dataDir": "", + "description": "", + "descriptionId": 0, + "deviceId": "", + "entryDir": "", + "iconId": 0, + "iconPath": "", + "isLauncherApp": false, + "isSystemApp": false, + "label": "", + "labelId": 0, + "moduleInfos": [], + "moduleSourceDirs": [], + "name": "", + "permissions": [], + "process": "", + "signatureKey": "", + "supportedModes": 0 + }, + "compatibleVersion": 3, + "cpuAbi": "", + "defPermissions": [], + "description": "", + "entryModuleName": "", + "gid": 2101, + "hapModuleNames": [], + "installTime": 105590, + "isKeepAlive": false, + "isNativeApp": true, + "jointUserId": "", + "label": "bmsSystemBundle_A1 Ability", + "mainEntry": "", + "maxSdkVersion": 0, + "minSdkVersion": 0, + "moduleDirs": [], + "moduleNames": [], + "modulePublicDirs": [], + "moduleResPaths": [], + "name": "com.system.hiworld.examples1", + "releaseType": "Release", + "reqPermissions": [], + "seInfo": "", + "targetVersion": 3, + "uid": 2101, + "updateTime": 105590, + "vendor": "example", + "versionCode": 1, + "versionName": "1.0" + }, + "baseDataDir": "/data/accounts/account_0/appdata/com.system.hiworld.examples1", + "bundleStatus": 1, + "gid": 2101, + "hasEntry": true, + "innerModuleInfos": { + "com.system.hiworld.example.h2": { + "abilityKeys": [ + "com.system.hiworld.examples1com.system.hiworld.example.h2bmsSystemBundle_A1" + ], + "defPermissions": [], + "description": "", + "distro": { + "deliveryWithInstall": true, + "moduleName": "testability", + "moduleType": "entry" + }, + "isEntry": true, + "metaData": { + "customizeData": [], + "parameters": [], + "results": [] + }, + "moduleDataDir": "/data/accounts/account_0/appdata/com.system.hiworld.examples1/com.system.hiworld.example.h2", + "moduleName": "bmsSystemBundle1", + "modulePackage": "com.system.hiworld.example.h2", + "modulePath": "/data/accounts/account_0/applications/com.system.hiworld.examples1/com.system.hiworld.example.h2", + "moduleResPath": "", + "reqCapabilities": [], + "reqPermissions": [], + "skillKeys": [ + "com.system.hiworld.examples1com.system.hiworld.example.h2bmsSystemBundle_A1" + ] + } + }, + "isKeepData": false, + "isSupportBackup": false, + "mainAbility": "", + "provisionId": "BNtg4JBClbl92Rgc3jm/RfcAdrHXaM8F0QOiwVEhnV5ebE5jNIYnAx+weFRT3QTyUjRNdhmc2aAzWyi+5t5CoBM=", + "skillInfos": { + "com.system.hiworld.examples1com.system.hiworld.example.h2bmsSystemBundle_A1": [] + }, + "uid": 2101, + "userId_": 0 + } + )"_json; + nlohmann::json bundleInfoJson_ = R"( + { + "abilityInfos": [], + "appId": "", + "applicationInfo": { + "bundleName": "", + "cacheDir": "", + "codePath": "", + "dataBaseDir": "", + "dataDir": "", + "description": "", + "descriptionId": 0, + "deviceId": "", + "entryDir": "", + "iconId": 0, + "iconPath": "", + "isLauncherApp": false, + "isSystemApp": false, + "label": "", + "labelId": 0, + "moduleInfos": [], + "moduleSourceDirs": [], + "name": "", + "permissions": [], + "process": "", + "signatureKey": "", + "supportedModes": 0 + }, + "compatibleVersion": 3, + "cpuAbi": "", + "defPermissions": [], + "description": "", + "entryModuleName": "", + "gid": 2101, + "hapModuleNames": [], + "installTime": 105590, + "isKeepAlive": false, + "isNativeApp": true, + "jointUserId": "", + "label": "bmsSystemBundle_A1 Ability", + "mainEntry": "", + "maxSdkVersion": 0, + "minSdkVersion": 0, + "moduleDirs": [], + "moduleNames": [], + "modulePublicDirs": [], + "moduleResPaths": [], + "name": "com.system.hiworld.examples1", + "releaseType": "Release", + "reqPermissions": [], + "seInfo": "", + "targetVersion": 3, + "uid": 2101, + "updateTime": 105590, + "vendor": "example", + "versionCode": 1, + "versionName": "1.0" + } + )"_json; + std::string deviceId_{}; + +private: + std::shared_ptr installdService_ = std::make_unique(); + std::shared_ptr bms_ = DelayedSingleton::GetInstance(); +}; + +BmsBundleInstallerModuleTest::BmsBundleInstallerModuleTest() +{ + deviceId_ = Constants::CURRENT_DEVICE_ID; + innerBundleInfoJson_["baseBundleInfo"] = bundleInfoJson_; +} + +BmsBundleInstallerModuleTest::~BmsBundleInstallerModuleTest() +{ + bms_.reset(); +} + +void BmsBundleInstallerModuleTest::CheckBundleSaved(const InnerBundleInfo &innerBundleInfo) const +{ + BundleDataStorage bundleDataStorage; + EXPECT_TRUE(bundleDataStorage.SaveStorageBundleInfo(Constants::CURRENT_DEVICE_ID, innerBundleInfo)); + std::map> bundleData; + EXPECT_TRUE(bundleDataStorage.LoadAllData(bundleData)); + std::string bundleName = innerBundleInfo.GetBundleName(); + auto bundleDataIter = bundleData.find(bundleName); + EXPECT_TRUE(bundleDataIter != bundleData.end()); + auto allDeviceInfos = bundleDataIter->second; + auto devicesInfosIter = allDeviceInfos.find(deviceId_); + EXPECT_TRUE(devicesInfosIter != allDeviceInfos.end()); + InnerBundleInfo afterLoadInfo = devicesInfosIter->second; + EXPECT_TRUE(innerBundleInfo.ToString() == afterLoadInfo.ToString()); +} + +void BmsBundleInstallerModuleTest::CheckBundleDeleted(const InnerBundleInfo &innerBundleInfo) const +{ + BundleDataStorage bundleDataStorage; + EXPECT_TRUE(bundleDataStorage.DeleteStorageBundleInfo(Constants::CURRENT_DEVICE_ID, innerBundleInfo)); + std::map> bundleData; + EXPECT_FALSE(bundleDataStorage.LoadAllData(bundleData)); +} + +void BmsBundleInstallerModuleTest::ClearJsonFile() +{ + std::string fileName = Constants::BUNDLE_DATA_BASE_FILE; + std::ofstream o(fileName); + if (!o.is_open()) { + std::cout << "failed to open as out" << fileName << std::endl; + } else { + std::cout << "clear" << fileName << std::endl; + } + o.close(); +} + +void BmsBundleInstallerModuleTest::CheckFileExist(const std::string &bundleName) const +{ + int bundleDataExist = access((BUNDLE_DATA_PATH + bundleName).c_str(), F_OK); + EXPECT_EQ(bundleDataExist, 0) << "the bundle data dir does not exists: " << bundleName; + int codeExist = access((BUNDLE_CODE_PATH + bundleName).c_str(), F_OK); + EXPECT_EQ(codeExist, 0) << "the ability code file does not exist: " << bundleName; +} + +void BmsBundleInstallerModuleTest::CheckFileExist(const std::string &bundleName, const std::string &modulePackage) const +{ + int bundleDataExist = access((BUNDLE_DATA_PATH + bundleName + "/" + modulePackage).c_str(), F_OK); + EXPECT_EQ(bundleDataExist, 0) << "the bundle data dir does not exists: " << modulePackage; + int codeExist = access((BUNDLE_DATA_PATH + bundleName + "/" + modulePackage).c_str(), F_OK); + EXPECT_EQ(codeExist, 0) << "the ability code file does not exist: " << modulePackage; +} + +void BmsBundleInstallerModuleTest::CheckFileNonExist(const std::string &bundleName) const +{ + int bundleDataExist = access((BUNDLE_DATA_PATH + bundleName).c_str(), F_OK); + EXPECT_NE(bundleDataExist, 0) << "the bundle data dir exists: " << bundleName; + int codeExist = access((BUNDLE_CODE_PATH + bundleName).c_str(), F_OK); + EXPECT_NE(codeExist, 0) << "the ability code exists: " << bundleName; +} + +void BmsBundleInstallerModuleTest::CheckFileExist( + const std::string &bundleName, const std::string &modulePackage, const std::vector &abilityNames) const +{ + int bundleDataExist = 1; + int codeExist = 1; + if (abilityNames.size() == 0) { + CheckFileExist(bundleName, modulePackage); + } + for (auto iter = abilityNames.begin(); iter != abilityNames.end(); iter++) { + bundleDataExist = access((BUNDLE_DATA_PATH + bundleName + "/" + modulePackage + "/" + *iter).c_str(), F_OK); + EXPECT_EQ(bundleDataExist, 0) << "the bundle data dir does not exists: " << *iter; + codeExist = access((BUNDLE_DATA_PATH + bundleName + "/" + modulePackage + "/" + *iter).c_str(), F_OK); + EXPECT_EQ(codeExist, 0) << "the ability code file does not exist: " << *iter; + } +} + +void BmsBundleInstallerModuleTest::SetUpTestCase() +{ + if (access(ROOT_DIR.c_str(), F_OK) != 0) { + bool result = OHOS::ForceCreateDirectory(ROOT_DIR); + ASSERT_TRUE(result); + } + if (chown(ROOT_DIR.c_str(), ROOT_UID, ROOT_UID) != 0) { + ASSERT_TRUE(false); + } + if (chmod(ROOT_DIR.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) { + ASSERT_TRUE(false); + } +} + +void BmsBundleInstallerModuleTest::TearDownTestCase() +{} + +void BmsBundleInstallerModuleTest::SetUp() +{ + std::cout << "BmsBundleInstallerModuleTest SetUp Begin" << std::endl; + StartInstalld(); + StartBundleMgrService(); + std::cout << "BmsBundleInstallerModuleTest SetUp End" << std::endl; +} + +void BmsBundleInstallerModuleTest::TearDown() +{ + std::cout << "BmsBundleInstallerModuleTest TearDown Begin" << std::endl; + StopInstalld(); + StopBundleMgrService(); + std::cout << "BmsBundleInstallerModuleTest TearDown End" << std::endl; +} + +/** + * @tc.number: SystemAppInstall_0100 + * @tc.name: test a system bundle can be installed and bundle files exist + * @tc.desc: 1.under '/system/app/',there is a hap + * 2.TriggerScan and check install results + */ +HWTEST_F(BmsBundleInstallerModuleTest, SystemAppInstall_0100, Function | MediumTest | Level1) +{ + std::string bundleName = SYSTEM_BUNDLE_NAME + "s1"; + std::shared_ptr dataMgr = GetBundleDataMgr(); + ASSERT_NE(dataMgr, nullptr); + BundleInfo bundleInfo; + bool ret = false; + int checkCount = 0; + do { + std::this_thread::sleep_for(50ms); + ret = dataMgr->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); + checkCount++; + } while (!ret && (checkCount < 100)); + + CheckFileExist(bundleName); + EXPECT_FALSE((bundleInfo.name).empty()); +} + +/** + * @tc.number: SystemAppInstall_0200 + * @tc.name: test install ten system bundles when the system starts + * @tc.desc: 1.under '/system/app/',there are two haps + * 2.TriggerScan and check install results + */ +HWTEST_F(BmsBundleInstallerModuleTest, SystemAppInstall_0200, Function | MediumTest | Level1) +{ + int bundleNum = 2; + std::shared_ptr dataMgr = GetBundleDataMgr(); + ASSERT_NE(dataMgr, nullptr); + BundleInfo bundleInfo; + + for (int i = 1; i <= bundleNum; i++) { + std::string bundleName = SYSTEM_BUNDLE_NAME + "s" + std::to_string(i); + + bool ret = false; + int checkCount = 0; + do { + std::this_thread::sleep_for(50ms); + ret = dataMgr->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); + checkCount++; + } while (!ret && (checkCount < 100)); + CheckFileExist(bundleName); + EXPECT_FALSE((bundleInfo.name).empty()); + } +} + +/** + * @tc.number: SystemAppInstall_0300 + * @tc.name: test install abnormal system bundles, and check bundle's informations + * @tc.desc: 1.under '/system/app/',there are three hap bundles, one of them is normal, + * others are abnormal + * 2.TriggerScan and check install results + */ +HWTEST_F(BmsBundleInstallerModuleTest, SystemAppInstall_0300, Function | MediumTest | Level2) +{ + std::string norBundleName = SYSTEM_BUNDLE_NAME + "s2"; + std::shared_ptr dataMgr = GetBundleDataMgr(); + ASSERT_NE(dataMgr, nullptr); + BundleInfo bundleInfo; + bool ret = false; + int checkCount = 0; + do { + std::this_thread::sleep_for(50ms); + ret = dataMgr->GetBundleInfo(norBundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); + checkCount++; + } while (!ret && (checkCount < 100)); + CheckFileExist(norBundleName); + EXPECT_FALSE((bundleInfo.name).empty()); + + int bundleNum = 5; + for (int i = 3; i < bundleNum; i++) { + std::string invalidBundleName = SYSTEM_BUNDLE_NAME + "s" + std::to_string(i); + CheckFileNonExist(invalidBundleName); + BundleInfo invalidBundleInfo; + dataMgr->GetBundleInfo(invalidBundleName, BundleFlag::GET_BUNDLE_DEFAULT, invalidBundleInfo); + EXPECT_TRUE((invalidBundleInfo.name).empty()); + } +} + +/** + * @tc.number: SystemAppInstall_0400 + * @tc.name: test install an abnormal system bundle, and check bundle's informations + * @tc.desc: 1.under '/system/app/',there is a hap, the config.json file of which + * does not contain bundle name + * 2.TriggerScan and check install result + */ +HWTEST_F(BmsBundleInstallerModuleTest, SystemAppInstall_0400, Function | MediumTest | Level2) +{ + std::string bundleName = SYSTEM_BUNDLE_NAME + "s3"; + CheckFileNonExist(bundleName); + std::shared_ptr dataMgr = GetBundleDataMgr(); + ASSERT_NE(dataMgr, nullptr); + BundleInfo bundleInfo; + bool ret = false; + int checkCount = 0; + do { + std::this_thread::sleep_for(1ms); + ret = dataMgr->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); + checkCount++; + } while (!ret && (checkCount < 100)); + + EXPECT_TRUE((bundleInfo.name).empty()); +} + +/** + * @tc.number: SystemAppInstall_0500 + * @tc.name: test install an abnormal system bundle, and check bundle's informations + * @tc.desc: 1.under '/system/app/',there is a hap, which doesn't have the config.json + * 2.TriggerScan and check install result + */ +HWTEST_F(BmsBundleInstallerModuleTest, SystemAppInstall_0500, Function | MediumTest | Level2) +{ + std::string bundleName = SYSTEM_BUNDLE_NAME + "s4"; + CheckFileNonExist(bundleName); + std::shared_ptr dataMgr = GetBundleDataMgr(); + ASSERT_NE(dataMgr, nullptr); + BundleInfo bundleInfo; + bool ret = false; + int checkCount = 0; + do { + std::this_thread::sleep_for(1ms); + ret = dataMgr->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); + checkCount++; + } while (!ret && (checkCount < 100)); + + EXPECT_TRUE((bundleInfo.name).empty()); +} + +/** + * @tc.number: ThirdAppInstall_0100 + * @tc.name: test third-party bundle install + * @tc.desc: 1.under '/data/test/bms_bundle/',there is a hap + * 2.install the bundle and check results + */ +HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0100, Function | MediumTest | Level1) +{ + auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); + ASSERT_NE(installer, nullptr); + OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); + ASSERT_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; + std::string bundleName = THIRD_BUNDLE_NAME + "1"; + CheckFileExist(bundleName); + OHOS::sptr recUninstall = new (std::nothrow) MockStatusReceiver(); + ASSERT_NE(recUninstall, nullptr); + installParam.userId = Constants::DEFAULT_USERID; + installer->Uninstall(bundleName, installParam, recUninstall); + EXPECT_EQ(recUninstall->GetResultCode(), ERR_OK) << "uninstall fail!" << bundleName; +} + +/** + * @tc.number: ThirdAppInstall_0200 + * @tc.name: test third-party bundle install and bundle info store + * @tc.desc: 1.under '/data/test/bms_bundle/',there is a hap + * 2.check install results + * 3.restart bundmgrservice + */ +HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0200, Function | MediumTest | Level1) +{ + auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); + ASSERT_NE(installer, nullptr); + OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); + ASSERT_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); + std::string bundleName = THIRD_BUNDLE_NAME + "1"; + CheckFileExist(bundleName); + + StopBundleMgrService(); + StartBundleMgrService(); + CheckFileExist(bundleName); + std::shared_ptr dataMgr = GetBundleDataMgr(); + ASSERT_NE(dataMgr, nullptr); + BundleInfo bundleInfo; + bool ret = false; + ret = dataMgr->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo); + EXPECT_TRUE(ret); + EXPECT_EQ(bundleInfo.name, bundleName); + + installParam.userId = Constants::DEFAULT_USERID; + OHOS::sptr recUninstall = new (std::nothrow) MockStatusReceiver(); + ASSERT_NE(recUninstall, nullptr); + installer->Uninstall(bundleName, installParam, recUninstall); + EXPECT_EQ(recUninstall->GetResultCode(), ERR_OK); +} + +/** + * @tc.number: ThirdAppInstall_0300 + * @tc.name: test third-party bundle install and bundle info store + * @tc.desc: 1.under '/data/test/bms_bundle/',there a hap,the suffix + * of which is wrong + * 2.check install results + */ +HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0300, Function | MediumTest | Level2) +{ + auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); + ASSERT_NE(installer, nullptr); + OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); + ASSERT_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); + 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); + bool isBundleExist = dataMgr->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, info); + EXPECT_FALSE(isBundleExist); +} + +/** + * @tc.number: ThirdAppInstall_0400 + * @tc.name: test third bundle install and bundle info store + * @tc.desc: 1.under '/data/test/bms_bundle/',there is a big hap + * 2.install and check install results + */ +HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0400, Function | MediumTest | Level1) +{ + auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); + ASSERT_NE(installer, nullptr); + OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); + ASSERT_NE(receiver, nullptr); + OHOS::sptr receiver2 = new (std::nothrow) MockStatusReceiver(); + ASSERT_NE(receiver2, nullptr); + InstallParam installParam; + installParam.installFlag = InstallFlag::NORMAL; + std::string bundleName = THIRD_BUNDLE_NAME + "5"; + std::string bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle13" + Constants::INSTALL_FILE_SUFFIX; + installer->Install(bundleFilePath, installParam, receiver); + StopInstalld(); + std::this_thread::sleep_for(1ms); + + EXPECT_NE(receiver->GetResultCode(), ERR_OK); + + std::this_thread::sleep_for(5ms); + CheckFileNonExist(bundleName); + + StartInstalld(); + std::this_thread::sleep_for(1ms); + installer->Install(bundleFilePath, installParam, receiver2); + ASSERT_EQ(receiver2->GetResultCode(), ERR_OK); + CheckFileExist(bundleName); + OHOS::sptr recUninstall = new (std::nothrow) MockStatusReceiver(); + ASSERT_NE(recUninstall, nullptr); + installer->Uninstall(bundleName, installParam, recUninstall); + EXPECT_EQ(recUninstall->GetResultCode(), ERR_OK); +} + +/** + * @tc.number: ThirdAppInstall_0500 + * @tc.name: test third-party bundle upgrade + * @tc.desc: 1.one hap has been installed in system + * 2.under '/data/test/bms_bundle',there a hap,the version of which is lower than the installed one + * 3.check install results + */ +HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0500, Function | MediumTest | Level1) +{ + auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); + ASSERT_NE(installer, nullptr); + OHOS::sptr normalInstall = new (std::nothrow) MockStatusReceiver(); + ASSERT_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); + 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); + installParam.installFlag = InstallFlag::REPLACE_EXISTING; + installer->Install(upgradeFilePath, installParam, replaceInstall); + ASSERT_EQ(replaceInstall->GetResultCode(), ERR_APPEXECFWK_INSTALL_VERSION_DOWNGRADE); + CheckFileExist(bundleName); + + OHOS::sptr uninstall = new (std::nothrow) MockStatusReceiver(); + ASSERT_NE(uninstall, nullptr); + installParam.userId = Constants::DEFAULT_USERID; + installer->Uninstall(bundleName, installParam, uninstall); + EXPECT_EQ(uninstall->GetResultCode(), ERR_OK) << "uninstall fail!" << bundleName; +} + +/** + * @tc.number: ThirdAppInstall_0600 + * @tc.name: test third-party bundle upgrade + * @tc.desc: 1.one hap has been installed in system + * 2.under '/data/test/bms_bundle',there a hap,the version of which is higher than the installed one + * 3.check install results + */ +HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0600, Function | MediumTest | Level1) +{ + auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); + ASSERT_NE(installer, nullptr); + OHOS::sptr normalInstall = new (std::nothrow) MockStatusReceiver(); + ASSERT_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); + 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); + installParam.installFlag = InstallFlag::REPLACE_EXISTING; + installer->Install(upgradeFilePath, installParam, replaceInstall); + ASSERT_EQ(replaceInstall->GetResultCode(), ERR_OK); + CheckFileExist(bundleName); + + StopBundleMgrService(); + StartBundleMgrService(); + CheckFileExist(bundleName); + + BundleInfo info; + std::shared_ptr bms = DelayedSingleton::GetInstance(); + auto dataMgr = bms->GetDataMgr(); + ASSERT_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); + installParam.userId = Constants::DEFAULT_USERID; + installer->Uninstall(bundleName, installParam, uninstall); + EXPECT_EQ(uninstall->GetResultCode(), ERR_OK) << "uninstall fail!" << bundleName; +} + +/** + * @tc.number: ThirdAppInstall_0700 + * @tc.name: test third-party bundle upgrade + * @tc.desc: 1.one hap has been installed in system + * 2.under '/data/test/bms_bundle',there a hap,the version of which is equal to the installed one + * 3.check install results + */ +HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0700, Function | MediumTest | Level1) +{ + auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); + ASSERT_NE(installer, nullptr); + OHOS::sptr normalInstall = new (std::nothrow) MockStatusReceiver(); + ASSERT_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); + 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); + installParam.installFlag = InstallFlag::REPLACE_EXISTING; + installer->Install(upgradeFilePath, installParam, replaceInstall); + ASSERT_EQ(replaceInstall->GetResultCode(), ERR_OK); + CheckFileExist(bundleName); + + OHOS::sptr uninstall = new (std::nothrow) MockStatusReceiver(); + ASSERT_NE(uninstall, nullptr); + installParam.userId = Constants::DEFAULT_USERID; + installer->Uninstall(bundleName, installParam, uninstall); + EXPECT_EQ(uninstall->GetResultCode(), ERR_OK) << "uninstall fail!" << bundleName; +} + +/** + * @tc.number: ThirdAppInstall_0800 + * @tc.name: test third-party bundle install + * @tc.desc: 1.under '/data/test/bms_bundle/',there are two haps with one ability,whose appname is equal + * 2.install the app + */ +HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0800, Function | MediumTest | Level1) +{ + auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); + ASSERT_NE(installer, nullptr); + OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); + ASSERT_NE(receiver, nullptr); + OHOS::sptr receiver2 = new (std::nothrow) MockStatusReceiver(); + ASSERT_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; + 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; + std::string modulePackage2 = "com.third.hiworld.example.h2"; + CheckFileExist(bundleName, modulePackage2); + + OHOS::sptr recUninstall = new (std::nothrow) MockStatusReceiver(); + ASSERT_NE(recUninstall, nullptr); + installParam.userId = Constants::DEFAULT_USERID; + installer->Uninstall(bundleName, installParam, recUninstall); + EXPECT_EQ(recUninstall->GetResultCode(), ERR_OK) << "uninstall fail!" << bundleName; +} + +/** + * @tc.number: ThirdAppInstall_0900 + * @tc.name: test third-party bundle install + * @tc.desc: 1.under '/data/test/bms_bundle/',there are two haps without an ability,whose appname is equal + * 2.install the app + */ +HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_0900, Function | MediumTest | Level1) +{ + auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); + ASSERT_NE(installer, nullptr); + OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); + ASSERT_NE(receiver, nullptr); + OHOS::sptr receiver2 = new (std::nothrow) MockStatusReceiver(); + ASSERT_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; + std::string bundleName = THIRD_BUNDLE_NAME + "1"; + std::string modulePackage = "com.third.hiworld.example.h1"; + std::vector hap1AbilityNames = {}; + CheckFileExist(bundleName, modulePackage, hap1AbilityNames); + + bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle6" + Constants::INSTALL_FILE_SUFFIX; + installer->Install(bundleFilePath, installParam, receiver2); + ASSERT_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); + installParam.userId = Constants::DEFAULT_USERID; + installer->Uninstall(bundleName, installParam, recUninstall); + EXPECT_EQ(recUninstall->GetResultCode(), ERR_OK) << "uninstall fail!" << bundleName; +} + +/** + * @tc.number: ThirdAppInstall_1000 + * @tc.name: test third-party bundle upgrade + * @tc.desc: 1.under '/data/test/bms_bundle/',there are two haps,one without an ability,the other with an ability + * 2.install this app + */ +HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1000, Function | MediumTest | Level1) +{ + auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); + ASSERT_NE(installer, nullptr); + OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); + ASSERT_NE(receiver, nullptr); + OHOS::sptr receiver2 = new (std::nothrow) MockStatusReceiver(); + ASSERT_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; + std::string bundleName = THIRD_BUNDLE_NAME + "1"; + std::string modulePackage = "com.third.hiworld.example.h1"; + std::vector hap1AbilityNames = {}; + CheckFileExist(bundleName, modulePackage, hap1AbilityNames); + + bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle4" + Constants::INSTALL_FILE_SUFFIX; + installer->Install(bundleFilePath, installParam, receiver2); + ASSERT_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); + installParam.userId = Constants::DEFAULT_USERID; + installer->Uninstall(bundleName, installParam, recUninstall); + EXPECT_EQ(recUninstall->GetResultCode(), ERR_OK) << "uninstall fail!" << bundleName; +} + +/** + * @tc.number: ThirdAppInstall_1100 + * @tc.name: test third-party bundle upgrade + * @tc.desc: 1.under '/data/test/bms_bundle/',there are two haps, + * one without an ability,the other with two abilities + * 2.install this app + */ +HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1100, Function | MediumTest | Level1) +{ + auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); + ASSERT_NE(installer, nullptr); + OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); + ASSERT_NE(receiver, nullptr); + OHOS::sptr receiver2 = new (std::nothrow) MockStatusReceiver(); + ASSERT_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; + std::string bundleName = THIRD_BUNDLE_NAME + "1"; + std::string modulePackage = "com.third.hiworld.example.h1"; + std::vector hap1AbilityNames = {}; + CheckFileExist(bundleName, modulePackage, hap1AbilityNames); + + bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle5" + Constants::INSTALL_FILE_SUFFIX; + installer->Install(bundleFilePath, installParam, receiver2); + ASSERT_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); + installParam.userId = Constants::DEFAULT_USERID; + installer->Uninstall(bundleName, installParam, recUninstall); + EXPECT_EQ(recUninstall->GetResultCode(), ERR_OK) << "uninstall fail!" << bundleName; +} + +/** + * @tc.number: ThirdAppInstall_1200 + * @tc.name: test third-party bundle upgrade + * @tc.desc: 1.under '/data/test/bms_bundle/',there are two haps,one without an ability,the other with an ability + * 2.install this app + */ +HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1200, Function | MediumTest | Level1) +{ + auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); + ASSERT_NE(installer, nullptr); + OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); + ASSERT_NE(receiver, nullptr); + OHOS::sptr receiver2 = new (std::nothrow) MockStatusReceiver(); + ASSERT_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; + std::string bundleName = THIRD_BUNDLE_NAME + "1"; + std::string modulePackage = "com.third.hiworld.example.h1"; + std::vector hap1AbilityNames = {"bmsThirdBundle_A1"}; + CheckFileExist(bundleName, modulePackage, hap1AbilityNames); + + bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle6" + Constants::INSTALL_FILE_SUFFIX; + installer->Install(bundleFilePath, installParam, receiver2); + ASSERT_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); + installParam.userId = Constants::DEFAULT_USERID; + installer->Uninstall(bundleName, installParam, recUninstall); + EXPECT_EQ(recUninstall->GetResultCode(), ERR_OK) << "uninstall fail!" << bundleName; +} + +/** + * @tc.number: ThirdAppInstall_1300 + * @tc.name: test third-party bundle upgrade + * @tc.desc: 1.under '/data/test/bms_bundle/',there are two haps with an ability, + * 2.install this app + */ +HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1300, Function | MediumTest | Level1) +{ + auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); + ASSERT_NE(installer, nullptr); + OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); + ASSERT_NE(receiver, nullptr); + OHOS::sptr receiver2 = new (std::nothrow) MockStatusReceiver(); + ASSERT_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; + std::string bundleName = THIRD_BUNDLE_NAME + "1"; + std::string modulePackage = "com.third.hiworld.example.h1"; + std::vector hap1AbilityNames = {"bmsThirdBundle_A1"}; + CheckFileExist(bundleName, modulePackage, hap1AbilityNames); + + bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle4" + Constants::INSTALL_FILE_SUFFIX; + installer->Install(bundleFilePath, installParam, receiver2); + ASSERT_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); + installParam.userId = Constants::DEFAULT_USERID; + installer->Uninstall(bundleName, installParam, recUninstall); + EXPECT_EQ(recUninstall->GetResultCode(), ERR_OK) << "uninstall fail!" << bundleName; +} + +/** + * @tc.number: ThirdAppInstall_1400 + * @tc.name: test third-party bundle upgrade + * @tc.desc: 1.under '/data/test/bms_bundle/',there are two haps,one with an ability,the other with two abilities + * 2.install this app + */ +HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1400, Function | MediumTest | Level1) +{ + auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); + ASSERT_NE(installer, nullptr); + OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); + ASSERT_NE(receiver, nullptr); + OHOS::sptr receiver2 = new (std::nothrow) MockStatusReceiver(); + ASSERT_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; + std::string bundleName = THIRD_BUNDLE_NAME + "1"; + std::string modulePackage = "com.third.hiworld.example.h1"; + std::vector hap1AbilityNames = {"bmsThirdBundle_A1"}; + CheckFileExist(bundleName, modulePackage, hap1AbilityNames); + + bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle5" + Constants::INSTALL_FILE_SUFFIX; + installer->Install(bundleFilePath, installParam, receiver2); + ASSERT_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); + installParam.userId = Constants::DEFAULT_USERID; + installer->Uninstall(bundleName, installParam, recUninstall); + EXPECT_EQ(recUninstall->GetResultCode(), ERR_OK) << "uninstall fail!" << bundleName; +} + +/** + * @tc.number: ThirdAppInstall_1500 + * @tc.name: test third-party bundle upgrade + * @tc.desc: 1.under '/data/test/bms_bundle/',there are two haps, + * one without an ability,the other with two abilities + * 2.install this app + */ +HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1500, Function | MediumTest | Level1) +{ + auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); + ASSERT_NE(installer, nullptr); + OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); + ASSERT_NE(receiver, nullptr); + OHOS::sptr receiver2 = new (std::nothrow) MockStatusReceiver(); + ASSERT_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; + std::string bundleName = THIRD_BUNDLE_NAME + "1"; + std::string modulePackage = "com.third.hiworld.example.h1"; + std::vector hap1AbilityNames = {"bmsThirdBundle_A1", "bmsThirdBundle_A2"}; + CheckFileExist(bundleName, modulePackage, hap1AbilityNames); + + bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle6" + Constants::INSTALL_FILE_SUFFIX; + installer->Install(bundleFilePath, installParam, receiver2); + ASSERT_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); + installParam.userId = Constants::DEFAULT_USERID; + installer->Uninstall(bundleName, installParam, recUninstall); + EXPECT_EQ(recUninstall->GetResultCode(), ERR_OK) << "uninstall fail!" << bundleName; +} + +/** + * @tc.number: ThirdAppInstall_1600 + * @tc.name: test third-party bundle upgrade + * @tc.desc: 1.under '/data/test/bms_bundle/',there are two haps,one with an ability,the other with two abilities + * 2.install this app + */ +HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1600, Function | MediumTest | Level1) +{ + auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); + ASSERT_NE(installer, nullptr); + OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); + ASSERT_NE(receiver, nullptr); + OHOS::sptr receiver2 = new (std::nothrow) MockStatusReceiver(); + ASSERT_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; + std::string bundleName = THIRD_BUNDLE_NAME + "1"; + std::string modulePackage = "com.third.hiworld.example.h1"; + std::vector hap1AbilityNames = {"bmsThirdBundle_A1", "bmsThirdBundle_A2"}; + CheckFileExist(bundleName, modulePackage, hap1AbilityNames); + + bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle4" + Constants::INSTALL_FILE_SUFFIX; + installer->Install(bundleFilePath, installParam, receiver2); + ASSERT_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); + installParam.userId = Constants::DEFAULT_USERID; + installer->Uninstall(bundleName, installParam, recUninstall); + EXPECT_EQ(recUninstall->GetResultCode(), ERR_OK) << "uninstall fail!" << bundleName; +} + +/** + * @tc.number: ThirdAppInstall_1700 + * @tc.name: test third-party bundle upgrade + * @tc.desc: 1.under '/data/test/bms_bundle/',there are two haps with two abilities, + * 2.install this app + */ +HWTEST_F(BmsBundleInstallerModuleTest, ThirdAppInstall_1700, Function | MediumTest | Level1) +{ + auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); + ASSERT_NE(installer, nullptr); + OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); + ASSERT_NE(receiver, nullptr); + OHOS::sptr receiver2 = new (std::nothrow) MockStatusReceiver(); + ASSERT_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; + std::string bundleName = THIRD_BUNDLE_NAME + "1"; + std::string modulePackage = "com.third.hiworld.example.h1"; + std::vector hap1AbilityNames = {"bmsThirdBundle_A1", "bmsThirdBundle_A2"}; + CheckFileExist(bundleName, modulePackage, hap1AbilityNames); + + bundleFilePath = BUNDLE_TMPPATH + "bmsThirdBundle5" + Constants::INSTALL_FILE_SUFFIX; + installer->Install(bundleFilePath, installParam, receiver2); + ASSERT_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); + installParam.userId = Constants::DEFAULT_USERID; + installer->Uninstall(bundleName, installParam, recUninstall); + EXPECT_EQ(recUninstall->GetResultCode(), ERR_OK) << "uninstall fail!" << bundleName; +} + +/** + * @tc.number: BundleDataStorage_0100 + * @tc.name: check bundle data storage + * @tc.desc: 1.save a new bundle installation information for the first time successfully + */ +HWTEST_F(BmsBundleInstallerModuleTest, BundleDataStorage_0100, Function | MediumTest | Level1) +{ + APP_LOGI("BmsBundleInstallerModuleTest::BundleDataStorage_0100 begin"); + InnerBundleInfo innerBundleInfo; + bool result = innerBundleInfo.FromJson(innerBundleInfoJson_); + EXPECT_TRUE(result); + ClearJsonFile(); + CheckBundleSaved(innerBundleInfo); + CheckBundleDeleted(innerBundleInfo); + APP_LOGI("BmsBundleDataStorageTest::BundleDataStorage_0100 end"); +} + +/** + * @tc.number: BundleDataStorage_0200 + * @tc.name: save bundle install information to persist storage + * @tc.desc: 1.Update the existing db data + */ +HWTEST_F(BmsBundleInstallerModuleTest, BundleDataStorage_0200, Function | MediumTest | Level1) +{ + APP_LOGI("BmsBundleInstallerModuleTest::BundleDataStorage_0200 begin"); + + InnerBundleInfo innerBundleInfo; + innerBundleInfo.FromJson(innerBundleInfoJson_); + ClearJsonFile(); + CheckBundleSaved(innerBundleInfo); + CheckBundleDeleted(innerBundleInfo); + + BundleInfo bundleInfo = bundleInfoJson_; + bundleInfo.description = "update test application"; + InnerBundleInfo otherInnerBundleInfo = innerBundleInfo; + otherInnerBundleInfo.SetBaseBundleInfo(bundleInfo); + + CheckBundleSaved(otherInnerBundleInfo); + ClearJsonFile(); + APP_LOGI("BmsBundleInstallerModuleTest::BundleDataStorage_0200 end"); +} diff --git a/services/test/moduletest/common/bms/bundle_parser_test/BUILD.gn b/services/test/moduletest/common/bms/bundle_parser_test/BUILD.gn new file mode 100755 index 000000000..e64b8ba8d --- /dev/null +++ b/services/test/moduletest/common/bms/bundle_parser_test/BUILD.gn @@ -0,0 +1,52 @@ +# 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/mstbundlemgrservice" + +ohos_moduletest("BmsBundleParserModuleTest") { + module_out_path = module_output_path + + sources = [ + "${services_path}/bundlemgr/src/inner_bundle_info.cpp", + "bms_bundle_parser_module_test.cpp", + ] + + configs = + [ "${services_path}/test/moduletest/common/bms:bms_module_test_config" ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${common_path}:libappexecfwk_common", + "${services_path}/bundlemgr:bundle_parser", + "${services_path}/bundlemgr:parser_common", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//third_party/googletest:gtest_main", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("moduletest") { + testonly = true + + deps = [ ":BmsBundleParserModuleTest" ] +} diff --git a/services/test/moduletest/common/bms/bundle_parser_test/bms_bundle_parser_module_test.cpp b/services/test/moduletest/common/bms/bundle_parser_test/bms_bundle_parser_module_test.cpp new file mode 100644 index 000000000..9936229a5 --- /dev/null +++ b/services/test/moduletest/common/bms/bundle_parser_test/bms_bundle_parser_module_test.cpp @@ -0,0 +1,127 @@ +/* + * 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 "bundle_parser.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; + +namespace { +const string RESOURCE_ROOT_PATH = "/data/test/bms_bundle/"; +const string INVALID_BUNDLE_SUFFIX = ".rpk"; +} // namespace + +class BmsBundleParserModuleTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + void CheckBundleParserResult(const std::ostringstream &pathStream) const + { + BundleParser bundleParser; + InnerBundleInfo innerBundleInfo; + ErrCode result = bundleParser.Parse(pathStream.str(), innerBundleInfo); + BundleInfo bundleInfo = innerBundleInfo.GetBaseBundleInfo(); + EXPECT_EQ(result, ERR_OK); + + EXPECT_EQ(bundleInfo.name, "com.third.hiworld.example1"); + EXPECT_EQ(bundleInfo.versionName, "1.0"); + + uint32_t versionCode = 1; + EXPECT_EQ(bundleInfo.versionCode, versionCode); + EXPECT_EQ(bundleInfo.vendor, "example"); + + EXPECT_EQ(bundleInfo.maxSdkVersion, 0); + EXPECT_EQ(bundleInfo.minSdkVersion, 0); + } + +protected: + std::ostringstream pathStream_; +}; + +void BmsBundleParserModuleTest::SetUpTestCase() +{} + +void BmsBundleParserModuleTest::TearDownTestCase() +{} + +void BmsBundleParserModuleTest::SetUp() +{} + +void BmsBundleParserModuleTest::TearDown() +{ + pathStream_.clear(); +} + +/** + * @tc.number: MultiAbilityParse_0100 + * @tc.name: Test parse the bundle with two abilities success + * @tc.desc: parse a bundle with two abilities + */ +HWTEST_F(BmsBundleParserModuleTest, MultiAbilityParse_0100, Function | MediumTest | Level1) +{ + pathStream_ << RESOURCE_ROOT_PATH << "bmsThirdBundle2" << Constants::INSTALL_FILE_SUFFIX; + CheckBundleParserResult(pathStream_); +} + +/** + * @tc.number: NullAbility_0200 + * @tc.name: Test parse the bundle with no ability success + * @tc.desc: parse a bundle with no ability + */ +HWTEST_F(BmsBundleParserModuleTest, NullAbility_0200, Function | MediumTest | Level2) +{ + pathStream_ << RESOURCE_ROOT_PATH << "bmsThirdBundle1" << Constants::INSTALL_FILE_SUFFIX; + CheckBundleParserResult(pathStream_); +} + +/** + * @tc.number: InvalidBundleProfileName_0300 + * @tc.name: Test parse the bundle with invalid profile success + * @tc.desc: 1. parse a bundle with invalid profile suffix + * 2. parse a bundle with invalid profile format + */ +HWTEST_F(BmsBundleParserModuleTest, InvalidBundleProfileName_0300, Function | MediumTest | Level2) +{ + pathStream_ << RESOURCE_ROOT_PATH << "bmsThirdBundle11" << Constants::INSTALL_FILE_SUFFIX; + BundleParser bundleParser; + InnerBundleInfo innerBundleInfo; + + ErrCode result = bundleParser.Parse(pathStream_.str(), innerBundleInfo); + EXPECT_EQ(result, ERR_APPEXECFWK_PARSE_NO_PROFILE) << "fail, parser bundle success!"; + + pathStream_.clear(); + + pathStream_ << RESOURCE_ROOT_PATH << "bmsThirdBundle14" << Constants::INSTALL_FILE_SUFFIX; + result = bundleParser.Parse(pathStream_.str(), innerBundleInfo); + EXPECT_EQ(result, ERR_APPEXECFWK_PARSE_UNEXPECTED) << "fail, parser bundle success!"; +} + +/** + * @tc.number: RepeatBundleParser_0400 + * @tc.name: Test parse a bundle ten times success + * @tc.desc: parser a bundle ten times + */ +HWTEST_F(BmsBundleParserModuleTest, RepeatBundleParser_0400, Function | MediumTest | Level1) +{ + int count = 10; + pathStream_ << RESOURCE_ROOT_PATH << "bmsThirdBundle1" << Constants::INSTALL_FILE_SUFFIX; + for (int i = 0; i < count; i++) { + CheckBundleParserResult(pathStream_); + } +} diff --git a/services/test/moduletest/common/bms/bundle_uninstall_test/BUILD.gn b/services/test/moduletest/common/bms/bundle_uninstall_test/BUILD.gn new file mode 100755 index 000000000..742cf77a3 --- /dev/null +++ b/services/test/moduletest/common/bms/bundle_uninstall_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") +import( + "//foundation/appexecfwk/standard/services/bundlemgr/appexecfwk_bundlemgr.gni") + +module_output_path = "appexecfwk_standard/mstbundlemgrservice" + +ohos_moduletest("BmsBundleUninstallerModuleTest") { + module_out_path = module_output_path + + configs = [ + "${services_path}/test/moduletest/common/bms:bms_module_test_config", + "${libs_path}/libeventhandler:libeventhandler_config", + "${services_path}/bundlemgr:bundlemgr_common_config", + "${common_path}:appexecfwk_common_config", + ] + + include_dirs = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core/include/bundlemgr", + "//third_party/json/include", + "${services_path}/test/mock/include", + ] + + sources = [ + "${services_path}/bundlemgr/src/bundle_data_mgr.cpp", + "${services_path}/bundlemgr/src/bundle_data_storage.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/installd/installd_host_impl.cpp", + "${services_path}/bundlemgr/src/installd/installd_operator.cpp", + "${services_path}/bundlemgr/src/installd/installd_service.cpp", + ] + + sources += bundle_install_sources + + sources += [ + "${services_path}/bundlemgr/test/mock/src/system_ability_helper.cpp", + "${services_path}/test/mock/src/mock_status_receiver.cpp", + ] + + sources += [ "bms_bundle_uninstaller_module_test.cpp" ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${libs_path}/libeventhandler:libeventhandler_target", + "${services_path}/bundlemgr:bundle_parser", + "${services_path}/bundlemgr:parser_common", + "${services_path}/test/moduletest/utils:tool_common", + "//base/notification/ces_standard/cesfwk/kits/native:cesfwk_kits", + "//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/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//third_party/googletest:gtest_main", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("moduletest") { + testonly = true + + deps = [ ":BmsBundleUninstallerModuleTest" ] +} 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 new file mode 100755 index 000000000..9d28828f3 --- /dev/null +++ b/services/test/moduletest/common/bms/bundle_uninstall_test/bms_bundle_uninstaller_module_test.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 +#include +#include + +#include "directory_ex.h" +#include "bundle_mgr_service.h" +#include "installd/installd_service.h" +#include "installd_client.h" +#include "mock_status_receiver.h" + +using namespace OHOS; +using namespace testing::ext; +using namespace OHOS::AppExecFwk; +using namespace std::chrono_literals; +using OHOS::DelayedSingleton; + +namespace { +const std::string BUNDLE_CODE_PATH = "/data/accounts/account_0/applications/"; +const std::string BUNDLE_DATA_PATH = "/data/accounts/account_0/appdata/"; +const std::string THIRD_BUNDLE_PATH = "/data/test/bms_bundle/"; +const std::string BUNDLE_NAME = "com.third.hiworld.example1"; +const std::string MODULE_PACKAGE = "com.third.hiworld.example.h1"; +const std::string SYSTEM_BUNDLE_NAME = "com.system.hiworld.examples2"; +} // namespace + +class BmsBundleUninstallerModuleTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + ErrCode InstallBundle(const std::string &bundlePath) const; + ErrCode UninstallBundle(const std::string &bundleName) const; + ErrCode UninstallHap(const std::string &bundleName, const std::string &modulePackage) const; + void CheckFileExist(const std::string bundlename) const; + void CheckFileNonExist(const std::string bundlename) const; + void CheckBundleInfoExist(const std::string bundlename) const; + void CheckBundleInfoNonExist(const std::string bundlename) const; + void CheckHapDirNonExist(const std::string bundlename, const std::string &modulePackage) const; + static void ClearJsonFile(); + + void StartBundleMgrService() + { + bms_ = DelayedSingleton::GetInstance(); + bms_->OnStart(); + } + + void StopBundleMgrService() + { + bms_->OnStop(); + DelayedSingleton::DestroyInstance(); + } + + void StartInstalld() + { + installdService_->Start(); + } + + void StopInstalld() + { + installdService_->Stop(); + InstalldClient::GetInstance()->ResetInstalldProxy(); + } + +private: + std::shared_ptr bms_ = nullptr; + std::shared_ptr installdService_ = std::make_shared(); +}; + +ErrCode BmsBundleUninstallerModuleTest::InstallBundle(const std::string &bundlePath) const +{ + auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); + if (installer == nullptr) { + EXPECT_FALSE(true) << "the installer is nullptr"; + return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR; + } + OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); + if (receiver == nullptr) { + EXPECT_FALSE(true) << "the receiver is nullptr"; + return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR; + } + InstallParam installParam; + installParam.installFlag = InstallFlag::NORMAL; + installer->Install(bundlePath, installParam, receiver); + return receiver->GetResultCode(); +} + +ErrCode BmsBundleUninstallerModuleTest::UninstallBundle(const std::string &bundleName) const +{ + auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); + if (installer == nullptr) { + EXPECT_FALSE(true) << "the installer is nullptr"; + return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR; + } + OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); + if (receiver == nullptr) { + EXPECT_FALSE(true) << "the receiver is nullptr"; + return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR; + } + InstallParam installParam; + installParam.userId = Constants::DEFAULT_USERID; + installer->Uninstall(bundleName, installParam, receiver); + return receiver->GetResultCode(); +} + +ErrCode BmsBundleUninstallerModuleTest::UninstallHap( + const std::string &bundleName, const std::string &modulePackage) const +{ + auto installer = DelayedSingleton::GetInstance()->GetBundleInstaller(); + if (installer == nullptr) { + EXPECT_FALSE(true) << "the installer is nullptr"; + return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR; + } + OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); + if (receiver == nullptr) { + EXPECT_FALSE(true) << "the receiver is nullptr"; + return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR; + } + InstallParam installParam; + installParam.userId = Constants::DEFAULT_USERID; + installer->Uninstall(bundleName, modulePackage, installParam, receiver); + return receiver->GetResultCode(); +} + +void BmsBundleUninstallerModuleTest::CheckFileExist(const std::string bundlename) const +{ + int bundleDataExist = access((BUNDLE_DATA_PATH + bundlename).c_str(), F_OK); + EXPECT_EQ(bundleDataExist, 0) << "the bundle data dir does not exists: " << (BUNDLE_DATA_PATH + bundlename); + int codeExist = access((BUNDLE_CODE_PATH + bundlename).c_str(), F_OK); + EXPECT_EQ(codeExist, 0) << "the ability code file does not exist: " << (BUNDLE_CODE_PATH + bundlename); +} + +void BmsBundleUninstallerModuleTest::CheckFileNonExist(const std::string bundlename) const +{ + int bundleDataExist = access((BUNDLE_DATA_PATH + bundlename).c_str(), F_OK); + EXPECT_NE(bundleDataExist, 0) << "the bundle data dir exists: " << (BUNDLE_DATA_PATH + bundlename); + int codeExist = access((BUNDLE_CODE_PATH + bundlename).c_str(), F_OK); + EXPECT_NE(codeExist, 0) << "the ability code exists: " << (BUNDLE_CODE_PATH + bundlename); +} + +void BmsBundleUninstallerModuleTest::CheckBundleInfoExist(const std::string bundlename) const +{ + BundleInfo info; + std::shared_ptr bms = DelayedSingleton::GetInstance(); + auto dataMgr = bms->GetDataMgr(); + ASSERT_NE(dataMgr, nullptr); + bool isBundleExist = dataMgr->GetBundleInfo(bundlename, BundleFlag::GET_BUNDLE_DEFAULT, info); + EXPECT_TRUE(isBundleExist); +} + +void BmsBundleUninstallerModuleTest::CheckBundleInfoNonExist(const std::string bundlename) const +{ + BundleInfo info; + std::shared_ptr bms = DelayedSingleton::GetInstance(); + auto dataMgr = bms->GetDataMgr(); + ASSERT_NE(dataMgr, nullptr); + bool isBundleExist = dataMgr->GetBundleInfo(bundlename, BundleFlag::GET_BUNDLE_DEFAULT, info); + EXPECT_FALSE(isBundleExist); +} +void BmsBundleUninstallerModuleTest::CheckHapDirNonExist( + const std::string bundlename, const std::string &modulePackage) const +{ + int bundleDataExist = access((BUNDLE_DATA_PATH + bundlename + modulePackage).c_str(), F_OK); + EXPECT_NE(bundleDataExist, 0) << "the bundle data dir exists: " << bundlename; + int codeExist = access((BUNDLE_CODE_PATH + bundlename + modulePackage).c_str(), F_OK); + EXPECT_NE(codeExist, 0) << "the ability code exists: " << bundlename; +} + +void BmsBundleUninstallerModuleTest::ClearJsonFile() +{ + std::string fileName = Constants::BUNDLE_DATA_BASE_FILE; + std::ofstream o(fileName); + if (!o.is_open()) { + std::cout << "failed to open as out" << fileName << std::endl; + } else { + std::cout << "clear" << fileName << std::endl; + } + o.close(); +} + +void BmsBundleUninstallerModuleTest::SetUpTestCase() +{} + +void BmsBundleUninstallerModuleTest::TearDownTestCase() +{} + +void BmsBundleUninstallerModuleTest::SetUp() +{ + ClearJsonFile(); + OHOS::ForceRemoveDirectory(BUNDLE_CODE_PATH); + OHOS::ForceRemoveDirectory(BUNDLE_DATA_PATH); + StartInstalld(); + StartBundleMgrService(); +} + +void BmsBundleUninstallerModuleTest::TearDown() +{ + std::cout << "BmsBundleUninstallerModuleTest::TearDown begin" << std::endl; + if (access((BUNDLE_CODE_PATH + BUNDLE_NAME).c_str(), F_OK) == 0) { + ErrCode uninstallResult = UninstallBundle(BUNDLE_NAME); + EXPECT_EQ(uninstallResult, ERR_OK); + } + + StopInstalld(); + StopBundleMgrService(); + OHOS::ForceRemoveDirectory(BUNDLE_CODE_PATH); + OHOS::ForceRemoveDirectory(BUNDLE_DATA_PATH); + ClearJsonFile(); + std::this_thread::sleep_for(50ms); +} + +/** + * @tc.number: Uninstall_0100 + * @tc.name: test the third-party bundle can be uninstalled. + * @tc.desc: the installed bundle can be uninstalled successfully. + */ +HWTEST_F(BmsBundleUninstallerModuleTest, Uninstall_0100, Function | MediumTest | Level1) +{ + std::string bundlePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1" + Constants::INSTALL_FILE_SUFFIX; + ErrCode installResult = InstallBundle(bundlePath); + ASSERT_EQ(installResult, ERR_OK); + + CheckFileExist(BUNDLE_NAME); + CheckBundleInfoExist(BUNDLE_NAME); + + ErrCode uninstallResult = UninstallBundle(BUNDLE_NAME); + ASSERT_EQ(uninstallResult, ERR_OK); + CheckFileNonExist(BUNDLE_NAME); + CheckBundleInfoNonExist(BUNDLE_NAME); +} + +/** + * @tc.number: Uninstall_0200 + * @tc.name: test the third-party bundle can not be uninstalled by wrong bundle name. + * @tc.desc: the installed bundle can not be uninstalled successfully. + */ +HWTEST_F(BmsBundleUninstallerModuleTest, Uninstall_0200, Function | MediumTest | Level1) +{ + std::string bundlePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1" + Constants::INSTALL_FILE_SUFFIX; + ErrCode installResult = InstallBundle(bundlePath); + ASSERT_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); + + CheckFileNonExist(errorBundleName); + CheckBundleInfoNonExist(errorBundleName); +} + +/** + * @tc.number: Uninstall_0300 + * @tc.name: test the third-party bundle can't be uninstalled twice + * @tc.desc: The first is successful but second is failed + */ +HWTEST_F(BmsBundleUninstallerModuleTest, Uninstall_0300, Function | MediumTest | Level2) +{ + std::string bundlePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1" + Constants::INSTALL_FILE_SUFFIX; + ErrCode installResult = InstallBundle(bundlePath); + ASSERT_EQ(installResult, ERR_OK); + + CheckFileExist(BUNDLE_NAME); + CheckBundleInfoExist(BUNDLE_NAME); + + ErrCode uninstallResult = UninstallBundle(BUNDLE_NAME); + ASSERT_EQ(uninstallResult, ERR_OK); + CheckFileNonExist(BUNDLE_NAME); + CheckBundleInfoNonExist(BUNDLE_NAME); + + uninstallResult = UninstallBundle(BUNDLE_NAME); + ASSERT_EQ(uninstallResult, ERR_APPEXECFWK_UNINSTALL_MISSING_INSTALLED_BUNDLE); +} + +/** + * @tc.number: Uninstall_0400 + * @tc.name: test the third-party app with one hap can be uninstalled. + * @tc.desc: the installed app can be uninstalled successfully. + */ +HWTEST_F(BmsBundleUninstallerModuleTest, Uninstall_0400, Function | MediumTest | Level1) +{ + std::string bundlePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1" + Constants::INSTALL_FILE_SUFFIX; + ErrCode installResult = InstallBundle(bundlePath); + ASSERT_EQ(installResult, ERR_OK); + + CheckFileExist(BUNDLE_NAME); + CheckBundleInfoExist(BUNDLE_NAME); + + ErrCode uninstallResult = UninstallHap(BUNDLE_NAME, MODULE_PACKAGE); + ASSERT_EQ(uninstallResult, ERR_OK); + CheckFileNonExist(BUNDLE_NAME); + CheckBundleInfoNonExist(BUNDLE_NAME); +} + +/** + * @tc.number: Uninstall_0500 + * @tc.name: test the third-party app with two haps can be uninstalled + * @tc.desc: the installed bundle can not be uninstalled successfully. + */ +HWTEST_F(BmsBundleUninstallerModuleTest, Uninstall_0500, Function | MediumTest | Level1) +{ + std::string bundlePath = THIRD_BUNDLE_PATH + "bmsThirdBundle1" + Constants::INSTALL_FILE_SUFFIX; + ErrCode installResult = InstallBundle(bundlePath); + ASSERT_EQ(installResult, ERR_OK); + + bundlePath = THIRD_BUNDLE_PATH + "bmsThirdBundle4" + Constants::INSTALL_FILE_SUFFIX; + installResult = InstallBundle(bundlePath); + ASSERT_EQ(installResult, ERR_OK); + + CheckFileExist(BUNDLE_NAME); + CheckBundleInfoExist(BUNDLE_NAME); + + ErrCode uninstallResult = UninstallHap(BUNDLE_NAME, MODULE_PACKAGE); + ASSERT_EQ(uninstallResult, ERR_OK); + CheckHapDirNonExist(BUNDLE_NAME, MODULE_PACKAGE); + CheckFileExist(BUNDLE_NAME); + CheckBundleInfoExist(BUNDLE_NAME); +} + +/** + * @tc.number: Uninstall_0600 + * @tc.name: test the big third-party app can be uninstalled + * @tc.desc: the installed bundle can not be uninstalled successfully. + */ +HWTEST_F(BmsBundleUninstallerModuleTest, Uninstall_0600, Function | MediumTest | Level1) +{ + BundleInfo info; + std::shared_ptr bms = DelayedSingleton::GetInstance(); + auto dataMgr = bms->GetDataMgr(); + ASSERT_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); + 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); + OHOS::sptr receiver = new (std::nothrow) MockStatusReceiver(); + ASSERT_NE(receiver, nullptr); + InstallParam installParam; + installParam.userId = Constants::DEFAULT_USERID; + installer->Uninstall(bundleName, installParam, receiver); + ASSERT_EQ(receiver->GetResultCode(), ERR_OK); + isBundleExist = dataMgr->GetBundleInfo(bundleName, BundleFlag::GET_BUNDLE_DEFAULT, info); + EXPECT_FALSE(isBundleExist); + CheckFileNonExist(bundleName); + CheckBundleInfoNonExist(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 new file mode 100755 index 000000000..d9f5b9e35 --- /dev/null +++ b/services/test/moduletest/common/bms/service_start_process_test/BUILD.gn @@ -0,0 +1,77 @@ +# 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") +import( + "//foundation/appexecfwk/standard/services/bundlemgr/appexecfwk_bundlemgr.gni") + +module_output_path = "appexecfwk_standard/mstbundlemgrservice" + +ohos_moduletest("BmsServiceStartModuleTest") { + module_out_path = module_output_path + + include_dirs = [ "${appexecfwk_path}/interfaces" ] + + sources = [ + "${services_path}/bundlemgr/src/bundle_data_mgr.cpp", + "${services_path}/bundlemgr/src/bundle_data_storage.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", + ] + + sources += + [ "${services_path}/bundlemgr/test/mock/src/system_ability_helper.cpp" ] + + sources += bundle_install_sources + + sources += [ "bms_service_start_module_test.cpp" ] + + configs = [ + "${services_path}/test/moduletest/common/bms:bms_module_test_config", + "${libs_path}/libeventhandler:libeventhandler_config", + "${common_path}:appexecfwk_common_config", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + deps = [ + "${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "${libs_path}/libeventhandler:libeventhandler_target", + "//base/notification/ces_standard/cesfwk/kits/native:cesfwk_kits", + "//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/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//third_party/googletest:gtest_main", + ] + + deps += bundle_install_deps + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] +} + +group("moduletest") { + testonly = true + + deps = [ ":BmsServiceStartModuleTest" ] +} diff --git a/services/test/moduletest/common/bms/service_start_process_test/bms_service_start_module_test.cpp b/services/test/moduletest/common/bms/service_start_process_test/bms_service_start_module_test.cpp new file mode 100755 index 000000000..7277333fe --- /dev/null +++ b/services/test/moduletest/common/bms/service_start_process_test/bms_service_start_module_test.cpp @@ -0,0 +1,352 @@ +/* + * 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_mgr_service.h" +#include "bundle_parser.h" +#include "bundle_extractor.h" +#include "bundle_scanner.h" + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::AppExecFwk; +using OHOS::DelayedSingleton; +namespace { +const std::string TEST_DIR = "bundle_scan_module_test"; +const std::string BUNDLE_FILENAME_NORMAL = "t11.hap"; +const std::string BUNDLE_FILENAME_ABNORMAL = "t11.rpk"; +const string RESOURCE_ROOT_PATH = "/hos/test/bms_bundle/"; +const int CYCLE_NUMBER = 1000; +} // namespace + +class BmsServiceStartModuleTest : public testing::Test { +public: + BmsServiceStartModuleTest(); + ~BmsServiceStartModuleTest(); + + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + + void CreateDir(const std::string &path) const; + void DeleteDir(const std::string &path) const; + void CreateFile(const std::string &path) const; + void DeleteFile(const std::string &path) const; + long TriggerScan(); + bool IsScanResultContain(const std::string &name) const; + + std::shared_ptr GetServiceInstance() + { + return bms_; + } + +protected: + std::ostringstream pathStream_; + +private: + std::shared_ptr bms_ = DelayedSingleton::GetInstance(); + std::list bundleList_{}; +}; + +BmsServiceStartModuleTest::BmsServiceStartModuleTest() +{} + +BmsServiceStartModuleTest::~BmsServiceStartModuleTest() +{ + bms_.reset(); +} + +void BmsServiceStartModuleTest::SetUpTestCase() +{} + +void BmsServiceStartModuleTest::TearDownTestCase() +{} + +void BmsServiceStartModuleTest::SetUp() +{ + CreateDir(TEST_DIR); +} + +void BmsServiceStartModuleTest::TearDown() +{ + bundleList_.clear(); + DeleteDir(TEST_DIR); +} + +void BmsServiceStartModuleTest::CreateDir(const std::string &path) const +{ + if (access(path.c_str(), F_OK) != 0) { + if (mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) { + APP_LOGE("CreateDir:%{public}s error", path.c_str()); + } + } +} + +void BmsServiceStartModuleTest::DeleteDir(const std::string &path) const +{ + if (access(path.c_str(), F_OK) == 0) { + if (rmdir(path.c_str()) != 0) { + APP_LOGE("DeleteDir:%{public}s error", path.c_str()); + } + } +} + +void BmsServiceStartModuleTest::CreateFile(const std::string &path) const +{ + if (path.size() > PATH_MAX) { + APP_LOGE("CreateFile the length of path is too long"); + return; + } + + 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; + } + + 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; + } + if (close(fd) != 0) { + APP_LOGW("CreateFile-close:%{public}s error", realPath.c_str()); + return; + } + + if (access(realPath.c_str(), F_OK) != 0) { + APP_LOGE("CreateFile-checkFile:%{public}s not exist", realPath.c_str()); + } +} + +void BmsServiceStartModuleTest::DeleteFile(const std::string &path) const +{ + if (remove(path.c_str()) != 0) { + APP_LOGE("DeleteFile:%{public}s fail", path.c_str()); + } +} + +long BmsServiceStartModuleTest::TriggerScan() +{ + auto scanner = std::make_unique(); + if (scanner == nullptr) { + return -1; + } + + bundleList_ = scanner->Scan(TEST_DIR); + return bundleList_.size(); +} + +bool BmsServiceStartModuleTest::IsScanResultContain(const std::string &name) const +{ + auto it = std::find(bundleList_.begin(), bundleList_.end(), name); + if (it == bundleList_.end()) { + return false; + } + return true; +} + +/** + * @tc.number: BmsStartup_0100 + * @tc.name: Bundle manager service startup + * @tc.desc: Bundle manager service startup 1000 times,only the first time is successful + */ +HWTEST_F(BmsServiceStartModuleTest, BmsStartup_0100, Function | MediumTest | Level1) +{ + APP_LOGI("BmsStartup_0100 start"); + + EXPECT_EQ(false, GetServiceInstance()->IsServiceReady()); + GetServiceInstance()->OnStart(); + EXPECT_EQ(true, GetServiceInstance()->IsServiceReady()); + + for (int i = 0; i < CYCLE_NUMBER; i++) { + GetServiceInstance()->OnStart(); + } + EXPECT_EQ(true, GetServiceInstance()->IsServiceReady()); + GetServiceInstance()->OnStop(); + EXPECT_EQ(false, GetServiceInstance()->IsServiceReady()); + APP_LOGI("BmsStartup_0100 end"); +} + +/** + * @tc.number: BmsStartup_0200 + * @tc.name: Bundle manager service startup and stop + * @tc.desc: Bms service start and stop 1000 times alternately,Only the last start is successful + */ +HWTEST_F(BmsServiceStartModuleTest, BmsStartup_0200, Function | MediumTest | Level1) +{ + APP_LOGI("BmsStartup_0200 start"); + EXPECT_EQ(false, GetServiceInstance()->IsServiceReady()); + GetServiceInstance()->OnStart(); + EXPECT_EQ(true, GetServiceInstance()->IsServiceReady()); + + for (int i = 0; i < CYCLE_NUMBER; i++) { + GetServiceInstance()->OnStart(); + GetServiceInstance()->OnStop(); + } + EXPECT_EQ(false, GetServiceInstance()->IsServiceReady()); + GetServiceInstance()->OnStart(); + EXPECT_EQ(true, GetServiceInstance()->IsServiceReady()); + GetServiceInstance()->OnStop(); + APP_LOGI("BmsStartup_0200 end"); +} + +/** + * @tc.number: BmsStartup_0300 + * @tc.name: Bundle manager service start and stop alternately + * @tc.desc: Bundle manager service stop 1000 times alternately,the last time is successful + */ +HWTEST_F(BmsServiceStartModuleTest, BmsStartup_0300, Function | MediumTest | Level1) +{ + APP_LOGI("BmsStartup_0300 start"); + EXPECT_EQ(false, GetServiceInstance()->IsServiceReady()); + GetServiceInstance()->OnStart(); + EXPECT_EQ(true, GetServiceInstance()->IsServiceReady()); + + for (int i = 0; i < CYCLE_NUMBER; i++) { + GetServiceInstance()->OnStop(); + } + EXPECT_EQ(false, GetServiceInstance()->IsServiceReady()); + GetServiceInstance()->OnStart(); + EXPECT_EQ(true, GetServiceInstance()->IsServiceReady()); + GetServiceInstance()->OnStop(); + EXPECT_EQ(false, GetServiceInstance()->IsServiceReady()); + APP_LOGI("BmsStartup_0300 end"); +} + +/** + * @tc.number: TestParse_0100 + * @tc.name: Parse bundle package by config.json + * @tc.desc: Test parse bundle with an incorrect path + */ +HWTEST_F(BmsServiceStartModuleTest, TestParse_0100, Function | MediumTest | Level2) +{ + APP_LOGI("TestParse_0100 start"); + BundleParser bundleParser; + InnerBundleInfo innerBundleInfo; + + pathStream_ << RESOURCE_ROOT_PATH << "incorrect_path/demo" << Constants::INSTALL_FILE_SUFFIX; + ErrCode result = bundleParser.Parse(pathStream_.str(), innerBundleInfo); + EXPECT_EQ(result, ERR_APPEXECFWK_PARSE_UNEXPECTED); + APP_LOGI("TestParse_0100 end"); +} + +/** + * @tc.number: TestParse_0200 + * @tc.name: Parse bundle package by config.json + * @tc.desc: Test the path of parse bundle with unusual character + */ +HWTEST_F(BmsServiceStartModuleTest, TestParse_0200, Function | MediumTest | Level2) +{ + APP_LOGI("TestParse_0200 start"); + BundleParser bundleParser; + InnerBundleInfo innerBundleInfo; + + pathStream_ << RESOURCE_ROOT_PATH << " demo" << Constants::INSTALL_FILE_SUFFIX; + ErrCode result = bundleParser.Parse(pathStream_.str(), innerBundleInfo); + EXPECT_EQ(result, ERR_APPEXECFWK_PARSE_UNEXPECTED); + + BundleInfo bundleInfo = innerBundleInfo.GetBaseBundleInfo(); + EXPECT_NE(bundleInfo.name, "com.third.example.helloworld"); + EXPECT_NE(bundleInfo.applicationInfo.name, "com.third.example.helloworld"); + APP_LOGI("TestParse_0200 end"); +} + +/** + * @tc.number: TestParse_0300 + * @tc.name: Parse bundle package by config.json + * @tc.desc: Test the path of parse bundle with long string + */ +HWTEST_F(BmsServiceStartModuleTest, TestParse_0300, Function | MediumTest | Level2) +{ + APP_LOGI("TestParse_0300 start"); + BundleParser bundleParser; + InnerBundleInfo innerBundleInfo; + + pathStream_ << RESOURCE_ROOT_PATH + << "deepdir_1/deepdir_2/deepdir_3/deepdir_4/" + "deepdir_5/deepdir_6/deepdir_7/deepdir_8/deepdir_9/demo" + << Constants::INSTALL_FILE_SUFFIX; + ErrCode result = bundleParser.Parse(pathStream_.str(), innerBundleInfo); + EXPECT_EQ(result, ERR_APPEXECFWK_PARSE_UNEXPECTED); + APP_LOGI("TestParse_0300 end"); +} + +/** + * @tc.number: TestBundleScan_0100 + * @tc.name: Parse bundle package by bundle.json + * @tc.desc: Scan a normal bundle and an abnormal bundle + */ +HWTEST_F(BmsServiceStartModuleTest, TestBundleScan_0100, Function | MediumTest | Level2) +{ + APP_LOGI("TestBundleScan_0100 start"); + const std::string testFileNameNormal = TEST_DIR + "/" + BUNDLE_FILENAME_NORMAL; + const std::string testFileNameAbnormal = TEST_DIR + "/" + BUNDLE_FILENAME_ABNORMAL; + + CreateFile(testFileNameNormal); + CreateFile(testFileNameAbnormal); + + int number = static_cast(TriggerScan()); + EXPECT_EQ(1, number); + + EXPECT_TRUE(IsScanResultContain(testFileNameNormal)); + EXPECT_FALSE(IsScanResultContain(testFileNameAbnormal)); + + DeleteFile(testFileNameNormal); + DeleteFile(testFileNameAbnormal); + APP_LOGI("TestBundleScan_0100 end"); +} + +/** + * @tc.number: TestBundleScan_0200 + * @tc.name: Parse bundle package by config.json + * @tc.desc: scan 1000 normal bundles and 1000 abnormal bundles + */ +HWTEST_F(BmsServiceStartModuleTest, TestBundleScan_0200, Function | MediumTest | Level2) +{ + APP_LOGI("TestBundleScan_0200 start"); + unsigned long int i; + + for (i = 0; i < CYCLE_NUMBER; i++) { + const std::string testFileNameNormal = TEST_DIR + "/" + std::to_string(i) + BUNDLE_FILENAME_NORMAL; + const std::string testFileNameAbnormal = TEST_DIR + "/" + std::to_string(i) + BUNDLE_FILENAME_ABNORMAL; + CreateFile(testFileNameNormal); + CreateFile(testFileNameAbnormal); + } + + int number = static_cast(TriggerScan()); + EXPECT_EQ(CYCLE_NUMBER, number); + + for (i = 0; i < CYCLE_NUMBER; i++) { + const std::string testFileNameNormal = TEST_DIR + "/" + std::to_string(i) + BUNDLE_FILENAME_NORMAL; + const std::string testFileNameAbnormal = TEST_DIR + "/" + std::to_string(i) + BUNDLE_FILENAME_ABNORMAL; + EXPECT_TRUE(IsScanResultContain(testFileNameNormal)); + EXPECT_FALSE(IsScanResultContain(testFileNameAbnormal)); + DeleteFile(testFileNameNormal); + DeleteFile(testFileNameAbnormal); + } + APP_LOGI("TestBundleScan_0200 end"); +} diff --git a/services/test/moduletest/utils/BUILD.gn b/services/test/moduletest/utils/BUILD.gn new file mode 100644 index 000000000..631df6cb3 --- /dev/null +++ b/services/test/moduletest/utils/BUILD.gn @@ -0,0 +1,30 @@ +# 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") + +config("tool_config") { + visibility = [ ":*" ] + include_dirs = [ + "include", + "//utils/native/base/include", + ] +} + +ohos_source_set("tool_common") { + sources = [ "src/common_tool.cpp" ] + + public_configs = [ ":tool_config" ] + + deps = [ "//utils/native/base:utils" ] +} diff --git a/services/test/moduletest/utils/include/common_tool.h b/services/test/moduletest/utils/include/common_tool.h new file mode 100644 index 000000000..0c5acab4f --- /dev/null +++ b/services/test/moduletest/utils/include/common_tool.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_TEST_MODULETEST_COMMON_TOOL_H +#define FOUNDATION_APPEXECFWK_SERVICES_TEST_MODULETEST_COMMON_TOOL_H + +#include +#include + +namespace OHOS { +namespace AppExecFwk { + +class CommonTool { +public: + int32_t ExcuteCmd(const std::string &cmd, std::vector &resvec, const int size); + bool ExcuteCmd(const std::string &cmd); + bool CheckFilePathISExist(const std::string &filePath); + bool CopyTmpFileToSystemPath(const std::string &srcPath, const std::string &dstPath); + bool DeleteFile(const std::string &filePath); + long GetFileBuildTime(const std::string &path); + int32_t GetPid(const std::string &processName); + std::string VectorToStr(const std::vector &strVector); + bool StartExecutable(const std::string &serviceName, const std::string &args); +}; + +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_SERVICES_TEST_MODULETEST_COMMON_TOOL_H \ No newline at end of file diff --git a/services/test/moduletest/utils/src/common_tool.cpp b/services/test/moduletest/utils/src/common_tool.cpp new file mode 100644 index 000000000..08edfb2ae --- /dev/null +++ b/services/test/moduletest/utils/src/common_tool.cpp @@ -0,0 +1,183 @@ +/* + * 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 "common_tool.h" + +#include +#include +#include + +#include + +#include "string_ex.h" + +namespace OHOS { +namespace AppExecFwk { + +int32_t CommonTool::ExcuteCmd(const std::string &cmd, std::vector &resvec, const int32_t size) +{ + if (size <= 0) { + return 0; + } + resvec.clear(); + FILE *file = popen(cmd.c_str(), "r"); + if (file == nullptr) { + return 0; + } + char tmp[size]; + tmp[0] = '\0'; + while (fgets(tmp, sizeof(tmp), file) != nullptr) { + if (tmp[strlen(tmp) - 1] == '\n') { + tmp[strlen(tmp) - 1] = '\0'; + } + std::string iem(tmp); + resvec.push_back(iem); + } + pclose(file); + return resvec.size(); +} + +bool CommonTool::ExcuteCmd(const std::string &cmd) +{ + FILE *file = popen(cmd.c_str(), "r"); + if (file == nullptr) { + return false; + } + pclose(file); + return true; +} + +bool CommonTool::CheckFilePathISExist(const std::string &filePath) +{ + if (access(filePath.c_str(), F_OK) == 0) { + return true; + } + return false; +} + +bool CommonTool::CopyTmpFileToSystemPath(const std::string &srcPath, const std::string &dstPath) +{ + if (access(srcPath.c_str(), F_OK) != 0) { + return false; + } + FILE *srcFile = fopen(srcPath.c_str(), "r"); + if (srcFile == nullptr) { + return false; + } + FILE *dstFile = fopen(dstPath.c_str(), "w"); + if (dstFile == nullptr) { + fclose(srcFile); + return false; + } + + constexpr int READ_SIZE = 1024; + std::string buff; + buff.reserve(READ_SIZE); + buff.resize(READ_SIZE - 1); + int count = 0; + while ((count = fread(&(buff[0]), 1, READ_SIZE - 1, srcFile)) != 0) { + fwrite(&(buff[0]), 1, count, dstFile); + } + + fclose(srcFile); + fclose(dstFile); + return true; +} + +long CommonTool::GetFileBuildTime(const std::string &path) +{ + long buildTime = 0; + struct stat buf; + FILE *file = fopen(path.c_str(), "r"); + if (file == nullptr) { + return buildTime; + } + int fd = fileno(file); + if (fd == -1) { + fclose(file); + return buildTime; + } + fstat(fd, &buf); + buildTime = buf.st_ctime; + fclose(file); + return buildTime; +} + +int32_t CommonTool::GetPid(const std::string &processName) +{ + std::string cmd = "ps -A | grep " + processName; + int32_t size = 1024; + std::vector echoContents; + int32_t queryResult = ExcuteCmd(cmd, echoContents, size); + if (queryResult == 0) { + return 0; + } + + for (std::string echoContent : echoContents) { + unsigned long index = echoContent.find(processName); + if (index != std::string::npos) { + int32_t pid = 0; + std::vector strsRet; + OHOS::SplitStr(echoContent, " ", strsRet); + for (std::string item : strsRet) { + if (OHOS::StrToInt(item, pid)) { + break; + } + } + return pid; + } + } + return 0; +} + +std::string CommonTool::VectorToStr(const std::vector &strVector) +{ + std::string str; + for (auto it = strVector.begin(); it != strVector.end(); it++) { + str.append(*it); + } + return str; +} + +bool CommonTool::StartExecutable(const std::string &serviceName, const std::string &args) +{ + std::string cmd = "chmod +x /system/bin/" + serviceName; + int res = system(cmd.c_str()); + if (res != 0) { + return false; + } + + int32_t pid = GetPid(serviceName); + if (pid != 0) { + return true; + } + + std::string exeCmd = "/system/bin/" + serviceName + " " + args + "&"; + int cmdRes = system(exeCmd.c_str()); + if (cmdRes != 0) { + return false; + } + + std::vector resvec; + int32_t size = 1024; + int32_t contentSize = ExcuteCmd("ps -A |grep " + serviceName, resvec, size); + if (contentSize == 0) { + return false; + } + return true; +} + +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/test/resource/ams/ams_data_ability_bundle/amsDataSystemTestA.hap b/test/resource/ams/ams_data_ability_bundle/amsDataSystemTestA.hap new file mode 100644 index 0000000000000000000000000000000000000000..1a22a001b538a66aa3d97d3ab261d885ae59ce49 GIT binary patch literal 120374 zcmZ^~S5On)7cDG=-UXE21Vlu-fJ%viNK-)&P$>Zs5K%&r4hdD17NtrJO;D)<(jlQY z>C#ImLg)!C390w@|Gt^~cF)6}^S1Wvwbq_F`MlF8Z^oxA6Pc5#tOc!$_tBi&q7*D`Gyi zGRCKu`qoz3Qw}`e&OfN_O?_lZGlvw7HEQJ$SiB#<9itctd>1ah35gT#4UjIWWDl(= zjJU&~WQxv@Eab-*^U2*DB0kN#UYExG>d~L18!d_T*M)Re+;G;<^{=3Ms;GoSdpQGNrXdhY!{zNSgo58=|{lBgMta2q%E{(dG=^X*kq(m zm)?WfXO}yNS?k3kukB&$I1|s|567!O|jAi)qL`7`v+aJ@_+fO zYbcMx2yXPzGr!`)qnks3M1Rj)0UVb+)@^Rsa)qhLB zm>}JyVGj%<9gIP6&yIdba3zH)30v)d4Ednh4c+v{;l1)FFJD#`^Lsix0i0? z0d6aal}q-31^rFub#uK!@bP`;XS+R+Y*9Yawc>frO4S9ATQ8rL{bdcOm%S8@Dok@1 zF`rHCe&Zz}J_8wabt={f7lTk1bB2KyX3Q)z4@E4C=`LI_WxQ~~;{VC7@PACd^?2$0 z&hNhSduOX)zxS^1p1S(Izo!(Ub7re|U}VhJL@1_Rx}DYX8!HPvebLQ}baWm?S1d~iq4|09i_3!!Y%zEW z4T#dZHL7csAH0?2{=YE4Y%cBc;^))rkI7bkdbtqp>A068s_{nAe3}9&0>K796(Qo}aX7KMQ zBS-qx~^e?QOiKRZgk#P{iDad;jf271IwHIT{RcW9b<{#v=;FWRz99OT8mnaay#5$ z(56QKp5{FG++IJm3$rd06{=6xV5BG>d-|i8~)~fg0 z42pbQef+tj;bXXTk1_4c^ee`t8kC2gbfeD%1Qkl8s(gS1G4ks8)0>3$Nz${cj{g$d z;EW7_^)XZ}e67bsADOOdJ%T@&5|}uRySZG$zjthx&o^&mn?OtBnF308&ATBUl`y}nYB7wvkK7P z4vzISq3eg|M$b^)UI|^ko(ItT7duJ}`P$5jSUU_WgYJnN*robfyYS#@pcl=C(mzQb z^xn0u(ma55h3|+X_@w z`F?*{%5J>spXhoo85)0|$nHEmOn)1H@OZM{xvemY5~enTJ^)yO7LwJLA=2HK*zLI%QEOlvHaqNoO_*om8V|;FNb#hdPPpI*R zx(U>y^f=?*uK&R!BE<;Y1wXiao!cg*gK;BiZ~uqpi?Iijutno@!>n5!Z%7$>C8*Te zAg_g+mu59`5>FJR0_xxxqkjW)@bTah;19U!g+1%~P-wi5Pb*Ap!xtBCzzUcCkU~^Y zbp&;LNj%v8s+lmez&#m!NqgEE^#89K0Wi34AAq+XmJq^BOeC7G6>7QzZxf4 zE$@ud%0e>B@ev02=|NfgefaJlB@SM~Cd#*ykhAjSk6j*9tZm>sKk%Qs%vBt_7iUK$ zu}4BN$)WsI@2ipE5t%cu(JNu?S_%L9|MWq=?>qXji0Z_pEvm((DX3;9f)?!c`(v7A z!ntFW$7Ii{teTc|CRgH42AU3XjE)1xiphEA*#0p&Zy=j;j``ULJ$Q3d|X74&>V&b1@1qId>!*bRzch0;( z&p~o?ZAQHd$Y|3^%mfcIKX1-QHeMq$$D-d!Vrw}Wk{69v>ysF&nm(P5q5VqAo5D9P zry#=F2T>jA$ru}Y@Ojkn0lPjr;vIu{LlW}hBI}aB_QBZW6t6|YE$K#)bDKXMZ?)E< z56u3coVb_FR^>uX&f`GNp)0sFgBWlt_eDsHSm`nJ>n?~5cIV+Sq5!L#4WfDGg0F|p z%-+wRfjpYYLW5F|SBzMwJ;kqd<&QXpGUZS_kWeu>LW{Uu*s<<^@&ew&mgPx?pu54W zl+DL4Lk$l+9n^^X5*_dfoVM)rt;P6jg2v`}A&=&{ddyKDFuZgKQLNElWp z4<-Is<3_Cyu^OpoB`7f|G1)nSKlHnA`nr(s@r=s^bxZf zFTr!wsYhomksCID@&i&=pW_td8*#Sr_{(eE#da|((T%DBb-*@*nFJraF%-5Wz4wV0 zZdu)fiIFgZ$eoIlqfeDj&5PtpDJIx+JxKydNAhe-N0Q)X5hNQME4XlQDv;iYFs8;M zj1kqkG6$l;4;O9|(kf6Add0`I#59Ss#Kcevx`f<@ju9uZ|BM6igfW9sd=s9&aSkH~ zf1DNg4YMp~q`vJG{O4Aj^8!gz?6aV8#YQLa1YPKR4P-ld5t^v|Ljv=7=$l1Qinct| z(HQg&`q&v&RFcaBfLiJNrALT|@U#{78tZ*>rt}N`gDX^Bo?)l0%Y-ZTsT_8j^4=*j zy%^RvS<)fqvW@x9_QpA!z0!DBL?H#&@!fdH&)T>(?vr5zBji0=2 zl%FZS0offKE`Q^uSsePyzr2UVZ1f;cS^m6_SwPn7jRS=lA_ z{C%E7bFf)U_LJT+%}%Q_O)+LRiHb)H<-3(zGaBf94}X??6Mtjk!kv11F@1FVof0Y_ zn;O&Qi1`w7vLcPm!2gX}89bK4UXw^c%*U-#qPtRedE3x?DW}|f7u$T!jCBvgQ@q09 z$W%$2&LEw_or`CzK+O-|Z$o6k2wweF-lXZM_AirPk?g{$M6~Jy?Qfs5MKo-B(?69_ zx&%*=-x<29pL}{V%5*LgnnDJ&v%ohJ-*_2JkKpPd#&HY(wf4srqoFr`2r#NLzke%g zw%w+dF+L9#-I+b~iAjEus^aK^(D+mm`1RpX@FS_6#WEh9#!?=gOJ!G<4G-j}j420G z#^=oZRd*Z|E7Uh)zBc-)|BcdX7?C`CJR-TN=Ee(I$~GbXcE8-2s+of{cS|K#`LO`| zN2E@BZ%F#sCf>sU3%$4XKiYQQsrk4Hs{dG0?Yf?xzyfLPMFNN2TJgLo$w%2+ow#s* zDuh*Dpd}5N_d3^jgI^dN_f>=mrx?4ZEbT4Y(*(lVKi=9&O@I10uV*j&B%txE9<*md zq2nLz5}Y}b%Q0@jxM^rP-K+reEJ`Iu1_>q^O+4G|fnr6JDN4~w%)fb8dXYU+S2~k~ zf^-2O*HvG`G^`QF5-f679jn2F^Rex65e$+50NqwU7^c_cN21lS&zY1q3uB4}36cQB ztJT$)rgL4$J)tH?AKBa?BwlEakipy0jntD(!(M0lZzH{8(*@3a+652_5(D&SSay{O z%^m)T8B@i!eoM!`Vxp!;GCzIV1y}WsH8l;=0Z6#68gbYoYIzU;Ak_s49DvNKq8Om- zYB$HeZTc4hCdUCJRL#5ljcJnt0Oq_Zz>)jZfpyGz)r`Zw=mW3U5VB5)APAT}w(R=E zp_3koa9c%lRQ&i66Q_oCW`eY4@M@}JA2U%?Bll)(y5u>?>HyngH{vjIH!$5>_&>1X zm}tSdKIE_<;R+xVV$K?;Qj;9nuY#3gf(#-f^-SmfAj<`BbyV?sIl|<}kp3&SUD859 zQUI{a>Stmi)oGQFgDe1;eNzx4r;24|f(#(7h1HJxkwA5CGV?>4AmJ83;KcP*9RM9d zh6<|^KSzdBvd-cnXH~Fc9Df*9i1CrFYFI%gy)L97KqxdivP=c*%2Xv%5~D6eFk`Y| zR9Jh>bl8vl^eD~STqx1(IfyBL4B0P4&;!g8Em(7eg02E+oydcn>uV309A^`EzzIynylrb=-WvY12zBCd6}A)T>oqq5sO{#16o?tu}@ztR-`_ zMMZ*Dyk!%3y}FUnLO}`ul-ugAjchIwSu7X?1PJ_=U%Skq^D#0|6>G)BHT1M=hokML z)ooy)+PRz%feRq8(>>?;+%$*|0C!*Yoj1MpA7QH4i%d$B|Iw%Ft-zG*zN*BL+k<3c z8g*K|!K85_SKx5MJSIQ}`-W9RPM;ZRZI47ztCwdNApY{U<8yBc_i2 z{~Un@ax86ox&ix*s{fc~k!KtfI20J$Z%U3G6Z0RH9b3dd4rB(oZphbceAh*i0zI1RMu;0EkOrV0gV z0+gLs{W;oV|3`)^Q%C22jwf6M(1wwR_%y6G#}Y-W4|*kf;*v&Mq`Nvcpp@z;lvq{A zT0jjm230H)Lcfssexve9WA{`{x>ViP?Lw=dO}#2s`-`hqnVCB zf1mkG`=m>izH2SX>5)gbU){B~_qY08$I^}^kiUkoV5a0=cqpZ(iu&;C}^4#L=5 z=Pz6*THv)&(4b(l-To*$UiqTZZLzoiHg#q{ca5O+sciYfMKzoYo^=+x=Ih2aUn28; z`43yuH~Qck&1U=^e)K^$4@Rs@y%R9VK8Wo|uT>D^0J`Vu8!x(8=yb%x`zK4c*cu%f z)!ILxcP)Yhk=hrk4A+7L!P9CQv*}%q5yq|AXkPg+j_qLljWNTIn=o(t))b5UW0#BL zfkhSBq|aUL5&29>)AlNgP$$Xl3RRuiuU$5h6}|NN<);0CINxOLmPB;eYij3)DE^+u zZ%G9f6!G$|0nN-ZNPS$}w=kPz^N;pw0M+kjbgkp2U^PyQCGi|$(QzWGVGHjf0b_Le z6LAvPbI0 zk{=^!nxAxRbGzV3h<~bx@)ET7INj1|L}~ZxY2($uFX)Nj7DV<*>88SBWYwCEZPalc z^>xjBSrmDKd`}YWk2dHSs1`B}_GAQTwA~oXEAlp&1C3r^zls%EjQ)Y-Jn`lG*M8MD z(vEv0uOl686Tf*+FKWhwz(iNf-AQP%3c^=Ar851z4P-N?qs%MbKUjsqE@So3&Cc}* z*ac{#wT@Q&7L*l-_$e{=?Mc(Mag@Nez|p~nqc;fSk+VXq0Ni&8ED6L1(T_!*7iCKg z4qv@X-sE>|@>Bd5-G2K5VQ=uuQC?HR#t^O3&nFG8$Q?nwK)fFea=83&BR<}&_?$De zGwdO{nYbRtY*_b3evEPQ_;+Ck5wy|?Gj+eERB(Mj;2XwhwV%85jS&;0SCCXf#i?Vz_;#vT=6uZ_!PsesB8h@AZMtsvv$MnA6c#$2q( z$s@DdhrL`TsBquU8<&0W17Dus@ppza?pf3eS^^gzA)S z#T=v$IQsL0PX}`MXyVu|vQb#))nrmjtBi8sU4#5h|hSBq4bs#W^s1Wu=gN zEUF{?veJ<{!%X0#`fT=M?`4KfBAT1e(?RX|7!T+YPkrUyxAP;kS_JoJ>Xk4$7W2=Q z0%ys-_EYO`)(#Oh)CkBePBO_Nw_4@bRH!NWIl~#K;!B?ke;w6ffr+@wwrylO)(dxP zKbG1P>2h$oLQ#426ZrCjrFbi{=T3{QFl}Z$|G@*W-!_d~wJjQ`_h8&8T$VD&xwZI- zwJn;;F4@$G`Etg(Hr`MGy5dB>7VcN7f3Dl60%atZNhr4PQZ_EpD!1Tb_$;_d7|CtBD>va@F1TQ-DN}vMRI+D?o1S*a`-55 z1ns^^&Oc^*oBw{*h>vU*%9VtT->;z)Fvbl(bqjy13%aehgCrn^%f)cZe$Ti+xPLkR zieV=P?7cMUAQ{jc38s56HX^Z4Ew3dIbVZ~5= z&!d}Fk~n2d})B|Ul-}-nhZ3+o{IT^A5dk&W9BIk1w7ZZ{(Nm-KS zYT@mn>6Q>g><96{6e3A`zq;00@6#TM^(zWAxP{L)ccN(j@k7gZ)Q#sm$Cr#{MC!e* zNkDsjB67`iXY~giN-ENBS3#A7suV{sEGPJP&rlmZ=h4Tfk=Y_fJJmB1eaflm{Es;4 z8#lio5g}Kgkx**QN{Cf(C>M@!x2C`MoR5wyZ1eC1Z22zm8{XE>QT9g%^Sxb4b$qMg zq8(lQ+Qx>8_)}_z1XHl$_4!$*0`%uclkj5a_R5>)BUyhL@+B(j8(WaXg^t{MM>riN zd|IXwt?m@AUH4+0R$Xu{6r9=TNnbxJY4!#qKY*%yS%SDlRqxdMaVkIdsQ4Uk_lvCv z9hvtaJ$Q)nKz^G>zBUMH0eq}$HO9?my-Hr({?Dj#>#*qaX_tiiP?iBJnLo1!X&t*N zE4G=YL?0s8cy(s*XwGr9PK7|uD^iYT=sgKXwAkLrt#M{Rs!TY-iER!MDjP}!NWR6s z@SyRqvkxC9T<<3WHF^7_jbDH=x`~s^4z*ywJyi#Sem0Hb)bS=tCNxl|0)22QiFi+* zJUUmK57VV5bN**WwiD2I+VoUp9jHftTz0YqyongNn!E^&53In~6$0n& z2FUsZVHI4|4OA`jE{zGNn@;Pv`>a)PP*0cXl&Wd|0=%cXH)~OYzkWIOpF17Px<`#x zl~tHH`qpC*Nbyu+XL)#E!mKOoy22jn^;dIdS5l>tTMfb$w*g8`!<`}bOhXfx4Hua9 zgMGpw)fJZ1vNHX1=KCEr}@YTf{Gmp*+^zO&O^v3h=hE9+<8pSLD|~o9SETq*#(~j6O^3|P)sw=Ti8Rwy z=%r@}qClfVm*#H#&gZVr_g33yy{&r1}+=AracE03o%MTB{+euMo_LC z*XixcLFh?_q6l+D#1T+#C!xDFlG>Vrz}(ob6KgD?*t6YWc%l|A%nhhEOY58BoQYG$ z8)J3dfaDANzkniU)Rreeza`E&%)^577d6UZuTBn>>OITllV}!mU~#k0ghev*xDkdg zJo+q?4j6a=*n2L(a-uA@1#d!`#>O6S5V?Qog|i-qzHa^p6k{T_?(}{;$6K}e(ww!<67E(jg)+9pWNljqr@mY!^J-(uSH|K%}By(V~i{)vsZ z{Y;AX=jji!-)jG4R!aMXe|w6=Bj>gc!(_QZ99vS~PlAD5$y?BK%-JaW>Bk5GME zd~zbWo$xk`_HWa;23l%DEg5kF+YYDgpCBR;-)2q7Vi)2I@B4Vr&Ny&JCz(IRPSzY& zjcVRPvVk^L+`~e&d*S1FXnq=baq&X3j^ex=_o%`i`1}d0JIdlvVpxNj#7mG{0K-cn z^)!tsBOfS6+R-J5%TbU8l+m5BZI%-cs+x!1!$r0eQdB)WjEN*~a7iQ3ehCq!N4R?x z{G;F*6ZlJ?J6%OJU6~BTEBYL@L%9F zBx|b%-sdx zWfJGi-la)`-af~%P`{tqwRY*w{NOvbwP-se5sMD<=y<1BT;G44UiSoTOhx-iqVnQR ziJBJ(lnp~x6kiR#5B1bXHBF+f0P&%2^862`^{yV+ga~FBfO-I5!$$i<#~r^h-e36) zbhVK`7(v{HoIRNgqjGG^%jJNrI;qKe@`L4^TeQsDbExPH9$02fydpAI=A`$Dioirj z7&+^72%yzBV7G`u~b?m0wR zu?%fSan-#3tu8y@{5&-M-xyVdWBMiSn2Wal_OC>e?D;ht@rBmX^%+ZI@!gAp!CLq7 zYoLwp0IDo6CGakE1^ZO{bjo}jG9^1nxDid+xS6FF!f;X+Z#wckXcD3$`3CxtU~sX6 ziwGtP4$=rylAi-xUyW6YmY#Ck#GQFN$b0C8BFRFGMAhV>v3eUx5P^$hVdcT+vK6)9 z_&6#^Ua2xu1!A`%Y8Z1|5Z|i*C~t>}tzy45w3v z!wX=LTk>aMLVzIL?7rhg+O*x!$=?-838pM4L}>sd{|t1Wb}02ZK@<3c0s7UcnhsI- zitNZnT3%G6EnKKUxLr!e*?sF&VJDi@N^o~WTn;UNkdbvNpuPXh(5SdC*8q{9??-fo z++4JsG_Q=Hmex|bR9D?cV4r|YYn?S;b~uNm5{T-fubuV&Ye8SvwYzfVP_A1T-e*t& zOzLUq%?jH(bJIO*|8WeU9Ds-)KjZmF>v4b652^0CTL8T|=5Ub$sQHyBDzjG2wb3m7 zY!V?>*x~hCW-QbRy4;~Krcp|H{-#G8nxbcafmlLDs~}!OIBT@7c0;ZjEOB3;uB=U- zpBa2r&Z<3E`z6*NeqEb8l!FoKDSZweRi{o>set5ApGT*{qC1+lu z+ua5Uvb6rd0$RrKsb{)Ovf0V!E!0)FaG{m74V~b@l^=}pL8TdJ$4Ok6oWdABP7ODC z`vkL9+D2dFB*A39w0p(SKtj}9se?%l^fD+DouH6-#cJgz*A7_PM6 zf0|xG65BxPEvs6;0J-0YIVPEec7>3VCJ{$sDgkN(2COal4dz?7U@v(QrGIQknFBu~ z8Z%8v_?tX$9sEu5{~H^4T^b}`A}>llYkzD)vb$OD*_KAEV?AB|^fD#PF_tnzZkeQB z6+E3Nyt|`Q;V1nJ_QH%hof)BgEPFJ|Mm4X=Eb}ZOI^1=%8A%x>!7oq_W=%;`7YhdD zn!lVepILw78V6@V%O(C8aU$2xkI_z0hdily8k0`-bIGHACIU<;<)5csB5idl1scl3 zQnjX>Z}(`&Q^W8FMlXV>WpiY&{-T3v0PUB4A7r9ZF{CF$=|9GBFjDkPj;jk?eD~gd zLWxBpY@I2-#T0n(lV0~3Q`kpP{>TI$}iXH;^qFMY;ZpjiDa@#z(BjEL~NyL&EliIxi z$G5R(J021BdS|heE$?}VpXi^=GEC};WC`NNHf>X(;CZD-PZ7-8)f9Dh>8`=U;aeEtXB5}$P3bs<116hW8OJcSE8q@-zbiF#k>|ek) z;A|h?43jbJ$o$vLM8i`Mv-;k$BC>J7;12X?hmLqAg~3)obse3$4(Pb7M*1gN0g@OV z&8c;6^NQBHjQ0drTIGXfqn!jtQ_r5=;*LFQbzmHXgwMxp?5mN~*{?ck%u|nDYR06; zOh`XgtC7^tc@lF4(7g;}+ND59Pukm4H-utcIn0(WV!+LKd^ocwHN z<@idF#vjld(BTIP%yDb%q^jDU+da@a-<@BGgDi4mGm}0Tqifwl^KogO1m0#^AnnDL zNGL>0?hTn7Q^fX-@&&#SPv~c8OrGD)h1vHGET0`^XG1|e=(fX$t15rr#TeCG^O7s5$LYYMHi z%c((d76j{#Q$S~(1zi;rCTZ}Anu{w} z7Qxk#rz}~}ntRfl;U!xts>861nOTxmI`uRVVX>0=aJxbWr8~N0{u8-mwEGb+bQhR_ zTbFZ^2(-JpjDF7fQ6YWH+1zwYxnE(^b=l+_`9P2J*wSv~pm@XYLSJZ5%7QcPVdu$^ zYYOBmvv+j!8?R5>)sY|KY`=`!x#`muxz~>T9eY464m(g9FRr`$o<#g!_y9PFW?l;q zz2FRLxk!sx9b+KvjagaJ7FG7}^H!#`Ddq_9h^a>7^Ln{k(==*(A+$|;^nA=(>CaxFd)rBChU-T5X=tiZzI)l=vc+CG75F{Ai&6E3K zRjGWA!%8JZ;HyuW#!6JEvWO&Q(T!&2LK#FB9bde64kQ&_9vj9Q;D^k?3f)ML(8u0e z{Tac{{XO^+dZ#;fL0Vs0l-vHmHl6DmMxoX(*OnbzmB<#L=jGvg>l`%1lgDv|+sT~Q zJCqgdSDwRk8X7XVvVVD3o`*FdWg&I3|LCWbb8cLwT<}3FwrBfVYo4D%+%27gck^a% zohCM{qnl;YYkK){&DSNl{)}E5<*Vp;@;Vr!AXUaK%#}xf8hV90$b2QWCb?~SnEmGk$bJx?0Ot?ND z9*Iss>lBJOeLhiOd>eM{FP?{h>C6N`S{Tcp4w!6b%aNm({S#_)hZ6W4JC!^5$JDRf zOgs6w{n1;)KnlONID!5+t@I2b^)}_hBL* z!=AuYGPD95d645T#d8g)g@~@O_3hS@qA#(sL9KBFFZr*hg&p5{adeK{*DqdIdr+uh zs2vB#aG>slEr_b+Lu#NX=dqQt3tY!0B_0NIWnJBjC;M|C=oGjcqfxs(t_li!l z#iOs13|?45m?y^`ws@@BA2eLsN9qI(toMu zPf2#Jk;C>Ut(s1SzlWQ2*Ak2!&U$K*UX7ht=x6oO!#;m}1n!*WoZwxXdFqp|vZNCL zOy1?n9m!vRFVEK>92@*NzU$(3uDPy#9dP5cVN^k)!=!hDlakf##A|YI$DCgV#~iQR zef(YP3uEDh_vM#%>dVT;3&iSGWEtyOe==$h!g%YiTU7XNtnY*>eYog+{C#iml2MUu zO8+aVi=`>G8ae;GlgnLNLIc(xqbt$9-;UfU#N7;IMY?eOk(;t`P|OD@sp>I zo{D?vMeTJvas|E1+yb5}IIoL>|9t}8FOB9#Gi6^mjTZTN+2Vcf&ztENM-TaiT8(0Y zw=AybvRx~`h?hzS7z}%|savKL3#1>G3{h!!y=bF@i~1 z?Ynq>L9mfeLX6=+)%u6f&t50`E-EQV5NPe;^b!4^Y%u56{^q)ON;z4l`K94gdQ?!P zw>>$`0z_|ei>>heEAL-L)ql(7hopyUk)GyNDa=Cv<&LMH<-ByqE1u-*zo>i>kjq43 zSo4R=bhOEHv30&#EsZy@bK;L-3C8JkH~IfZrO7F0#B&UtRgobaO$P=coR6&O)UaZpoWb zJS>IsG2SeSQeg~q51s^RYFyT*j~V6B`+#MQdBqY0rNg9^8EkV(@#$;E+|#-K{;L+x z1ARe8XZjdIZPu3&;?+D-V5SblVBN>`u_L3+`R_LApIa_eQS+iW-l?8Gs&9~ z1(B=VQY>9@JlO^xKer1sULq$)j&teDvE)g;j~y3_64&QudB8&8cnD^pNOE+|;`9Ys zokjouDsee;#RT(Q9@o5V&?fp{p+uy@xSSPYmU(dcw;0w$Sjr@GBfT$n!FZGm2$#Ba ziO-7=Qsij$izRi}V%B*~4X&}TiLqEq{q;5|W_v{+#T`TBxyeH>bu%`ie7H7C+%7vQ zSGR3lyVD@-9I6*qhW`Z$j}BY`S>gi6{$5h<2(&#|3Mj+3!G@}~Rb?Q%rJSe-Y1e#e z?tKqkRXtnk5U{))H+|UpHgL*1NkI<*As|x&&~6QT;kcLc1H6?TST;M<`s`G+`6Ghs z^dN!PX!ois1RZ)%H-6ASGE)ETxGeB+N~5&~4cj9sDl~$hFwcUPEGOp zQEAR0ggiRq+PjtfJJa~ZQpHp4I#6!MakTYxyb?w{bHaZrw^InlEYO_)SNGm@wPWn6 z@1h&n%RhAE0*1s+0$1GGG_Islh~{<^wKLz$qBFn88*%JP+`Qu7y%N7SR;>`yIDK%@ zMHA0%OhET+*PB#=nIR`<`IJzJ%pbX7uYZs*BDgTbswK+T6L_orxV5ieF3@i3)zI|! zKfJQlv*ef7zuZNpyh@nd-|d|Y_6R_g_ATD~9=+-B3x+mFaxb2CMvs5M_esbjaPL60 zF&oH9WB38{14Nxz(eCU|J>9h)taVmStDA;Do;0ldl_p6JL$Fy6Sh?W$O@eTr6ha$+bPp zrm~?k58wIk>=#TIWBM9Mex`Z5w)xx*Pq{s;F@>`OcWFx6R85D!_Mzy&v2epGpbjZ8 zj@|V^TxCnIHMe%kA8=9vZ z^YoqtZ~t11jqnYQu{` zt{#NaWfd}?|5vI#HXz2C5YN|FjYKmGHu#8@+N$<`{7q*~0OdT$a&W8lAIWI1X zv|fd_UMoKyU63t`*O5mA9i**e&M=MNDng158l}@gxxt#BQSW7bI)2OOhGspz6WSF$ zcRD@&*8i#)wv|8KA3{vM+7@mzukL&=v~J4Fix7}V%2OW^w_cvO-PH5(@$agt#OdmH z9k+kok9&b@foUvuC7d>l65pRDM54?qs`H;n`O}yn<3&ZSN=h{qd(+S%dP+749&`!@O;+!#MS|hK^QT{qEAQ(%EE}36VP}mc817y2YtN zCd}C-1x2$K+I-DUt8j)MVvk(1JY7zCR{LzD@{+c)Fcy>aNoXWgvD$XM_urb`VRo{A z5{5X^A6E?v3TglVH>3M|!FuNl8ETe`1h0)ZW)k$MWYN7QaDJz!QR?Ri=*uBQt9uz~ z3$`4deIvmke;jRDhQD)z6w(=OvTQ@v?ARKHkY>0)vLs4Knqj3e!RAU78eiyAkp^T%lsFry)rDe@x=X+C;dS(4`7*0&6AjkDB!WrUi*x}h24IQbnAY~%&(2-itmS#In&-xB8 z32Rj>>qxx}o-oU_3D0l2D%G&|2D6*Fo4kL#?_2gF6GC=fOXR`a9u8?d-*YUdgp#>r z#eP5aYO>T`-&&fNCbfy2tflNMSB<>=b3nuw-zMRR54Qtr7bD)8>AePO>`t72|Gj*f zT(rBQ>|)+HDsJ>MY1@xTt`RbP+-y7e)9T!f#wMMj*{caeTR> z6~7~5@4$!|Sd=3wOnrh-;5LZtiXXgxLQXTd{CzN?&p=m6*K-#)V?+|bW!cnXqJ2`Y>zy?R z?C)LRHeXIG7DO_QzUEVy!wqZ!T74xdw z1i?LYYhn^zMDep-#4p$CF##S@gD?bl+HSxk!dd8h!w{r9L6W|iE@@)5c z86A5T8jkoC+??gCpefU%nNLih<}`GVJ)M3(jTc=~`?$B#WUNhE!aGuLBdR72QHYqu zYU#RB!=wd~>9+xsUe$d*;_VN#JgpGUgnr`hjRj$5-CK)$@9_VCnw8&EenAI*SlXFW z^-fJYuu$QHaf$}yZ$RtrXfig^nkb5S(H?$Ko}*{Jf4DM4A%3jPdGLPM0^Hecx(s{m2|6Uo zoF0Q7XSGYSuwN0tg(mdoM2WAGgDkvg|9e-!!9zhp%0{oh(vwgH%ZR?ao zRdnEgxb5VD4NzY-JDL|YoC`%jV^wAGz}yKnr?KyTXnb1R*z{|vEi4P4OnnwS5^qW0ocO(YHmustzdXg$=$xu?*_v`Qwn<{RpOD zXr?5RtqMu{J=`7`vah@TE7S-Nl^~3e%BggYjULeBI#}EbJu)Sy1lo!Lk>{88Y6mVIy8F_NzH-tR(#@qTkznz8V zlQdOdk!o*u_gCglB8XMr@4#n_S*T}(rcG(Iqtb2F>9LU7f5YY?qT}Hw!;i)i1oY6? zg92;dE2ogZ8^yNQ_l5MlmVYVQ3Os8GYY0!$+kN#5lkxlQ9z=KN;H!0>V+l=H(PMO9 z>MCCNcd32*Wvs!_x=UxLBH};`W3s)k)ZU^fWaU1vB@w7(iu?J?fzM9u{bA2j(plo0_S7@=tXu91G94@W{a(>sjdCh4*(oGKCz_~*Bw?*vF zd+Oi#A|&~aZ#S(G@TeLJ*>xBT!N&)11ns%@72qc`m)^YncSS)0b?os94Tpsq`42t& z8)DiU&ADi!le6Qnw=WJWS+48Pdk%W9Y!u2a z6JbAB5U4g;ciJHtJ>DvguB{dCkyv(gjw5kE;r(m0p!1~N7SAzdqp5cEjq!|A;a0cG z#RV5`t;Cat8x>mWI+T7rqfwpgao>rGoK&z@>(c6BK0FXi{<(lYS=RoObSKQcJO7mM z1(Wd%^6n^2v(OGT^N7%L-rv3(BnFv(|KRSruS=l+#4v16;(ItbjLd)aLDZK14vL!%+TW#+#-iOUZud)tNh z-9PH&29i5|dE|q}EsN%nNcB*KDkaLrxgJ4mR#=->UB4R?{D4HC5`dEY?XZ%s>2;X?zNZVMpcUiemF3H4(D!c4m} zsVhQVgK&ufn$SET?KphY#2IhdRniaBChiD=&N4hB@>GR|(+6R&=;tR*G9>31;B&11 zzQWW*m1=qO=}!NRQ!M^{!{08$Fn{7$@ikRE0_AhOmLeS?0cvly>vLJctgn<^{o6?z z4j|-R8}7HA|6PROlcb2IDeEtGupyZ55{&ceD&H<~>oRd)_hID1;9}p-#NOwx z>1B5{NkCZE1YY253GJ-ME6i=hYj{$`B9o8C(rh;d&;*a2bC|&g`oN4A6SmUdzkRuS z>jgNyLhmrPad36;&AJf}jku~Ow7UCV`7nrEG+CdKJ?szGVAKGTee!$YB ztcM2V4>Mtf;K=o_EQq6a*({#MZ>|ud=7RTO^k=j_)gmnE&)3q)_wB}fJ)pbW1sUW! zQKFX5l8)JK%^vqKOHm8q%oLGdZ`K!s^-mxXP5k3a5jX(+NXYo4cAQ4%dUU%4EcM>% zBAkuNsPFiE7bwKBLpa}bVgae1Ryz}-QCuP1Lus+6#q~FcVxt4Q%Sd%OV^Vro`)i%3 z$yf-V&Vmp66Nn>R8UN}mVbXV7TS&$eAxC^&uymI|kxExMbvWE;3rYGj)c_q7P#jKFicp?z3I3=7B%La1zKT zTKu!{&$hhSRc(!_*HpI%qhiF@$vfhx=>)x3Y{l?Pz~7Rjuq13=z^OvNW!t^KMu~w6 z6SM>f&2YQ%+vWtbo%rliQ#;2+-p%m9azrTBVCic+v`&T`+@d*lJDu7RAVC3l(@4| z9~;(&`QRPoYPpe|D56ncu`18ciCRCOeV_0ca{hJS6_tdo@T3Ms-GtAywJeJgk!DR5 zw&SWvvY17OKnz!H!`9>pfG?l@-g$A5n{1UG4~+%;%q{i`lrDjp_AwfHwvO zROh~TdR1#Y*cc&TPP5QEkp&3jcf2|>Xl*^T-u-D%Gb66GKe-RQ zm8`)|*U!V`*o~ZGE94B*e5_xa*DZ;~Cxt{%6NkRE>di=84~ zeGp$!1RgQ8OJyHmo-g~}6rUL3aG4_4)YtkQbOU~HV^FsG$NnNq?2#MUG1mlxG+p{r9ayG->!#$Gb2kZv8~Qh4!ra zpUqfiW$ibvnTtwr$(k+HSYD?Y_m$(1&mN^?$Y1ac!>j{Oh zJ4p2tMV6=hu}*~JdmK(-^GMH?x8o&gURv9Pq8?~*Lfu|G)jr!zF_=?Ymb;9ZvTIY8 zhq+>Zx{%Z3-xHs32j+CmNPEb1j9aQ&G+;P`S%770!2t2*I(2QMcbi z&VGXGNxtQJ+3~kxqrUz&uCpf-pJF|u7xSm3Ze1PDvn3*qi|gby2`_N>pOKS%JPx`o z9`t=k_(mib2FDXSgHg(xbn&MewJ0gA8wp=u>QXH0F@c!2Z(6zpyRUvR<$q7xlP$eQ z=HCzA^MnhZRu4vfCs#xg5k+>Bj}HW}ltF9Oaig@H@&X5*$Fq>Q`J+LeoR*e8kpUtT(-s#6=KC5wxb%B3MX1_q<5-)!8BHw=ckk4_!wj#x zHiDR+q&;^IVC|?c>4KfZ4Bz%*_s?U!rScsjvqB}_F}ZhFG^zYZ=f=x|fm)t56TNEp zs0D<$1?PBj%M`9j*FRy#x?6Tedx>ROJpa;)V@iE9#VH(YRD1D|)fh+Jc)T6@Og(+_ ztsn<~q$KW2D%}iZkGd&8aSk~9-7*INutXTE)1DRn>Du4eho1zxTn9CYxEytspEUVo z+?x^!I)`&8-TTodbQ&3@C){QZ%-bLI-ZQ$shvHZCa=cQi;@I@WoE*Gp%U4hC9N|q- z`bE6ZdIg9ceElp(lqg_5x-Ra={b?X&+oQUDDS;O+Ec1lE&;u^mnb4gw^grH(siZ9U zS4VGq<9z#6P5N67;v)BJi`gih`^acH;e6JWc^}`;aemy0F9)XI4&U!KAno3U?#+%i z^Z4L;ho;;EHK+}|JwL8X`t=X}|5NtDQRt`;44JpQg#^CZ{!U80X|r=}&-r{;lDa|r z7QYSq`@VS_8NmN^`*0NBY0esSNmS}Ty3qSG;6!X|P^F)@{8%~4I$p4IoMi_8iM?j> z)A7SM{I==8r3}o(T_ka6!HD1osUqP39-*K^b_qQ~-FL=?2qaVZP+YGJeW{yQ?I15f z$4l_t(eh_V@-KpYZZwkP<8Bwqm#TKk{>-N9bN^pG5dkOQh$wo}}~hCBR*R*tZc zs&i{AS!Ro&@WsNK2oD2~*xxM*N=ghpr;YZEG2S0c%c*87?dPV8P^FiSU2whJ8)g%Y zStun2zo=h6x|5@EDg=qU&lLaljgE zrZoiK9K|<_oIwXyy=!ck9l12=mfv{IEYN4mex>d3<~H(cGXEyE(}KMGQ6b^V!f0g1 z+MRMt>`PbexB}#U)R61ix9TF5lPpd;Vt$aZ^D9{|ZZiGIbY7fHO3K887`9Sg1JBCD zpf|Z&hN-a14!x0SkG0R)uR+EjJcE=nNJ>vaH@{h21h_2}-#eydElH4;+?Mbn@c9>c zs{u-n5#`7lsbS#|18IJ3@JHgm z%zlMWgS%^meX+=5YsjF(DD>4(ojLyZgAgv7ekrk^fi4bUL?_Cr1B>s(EJ`f0K!THF z5YTGD@#YCNns03PI3!NZCaHm-L*QiwNk4J=heuo$%c_Gc0(g}tA`c}O%~O_*sD>PY zSK3PUF>Y6=W2)JT6FLDV2BZE2O?)FNCK)SjLUEud#vpypv6-pLjvLAv9Oa|X1wI4O z%eMkdO&CD&i6Q3}K&jEMD_lnqqs4pJ_?1Wn=?*^a>={DD5ityj$yZ0lO^NiUtW+^a zxC|_W0D_yc`KS6>EHpNpw_yZHnOf2A{F!3LaVL5YM@957;2#U%g z=^*X`wTn~2dd|^HUu!^^Ze{3Evj>L^#?#o!xA-MNMD6%x-HD=ttJu*_1A0-OUCB2D zkVA?TmIJQ2$E2pq*d#u4dKG)@_A5rKgzuqBMH zgU}v$8!1~@xXct*)cLq-#MY8wb5q89>;@-s=6a^re`=rbG6kB&VTUY47HUYJ$Jwa8 zs}dr|X)wy;EdK0dTiwG~|9s>R=ck9W$*5|#nAV#k-~QUvrYUBI`{gd4sio21rza8@ z3*d_p9t9gMIt5bmCSFmd<}yIFu%-LN#7WiMUlwu#2;im_Z=mgM`+m31%Pt;MB@b%x zrNV~kKTWt~O}y%vT0GHjA`zmHUg1dXWCT{h#m_F}Ojunj#aQ&^k<1y8FfY}?^WZ-Z zsr*uFos+?Z$n_v63p8|*lQytQUNi~QRCjK|js`cEwJBmoga3lhlA9Qz>Xi&NW7I-( zD6XEERFTt#vN6tTcPw&Sggs#{)ty-EMeX;#B3M02CYq4|1-L}#KZIw1s54+ zG&}VA zH&WcDKlEL*m*platB5e8(M8y%4FAd6p@az=t-pv+zNj_B^SFg8?CITj{AU@g8UBD{-dVw*iM~3LvP(@9;a~Hsa6Q_11t(=E?J3!(av81 z`E}V0z2RUgAH_kaKJi~{Gkytjc(Ek$iJWXLy>!E6Ne2CqARIi*FeZbnjHt!%RSj}z ze#@fe(IQ!wrx|lN2^+>3oIj~VlkkrQn$MACp%8lYh%4&26HWRx$tNuZH;znC+aKzv znJaRg+Dk2Kmz<@RY{JVHL(RX*%aEX>ZybMI z|2wkfdKk8sAq}kslSH74)2K0NOJ#f;D{=2oZ;h-lji;7fru#t>iZ3exyvgqbFV#tDQTdGunl|#Sj$GS0+T2pIuDVQo&U~NJ4JakP#t98sls~r6^2?rNf(vnQ9Ybu{# z8|>0qp_Wc^Kw+2x78>-*_W(G2t}^{mWAqodNJY6(ccz>q5d(j{OC_Fy?C9sZ_9YXg zwQZP+#)JG@`=CFTyI@hqpiK+RaC&QFyy%0I(jaq28AWb}*=Lm){1F2VN$*i}$9}j! zC9%hv9?9ma$MM|<`v7zSz;aab7*kQD+d{W^^k!2jk5OL4I3gok>S9~?VR>Roj>PHo z%6+ZS*ms%GVM$8YbPm4bBkvfo&8RPlzaY7u-JYvbfElJa?3Ee`x=K--yM;AvnX!pX z2a5v-!}830;U&&ygPv>(&HUzo)xDtYkdbQiEcr>g$9o&q9-5kJbH=Jf^KXtx%(*JFR)oliExom;Y#vVP4$V}c-1+A3L`$;qWg$fHjK(h-(C-Rvf(=&>3QE)E&xJz`pU+l3L|GODs&WQ`Us_^v zgj0DI!M4wZ${v$%XMkOAlQR{YP&-4+%GGS8%>bX6thW0CJN%05remU>Nzcb*#v`R) z90^(vi{!SdYkk=R@Y+Zvrfw{=^JjeEBTYV-Zw@WtD`(0-@>T&*__doF&1DU9$;I4% zBBRjq;6@?e;BdtT<^ULzR+x!N@HG$`GFP&SK{`fMaL!d>I!{$TF(d^jSpP}>i+Yk# zB7z6r6|8KafzG@s>(pR6h|x3`3WLiky1UYIj6-u+m$`O+9oKd^%vexM&f66~%2?kw z$#%Htj%a4(mi}N|rQ7`PL7X^3Ifk7lXxcTnCFt-%!YsmX@5I$`n_EEu%d5V-^4QBq zJ)M;>oVUT*sIExxq$h}L_NamREUgzpYw1XfJ|jl?C*`ZA4PpTHCZM&!EtruND$J9T zvLQX!_}4_un*E*^8FCLGslY6Dcw(iU7T9k>q;6Q#`k$VoYq~OG?ViI%fgebv*&f53A9$FPyx?0}{h_-DN8AA=9Yu`T*={+b!h8m1_s-PVZ=#EgO zDSHH+-D7HpaSFOr-{JMjyw-c;9%-e?$@i1nz`HEG-#g#VBAkaERX_1iqxceg$JEJD zh@7w3(a!CL2>s0@yaUep5@rrUFmLXu;bvPJb=)_?JYpGNihGy-anNn#=7VefK6|7m zvJmoZx}mG%QLpK@hv#E` zQSuk6n@z&HQLjoNs*CUw!&>vwJxr4MesKD!e)B(MHRT z>9=gea`Mpy+MV2?LE*{F>_;~JzX|KmCgst% zj7Hz$CFGNGoZyG#-UqEI&1qltE(-7|b(hc*pu}k@#UbqTSKXb!g)QyyUB_>WOiwfOm z{E|xU-#&kuhjr{UN9%B2e}JXa@r9LjsZ{S$Wx%4{hk>Qtw@bF;1=J0&z7knZ{Tmg< zyP_cq;bwo0+=l&!f?CS^dUk_)2FlpciSKX*AK3rnH6-nm$KS+_@CmdHJ8}mBPJNQP6s^3h&Eezn;GH3ZAPO!hvOzg&R!vY&Z#x zKLSRgLci(bjlu{zBMrX8gRf}jI{nx_BYm}~V}+!S!N^Fc3G-P*Zl3bo2J!ko1J`&K zIv}>`>|i4t<21V>`sP`1#irbXKPHI=qATu(`fH3mv1uANhAc4E_RZOKN=_o%q|W_V zzNXpsnI^c6Xm$vNXe;jgobk=~NW163ZBU^r7y1YqcMMIoU7WHux=QlypffsF`SDA~!L}?|PC_9%L|P$T0|= zekWd3fi}*tP~9%(WMR-W!{mJ|3^NRnu_`Va5HIQB&ujQGbwUO1y)*cWNVSiFlt2tw z%F_s2RThTD&kMDBpU6M23q1U(RMDr9I1(z!zNTS^xU8B5O-@X!w@*8KBiiOu{XoWD z)+ZU;n7FW2N*c#&74C&G6&$0IqoQ28IED3(NgKjiUShUcBUWzh$9{?Oxs5%dxpX$m zVEScF$zx}U#(o_8%c}k^*zUjA>lE>ELY1r5p+UwhE~svp1v?1LSv2Tw$%OFu26csT z-iRv9su5zQ!Zj!y28EB}I!DgsXB-JvQ_gO5xIFF+6S5aY1VRr0i(x_Kd=vKOPx(Ke zlux=*Cv^TeW!q%F*I2@-8Hrg?{H8wo#=W~5Hm;JpL)3lX;H1GW4s#Yls1#hP>> zHJ7xr0b(Z5ONhE!A$y^3$jTFJ1PIP%$25QB}EQN;yh2b{(<`?rhTzPyhm~1(# z3l9i7ZzU~3O7^1-yKl6K9Dc^swNdfCmlc|kTuW8vb^ z;|5}Nk*~%)Aneyn*lzq{^&j;}!Vd`ajCuKN?W&`xjtBzuBj( zXM1?=JGJMU0MZ=2uE(*8Id^<7j4LR=%d_6gFBLZ$MxO7q2`tKNpr{Z%&yp#n9P56b z%Wt^ZxCBD>8L-XiYKbXIA>pTW#AfxX`yT} zx%I|yv6)z(f7Dmz3U`Y;P>#>AZc78)o~z{g%GPZq4rKfcC5Jv+v={pu)KZK}FaOqX z+kUh(G(Gj|?HFuv_e*y-tn2}P16LVRVnTglMlDW|w1|DY$aoIZ!44I<{K8}imzjvj znzG`Epvc#)XgZSvi+Y){fBm`({Igahgd?M(eHJc2v^l0kJ2tqq5yQlrX|Z(C_wTdfQ_Gl zV`_qc9&I6&CJ6*Gx>@eTu(?bQQ5~r<`}EGdOB$K)g!gRTw7&4wIU^>eQONocB1MsPISf>vo^KCM`?NREgh@Cl%7 zPL9i>f0Gnt^c%wZLtMm5u!P(;lvf)txLD4+yJRoaO(#fz9d(K9{}XKezY=O4aBB;< zSE5)J=q|FJr=Vr(zxF2`M_dO<5Ps)k(clhXf~bdgO0an5&;*3{03;a}(*L}K!+$~a z!Glwj>{1C(54->flYQaW{f{}pWO!hBMWe#q{c)S+SYLYKNvCYgW!p0I)<(CXgmy*S zqe%=!^t(QUI)>UQF+vd!H2fN~Civ*e-BD!Dn(E+T)SHYjF^+O~5kzmO#*swF-!a@?MK!X4I z1@j1lq8rYrG39CZI&Dd%A~vJ?Lz~=Op_>3bgIj!pE1_A}l^pcsIs>CLk0hVoT-+DN zpZ`$@ZYU}_WzFpt*59YSUOt6g5g136%^|*aS`?JXQkpgMFYqy9*heqwI(D`l%`3v3 zhE0I+tGdKfR5oF7IN;DSNT`;Z8(G55db8Orxif*>Rj6KWGreYd_mlnCJBk8UMZ5`O229Fotl6mSP7dikf3P!^kx!b4H-X zFSfj>S&fcyAOq5G{~S{oC{I1(k%vm^Kx&VsRDoyXy|@=Z9%3LamHG=)JHTgJ(LnvO z9%kM4ErC3}^AWZeOT#CH+V-1YKc~0?=-f3)ws}bCM6)p=$jh=k^WZMsKlMm-P4BlJ zrcyo4Iy!NCE_tTzktMB<_&XrzP9cDvMFyR1F!ThAQFTu3K3)x@NmLxxRVhQfPZjf= zf_Er4EA*x))u8#EZyx(r4SQ3@G1t^{@t5zPjQu=P{rZhg4W}bq{5{U~D+2~t&|bdv zY4&w7hj%2i9xi?s*0>-+Ql%w{EG6g<2#mY-G}S?HrNMvYJ>a=j&S2J?gafu-kbJ&< z;JItOLCgPOT&#M*b2q{wnpx@WN3IlWJX-J^-qNL;=WwzvD0uZ2khRu3*?`FPZl=Gi zJ10gbNr|%3DYciEGHsPgs`)DH7EG*%3>gH;_3u7As^gH*;arB$kv}PtT>K8G^ebiL zASu^0;k&R(J0|Adjjn50UgS&EV1*DozHzcpN z*vs5^WjM#)z9tV40Y*mgMksOLXl2dz!9khu_;+>$A6ORV zNs#eR)SAK=x>Rh@;PBHcK?GscO`tG`0~etK8gf=L z7zedbau!z+AqO|Ogh?&O54qP%153Ug*)`cyd`GDc7y77y&f<&4o7#`O9 z+HWoQkc1*5G&W@&2zc*Qv1o@se-@QPP1>O;)rRC2k_=a-VD|6=e$vb#WiEvd6aj-8l1y$;qDB-x4RFkPWt}V+h?BpqtyrIp zT2>eXw=$SG+HVw)H3G<4p|5T(+Tn5kLv*^my?yBQVDTS>IQIP=Q@_;vOUQNNMI|SY z`~ywxDK~-zPMY;WhP4X~XcqW!h5%?j6JH-3`H-|OU_&CAX zgZzUa@FN@Xfc0_Q7$@|0V+HLgdCyZnWa+pWqRkA}i}v*m7+^;#@`SF>L<*n$;>gPO zc)gCb?|W6|Al%<1U}Efd0fj)9ZEuikY|7BUrCgW*_lz|!61gfNXh^>&@iBtm@?Q^Z zsNBO`TRz)K#$x^x2^-CPjlr*AKgA+PT`3~lx$E9VINX2XVCFjiBwogU)RaYlexum)2ZRWjquixuXuY1`pQB|zxB%v(|UCSoA ztRgIEjr4K#19g@4dZJj5i0Apb&FF@GwF`fCc0%36iFke$?Bw^5WjIydsat_lOqwCa zX<}1L)fP`l%820H5xxPn!65)gTOV1v!bK)L542P#xZbX)-#Rox8f26o!GUPOef(ta z3>n_}HJvc~34$}-*7hXU*@z1K+>TB~lR6rPcDWhO|Mt>vW877|k0mxNU1dFGd8cJ! zBj@r~W4Z^k(VoI&owp@{5{cC0l(Z_W42QZ`v-eQWO^n6K;_AxXda02An%*T#f8i#b zRABg(B_}tJ=tKd{lD?m}p33qm?EXD`EufL&B0N*$9S?N;NSw&^3 zIB3{}EP>?u#!}%Dxo;_?Gij23iI@hhx6E1K1Cf=fr(*1n$53~reYXUotOHb&1mhT< za;h1ARppkz$4n_qiHE}aag7QfsvSaRmH*@OR=Bo(Si_X+_nqq93icm4!RJBf#6P=V zswITcllw0!At{}LRELFKJFDSJ&Z!UFn?=uTW3>ZfLE#gD_yoqg;Cd4Ci;7PXeh0^$x2ChL0Cqk1br^)!mN>yKxH= z&yx=Rgq=$q^@{4K9aHnE&L|#fdr~_XD!)9m2AI8iyPm8dwEups|M$#rAlXIjWy;G7 zYs~eV!QA$INTH+k2E)n-Gvh(2{VOAqzUfZL-eYiHD%9Xdwm~F~UPmcIcjLn8n2l7q z6!61DR`-iS%RsR^Mwi`6<|94hgF;KOmG(Qm*{m8JEMHe^s)P?GEshD9X51@cG8clt z<2b8?e2>YP=|E)bUaE+4S*WDcY>LA7(~0Zu-5n|PR_s0p<#j>sFRd%lRJ!{ic3u>M$vM*_FpGV)o4 zHw>srQN10%WMTK!rq$0kcin0F*Gk-ZkX=(tH({)xfn@MS{Up^{wySOC8tO-7veDzJ z7klS#eiENv)DxLVNF*ZWl#Az7bK+AU|1_L=Hk#>#62)PfZhf*(SX*mg5X>3^+L5^a z#!y9h42G|5V_)(p#=4MCmeNstY(C4O;l}#gZ$F|o#is0Jyfv!$@dzopnzF>%>i+x;H)-oC7 zd~jw+04)$#acxK-RRgrr7H+sS4y`p>%r;gXF@`n}u9HKkN>)%5$qEGj)pz@5ggVh# z$r8}%>zwEfdr58C-~KFASoVxC+tBwfLOygORW%#C?0si4M#bGYaHSN zfolg*44KaF7ar6C-M7ae!+F-`Nq;+A!L+}Jl7WdmWsEk*a_}-mKP(kBZ~tqL+W)HRodnMQ}ZEZkHAYdE~%K2J!O@>w}ne56TDLQgVDh4 zV|`enxO}SeLA4ceznq@`47sVh{a(vb?a2aG>>;+~Zz zel6k0f6o7UdiMX28zU$3x7ozc<5G#AeqwMpk*3`|7l`P!PtBk*=NYBVu(0-{8PR#1 zCM5m>5BzbxZr@~zk$RNj^9$b)OvEujcT%b>vE3EAbxR5wSNTGF ztZ*I?bXH{*k+tWTp|rzP@jv!-gV)OnA#3)h;umUvt7i86tSp`d3F{icJ1d%G=!5>_mted<_KDU)kNk~=`3Td^OFT+`Rw|SA=z_Xu7n(8 zEk_=l`$UIEq*h14x_8IF0ZJZI%B7Xh~rWT|0lI7b8 zR(iy$->I+p(9NNUH11QKD-JbF7tfBsLLW*ED&mocL~rf=hHk7}IJZELx|X3_9L zNcFoM2`Am^IMu*vm!*5w5Ie~zK&3;isrxDy3gMjL2Cmb@^i|1Z8JCWCdkH2f3$d$} zneoUMy2(u9M)*m4>=yT70pHGm(+r|-+NrhWChe|MB{^q~Kuf*+rtg}H;#oM|7J9@c^ko6tSvcxC zd|bx5Z${`Fxlm3Y)*&gO6Y}e!Yx-;PEIGuPSiv8P$$P`0o3}WJ3v!;m+b7$76V2nZ zf$*aE;w)bzQ-LY;?m+(TtKhy0kE9xoWJ^OY^w@|a4ee*UI_B%8_01&~Z!;V_4_S5% zn(&S$_bKR`(Y*i8mm8<&CaJTtGp1hT33f9K{!Mc=v!*q?IPCW! zd+vvr;HFY1SsZrS)U9QVJn(l}vD#zPXl-WTad~O3(F}`pifK$u)$!f!?wxtoSIKxO z|I17{Yj^1kD<$4TSPdbq<{13vgNB%VKUx|+E){qYmOCcpUeL8O0{wrwbl#=`y6o~D zBaa$AD}*QBr9yF5KRB(z#|<FqjtRsdfo3B?fdF< zk)9ABvY(i@@nw*>)zsV+Q9Ev~%(uhsBvi3VZ9B5mRE8R=<@R z48RcnC*4A7hyTPhflJ~*^=PTuu2|V&D{78gUDv7d$gWbQ zSu>5L*FRVmmJ@!LmsW<)&drT%$9nhmN!fba>*X42+L$f7otAr4WyQd+=h+c=c#e3d z{g5XP3H)Hi$fu*0g+GIij4HOckO2H(pyy}`t5T;}m4o9OrSrlDtkyBHphVhzP>oc! zCfQxDE7mPmuEv?#wMu`AF#PJNylD--_+c&LVOUpK?~CAsyZz|0$L5hIrLmp|{Xycy zIAj#Eh3d&BZ|Dhjhqs*(c^T9^+&b`0k{f!O0KNq_KbRNcHsl}K=;7i#+zS^mv%dPG zz0M7`Hs}wXdkR~5nLqj{*P%^M;>5je)uHa_T|ZHe45`FJ&2I4?U+kKnku6p|{^>mE_@AiHZ1dUxcUI4&Bms5yMp( zv+6QGTvmA*UUNxTa+eE``1mi##={WMrCd`l@#zPbjk)5Hvf?4J;&EPy`|7N@K3cTm z6|K6iq`6LAb1CXi#DEf2Q6!9>Qd+N|z7ASxA`YijHRM$@zP?u~ zVBRGZ_XpW)HU%+%vM3LnijBi-M?CGtWYF%nRyMCwSb(>S|EYobAjNjk#|p(`L0lzS zq*BF+)Ywtg*f7=9$iu!P9B2+Q41xuFfoucc z1V;rYfl37v&{*^s2iK=_OfA2W7*N?)9^x)~C52ooxljhrzf4i{M3{BZ)UYr_tkxtz z)0NS5NATVNBVv4ewX*ON$VWvHjY12^%*I|6TMa0Vs`W)U-y^E56G(7%h|otQkO}@a zvrya7+xH`8>2CFhe8ksX2b1gl!`gdezF(leJq`&ujjOv3{)3bvFb6zORvoctK5|^t zd7}*}b-K+v$e``VopFR;{RLyUhw9+RyqXZ@e5;EyL`K(6wOFFqcV<`G2&aL*rw%3J z&4$>bht}Pn_&b*U8_{j+%7Xd92JkQB%A7}k%1Z(%rJeHt*X+2n&F;JHQ1=KhZA_(= zRlV2#a;NA57>9E=*w&W)ywX;%JqVa z3Zs6fLZ8oHs=Z(CsXo2bYQ0~0L%b9prP94$V2663hbPZl58rPa_x54i8bfcR{q!ZNXNqf5Um=oM-O`65fDqvv&-;z#gCs_QJN4IYp_3r}`-?AM zg|e0f=>V>I$Whvh_~C`$i)*M({A0ba9o;l%(3jihI?P`5Pr!a4{2SWDTRVNAsp_Tu zFy;C;-k9)hgO$WDwl(=X=&?SUR~&OKKm+HR^d0gT6`&hWK%p^-opummYz~vjIu;qs zU@SA+1lgPbpnw-c)sgy}4v@fxqvXPG&JIOt#T36!GS&j68B2|(!I>`W!fh@GRba{# zwx1HKMD|J=TZZYE{@WJndq4+fP#Sv~-7l6Ma?qHQC#M2ehh^_Ev$gYEe5x%*0qB7??a zUr@}Tk{cvy69xNwnpaGNTG(zF224$lMB-nN;L~J*fOb$T=g<%M_>d2H8qj-a?iljd z#^_P>ZB!uUHZ1VbYoeeK4v6Uo@jzRt{u>_Zk~|Q=D*gpk5b*(jW1%Q>N5jpDCWr*Y z6f8FDgc^@=AQ^lCje9Hc1r=Ch<_)C)`hW^*A43+HkMcmvhyHN-1X7W*{i7S?OIpR4 zQTts1w_9OW14m-+z&&3OtqVtD=|DXAMNvb`r(;0~A29L<2cS~(M+*>WRvT=BXf6Pk zZ&I7I9}#;^{mO2x1f?B$1vV(c@hdVz+ady<1Z3A2?UBk|?0_EJ7yiTPbG20ke7x50 zdH8&gpI=6!eKa~%W?Dx53?TB5GSJ++LkLVCQ?k(xsw{rPcaeS54fKQTrJg7-Ap{LW z8cFloJ5UVYR`QMcLGW2%f(uf*f$*dS;o2|y1tkCiq@d^=pEM4{5{?@^(&?MBitA3(flKM6D*uCI1uxSv55ju0qV;ToQBaOWq}Q~3QlL+N=9vF3H1o#iaH^>AZ zgfT9I*2rU(84aKg)Cm?unZ4-R=zTBl8uC9yW(oiA`kg1JiUnkwwT1(?Sl$E^6sHD= zI-MY`90;pfhPJR%R1oJBO^~55i@xEdK?ENMT{4;fm7r_91%e+QLO{`_a3UUE5o8W1 z0(ykW0*wklBUnrnWWa)eqCA>Eh5%v`A%g@Sh}i@Fa0-eBUm36un2=LJxomazGs_UG~ljL>+LDINI?97b1Z0 z4W1}R_k#vm38IY`BFOOILrRABg*$^uiNI>5C5&jh!R3Q({HyVvc->x$ohwsv;4cjNe7LdAQ znJ9P%8RG_${~_EBD)~VrVc|FY94P4KKp8}stnm@*HsqrL{G)SV1*#o{@hzxo7Ze&F z&`%|=mNRJ; z%@5_XU>}dWhWeER)Cn7eXiTDr826jVpvdqSr4AVI(GLUxBFLsZyl?mu5XiKVpa?Pp zH53PBJ@f}!8xW#%Agpmf?G!+MmV?NH3yO6=IMB$R48OA1QO5!SWgv6lK=^Y?SyAi2 z05Q2hsiHOrga#-p)`ow;Yl(j?TB!VQ_-I9mMxqDW4y*@S9S|l4C?ElKFo5_}X;dD? zfcpW;Kx5Uq7=tn(x+H)+^wTvt&rQfyqI`t`nOy)f1DU~!?3EY9`MrTJ%E+iuK|qNH zC~P=2ufPHQIJzW*2%tJQNh=CI%~^SPVGt7xVj7p#LM@b& zFslT|8AgWLN6D)}him@$P|Q9%B%bA~jCX@L9+0Kpz3*8-g5Df_{;x!DAy>$9q3hhf zZDoE))lurbx=-v)T+uqBRaq|`ufVJuEWWKiSpT+zSlXgND_KFm??1$ORyum-D!s8i zmjxIGW!eg+?pT)$Jjrdp;37RE!bm{~XA=(;?> zpil)BeU21exUSY_$ymIUxrT+guCiKkq(%OV z9`#!MXn{6UiIJ75wtnS7TX|ar_NfIt7)zOuJ~mB^T~MUY>uyv0bw&rN3Cr^#7Qqe zDyof-lp>A2W?Ft~Ml%tMp{jAghR6P|_uKwYH;=*XYWZU6y&p0K#|=WgU)|MlY12n} zBzo$7y80$u>9(_)$Jp3o6pjJ(j>x)WYHG_)`E36!9X-(lp~Ixc4hguHie2m8&oa}U zAtj7jIr3B!G&FEi)3JoLN{{&AD>YZsEO#^Qv@AL76oBn0Eg$iOj+&k6+3c2arSq(s zF0fOiQjxG<8mLifiJFH!!P7Nax44fj8_|MOh&a@X3F$0O3+b%vS~wZ$tV-o%o8t!x zWODkY1`@Y2TJs9x_#6+nqBe}L9`kxH$N_Sj9JdjRE$ucTbX|XOprlz?=)0S{ONAZe zur>h?4{CKi&>V6s3SjI**+xI@atX0;WvhR9B>Rb9AuM(mkJLk9Z(h5Xl^#iKB(NOM zZ<#<~7RfKs!<$@CsTl7UQJ+*9X*8?->=!L1Wi|f6PomdV+2bl$b#qjm&A@|->JH>U zJab;%EOsqf@|V?Yy5eX?A0D3X&Bf?VFz>zYKEvHiWbnOMakUKX#KQPcy(B4dojSoo zjH8~qf1aLHM|sZheGm%`tQa&f)H~i1vX2eZ^Zt&n)hX;KYN!!JkWQBn6vAwuN~Q*C zN+$;c&Il)7KdoJVl%DEC_`x5YXlH%g+5TBwQfeboSoDT|pWH=@*QIfldqEUe(!EipDlgA6oE6N z{I~7zt9(gk55cd?*N;)Fjh0dq%M%f!U^hlY`uxC{n7@fS41*p3o0)zCrm&=y6Q>9KAS@84(~fyvVy&Et z;LbMI(2#Tcd@!3^^!0;KcbF+li$YjMSE@VSP#ENJL?=i@=d3L&$8Zru(IXlV_dh><(?0# zGUQu$p?2PiIwp8mZfW@1&lut~1I8Mci2Rm;b|lUviJlpcquhI85fn?TQ`sR+L*-0D zbi)0X;l+%m9PXS=#do;Vm0R^E%>!4>?i08%(M8TIKG$qE=Z&dOJ98D$(+$-;@3s9L z0UHfTtnNOLG2ZJQ??;bQesP(`HmW!2PC*m?>C(NPW1Xr(o?>sswrSJ{4;*_xUll)6 zjql7D*O8lU=$CMRmqFJy1s&rymhm3KvlI~N|1{K+-U|dQ>E`x}wh8={@-xl6g6ERx zO!u}2cFtF?u==HkR9Md~Sf1Zn4u(AcA6su3702_03;z<5AVES15IlHrcS~@B1$PMU zE{pCaAwY0ePFJ6quBz_mv1I)i8`_s# zI4s$wBy6m4$c=f|rPlg#dmDcX>s{PnqA@`mO_79R`^Y>n)+>#_AJD?VP70AvWFcCc zJ=+?5=9O>|^HC1A7^wEa;AV>pMBp}Ca`F8)4xgWYZCE@s?^74T2nvWF+anShsnP3V zo~iFSl>4XrNe>7ux-`gMSL6Emn6 zeO0F(#)lR8@&wjYEp(%-gV1x122dhhea_6VM)4b_Zi}W{>JitR=9;#;IF9xEfjgso zvUmDetubFA5+XXOf=PG;Rwi0{U#O1erVpQiCpj}`;<*A^FRjLtTYT)33~WAUC>A?$ zC*@@t>7|KPzGiAjhW&kkwk1=Y@=DinnPexNc;?Q!?M><~rN8Ex^7x)|JwH^m-M=(8 z%GGY)-!G0km;0fkJ_2AqG3ZeTNSRS&QM&8w>4-PpPx|nTbw_it!S#tPZj1#|6iPOo z`yweV@bC);kTR5Jul5o#mCK=Tqv0# za;XCVlozX~`nxJ{osOoBKOne@$|QQKoQ;W%k9~{-VZ`m|sfVd7_V~WdguXRh^8IXK z)7a2?fFwBCH_uZq6D^*EXZev`)1`U(n@LXMuYYA zLUuXGt#zNTa>42tKi&K^?!!;(SSq(u^mNg38qrk4W*EB(?>x(33`XIf+`<5C#*GpG zYYB?q_CfIlGe1@^dV5pPvtW07xv72;6gZJA}IHTwJyaKI*89n7`f zbnGdJ&|;nPp@C;;p8XTj=^q&rV(g8hRTUrOz8qs3sM{VRQa+D~cdcAOO*YJ*@{krK z(#-lnTAbPu;iCMK!Zr&Ezg@-#g2~;@oYKjWaK|VNQ!T6QVSssk{k=c)-ppn5p|e+5 zG=|33*~4n+p@EzteyqcoeUyA{w0TpQkkwn6d-15hoa4M(0HFYqESd>v8H6yECen*0Zf+^h~l0dEys zC93`Z@S=B#9z)gnCDU-$M33!_L?x&HS+9$;`8W3nD68lQOQyXt3ClRn#aGAj$8>9x zp)HVZzjn>Sg3uzC<-F74@YOSn!q4r}@?lG6zJsKRT$1-11olot_zEx~7Sg$3(#++8 zN?T-hHrVB}**0b_pKaMtLkU;p)8(;vaMu!Fn`IlPMjq^{I*N)G+x!Z@-p*sxla|hk zk+soiW+W{?W;flOec=S;(fU3(d@TC_hf#XnUr46tp_MJ>*bnHTx`c7q5V=PwNqR+P zRP{Q?&;R4Jy_`ImW3P38G-cNK05&+F)#;XE)FXNitLp*M6(}oS6wcFWZ~nUcyr-PI zi{K$@Mo#lxC4&E(j(vC*U;U{61>e$%r){;~#0=|<5s$ix>yQvL#l(>hEs%5L!zjRdaj>m0bkreisaqPVGJvjh#u^&ru`)k{bnEuEdgEgF0?x5qCPi=72 zLh|u{Dge&n^l)A(D$iD=KWt}YFZkFcsA`o|zPUg8SVz0(e&Cx2$uv2#d&l>cM`dm9 zK2TJz$dB{yv9?5;vwPcv(5h@f?I*Cn&nkLtCy{7_>Q*tigEeOtuP6`4Y&nlWD?;D` zUgambu#?=tr3TC$@wJ3wTc_n98Aunf00rpdt+doU6SNA z5BYG@5I^UoZRIb(NrScX(QY-NQ%S&H_r+tNEM;w}(-^tc2;|Sns~YPx%;*s^r@8EM z|J%Q89UB3Y%B=6s+2oU>ld{h;gGUM}*fSA^nPNXIqIe5TP*bBGat;B;5IKn<6g#>n z*OwY1C3xec>OW+MyUaDd!FH2nTX4_gNzbprL#34C(sB}b($3R-YX3xD)8`XYYbR4T zV3wCkdBCzzy;(~GxE@V3dhrdoODWmratFRc^xCP~^E$lv+=#6Dgt;qxMc z*hAomr7&~3l241pKDnsxKx^J3ZBxnuX;@I(OqN?Pi%>P9piRsyJYc-xdx^*farKFQ z#sjjo-$%}YHi^Z zHBlOQ;j2wiyLx$#AK}R(dQ~}9f4iaX0bl-!BvwFtaP${hzISM`bs3yASqoO2&42Q! zSnixYRm{FdF5#)>c1rX^A6!Z+18WL!M`r#-E$clwm5fJG)f*1V68jfRW-X=ynP|<@m{guDMIB*{md@2)V#w;XZ z=ksD6$y(A%80#MgNZzzs!6^{j@UFuToJ0YSr!KbUa=@l8#bm#Ra$cP^ zEl&vds$gdX$JQsU*Bg}wEyS0*_4!6JYQ||uK}BJ=U+y}`=ti<^8=tKEA#i*Zlgc8q z)FihrJ}i5m6p8?Q_2{cP*)r-cb`#=fDch1lQe}D)T?vj zn&Rr-{)(^dmv4j6j5`tYzo~1cTQL}WM=b8*G-dRf24erd_Gj^nVl*I3#nq%SWFHea zqq2X5fXo%A@k;gYN(X?x%lYVFCs!aU?!J^cFpACSmV;*BHL=LOzn|O7nrr@Yoh?i< zqpN;NC6rGV+GVNg>4kOR)N-lkS0%ogs64S}xXF0@?y|42F(6)ppm8w=b~^Z%)X3Ir zACb2EyJZ-2)PrhCw@7RgKeNckc180?7M+sQQt4rc;>>#ZZWqQaLqiCHCW@&Wx?)@p ze-Q*v@;Zxbzr-h-x#C`9m~iasaWua6cQK$$77unWPiWQZk9?IF30#>4t^gh0Lg{UK zS^LIktCsRLTG;a5J0%EJIzdwSER|%v-c)c+R@KPH$jHv-UrK{#qc=;N4F8PVo`4wI zvU9-1kc(yKE{cz8(R)1t{j;J!!s1>nmJ5%6QovZ?UCUjH6;jEDiK>H8$A5j39^({d zR!$J)Z9B7$Po}mn z+CfrNI$W53VMG?Alti09CDJ|X9ci#4e7R2S)guHDt07?1zDt6MQ1PhwGF;oT^#+oI?4-L20{#RywUb_y@L z0~w|Zk?F^2kqW(R>~zt9mdlU;(no$od4PS(W!4sjz2kt(e)Fl?3a}rH3GDIJIICU* z9DJx`aj?gpf$(9kybgcob!2NZ(OyTuR>!_{@VC!q(MENy`jg}KV!@aif97dowaA9N^nvp$?1Z6- zG}?G+A|VQMcq9$fpO&iF>ge%0ZLsH(Bp7LJb}xO<+1NQxW7GT0;LhZCc+9l)#`uB- zk%n^iUD zIRzx5h3+c=MpclTXKLQ&P={$^_GAYsY@kvlc;Q{sjDegzEAKS@`C}$bOm28o&!8{( zkxMApa8}L3IFdc&U~eIM4;dt^|K|+eF%BSSYLc-t^;D5#<1ErLaPvC$xQ_lkmx@<@ z!QP7dhI>=Zv^{9yYa&}j^C>Br9#b^5=rgTDrSkKOsy-iY)zNT({INIsv zkLrSPYX0lWGOs5tHTsY<<_WZPs;^Qj_{4ARu^K-`<;i03-4}XZOEcOl=<^I-Q~iTn zZ1u=3v^k6w;ht~7%<`y081{hI4)tv}izC+{;GLX!Q*m>X= zdBnfwR=;?(i(S*C2h%!kkd4SPk`2&;)mr)5ED9+ApYJF_9%auSgK5Es6|wpalkHjV zWz@8ZI};Ql)Wl;ij(>aNkOX~|eexDrbx4HnmuvGm7gy_*W**nHLHF6qyP^B(+V_r| zVDyTFbFo8)?~GB*E*)!jrP)1$vk~s?x}XGk-;h(ii(xJrk)L%cUnm~2y!u9M>hV+v zmM*fdG_Q3kVRg=p!OkVexkn-uU6xeu>yAr`cyBuLms#R5u(^bHKFZYEW*fWbc9#U0UZM%v{I zWcQ=K5m2Z-8)HVLnasBUE5nOyM+eTvu2Z7|XbA}WYv-fVz66){c<>;>G>*oH)g+ax zI+c0HL|0AmYAZ4ZF=%SIv7nM~rMu`iF{Nb~Nte`HRMmv$W7m>U)WS9AK4PL)NdJkT zjS0i?fGz^<@upMdTR;O3cGBzz-HaKhkL-N9sNWr7(8bR-19t~kv%n59KuQ8MwS&o(?Q`HpJDQ0ad$U zs`8$yhD_60!{`<355Y}Fr9?P~2za&4TV_j8aYiMCIxafKl*sDa*KoVv17r+rC$mR) z&g@I3)A^a{F(>BvTlUw^f_;rEwSR|pgIvKp0k*f?4=2qUDqPoW{;yi1-3^(ifC+o) zQEVb5uPyWk=jwR~f3J|Hk(TUytT0(jV+N-B#0M$xvD|~&&G2{C1MYj`sGJoX->Jv3 zff{Rzig+Ayie%hn#~%mh49Dtt4}%r*McDk(>fL?B2}Cr=j%Pp{5zLa66Y=!Ex_%b} z486mDi;e<@tk2&lyEhtbDROcdsP;-j6g(-M zq8urb#K0PYULLnDbRb4}i|t!Mr(sy0ONTZpcFc8F2S{E?(M9f#CP*que)D_l0&B1t zO^{Mk5c!@Ql-fDcd$tur4!CoTz+C^hv(Z9Mp8T1d3TM4Ve?u2HYG-MOG73c!xAk5k z%H)~N=9&0poU1;Ne!~7PsE3E=r?oy@EZDCeTvHfTHnkcEY!9#*Es^tJ%06S$n@)Sp|oF#CtN#sFTVe^0I|8RO}}sUa1ID%^Q&`UlsQ!SXE z@ux<}$V+@$8-AKR$mf;8^H*iA4$_O%hL1e+Y$E69HR7x?D$f6jZO8k>%4z_ zz-u)`EyLZ$13{>FvGm|AH!&QP&a-3q=GM8}+ZX4N@D$`$IdmL|5}3q)-cj`m^v2_a z?bKe4Kz}>!a&hV!zzxW?V+XfAO}2_g+Ho>5*Yn4#^C+m! z#UIV9w0lR%uo&MN(o6W`t8f?DUZ-wnUVC5j3i_8_vA2;{p?e!gN|l^;I3gOfeOt|% zlbZsnAAha+^te2d{(0V=OT2lSPS>}o!-C!K+>oQNk8(6nj*xLL3N{K^Q|EsL_Bqmj zoG_od<*TtjO`mwPB@l|!Q=KHUA&`dCR~?Mg?aW4IUK-jC9QPj8c@9(jH~`C$v$YJcMc62Q3!){IoRKkFAu; zg=LyPY#Y1<4KbpIT8mjVu6TVrjmsOg6KB*9ep$1v{5Fn^sr+F1-^^VMkUzD5=Y?`C zanjnx@EN;Y2FOhXkOK)dOsdtkDzh`pazOI-XXH&2MZ-5$C6jaxLqp`cJO#Tytokr# zktAQ=nU;edtf_xB*1hsFpCRi@U3OAhn`Tj1V@pr^y$8C=99|8x994Y#*{ z*h?P6Nxe_M!afI9t{P^ykk$K`I-}j&L%ZkY*}_2+OEd@V5vd3F%?q=02kl|#RAM@D zOuJ(6$HR5y3DG^!9A?pK=yM1c=ZZCp9)s`$a+eMkq<^=X{?D2AW|U$b#O7+8 zNaDFE$w$+qzFOFPRb^$BZ&l*)ZIy1=v$xf++b6EK`MH4# zCY@XCOY$K)Jt0up1y%U{`BoFB*z%8*ilq`yY?qpJTu+JsVPld9XGil;CE?o!{p>ud z@DJ!x$!3~An2xURud*BJfzqC64w}qp`WgnCT^|B;ALRoUabi>r0?_m{M3zgM$e<~g zM9pv}}dj6uUlny)HymZb?Wadu#Z-s0J zsX#Q7>18(u)rp}gG zVa=WJ5PhJv9xJhI%Ri;6<6715vA6^FZ#{qv44Qf_V|keG#h(TddGAf4VJ_gUw@}5i zS*yHH)#=9C0w&dv*&nk*WDFE=Tb-2a>eSy}GX(|TWXke!*UtHtwwpdKD6v&d?MlcB zEIt}s6Qw)j!G8FWAg*Z*o<1eDnBv64yhn_-;EwaFSKlI0Hc;?Jz1krT2Qy!nc*#KT zlU>Ky{G}{_&2wvX-FwSMQCd-{n^es%;Gk*SWJj2m_Vwz=?>^mUCDfaRq^og!8yssp z5fSD^fQ-S0H^niMTc#ExDscE2N0pu#$#<%YX-=kT@fxJ>mq@WP;OCrW@e*;Om?iXu z!A|L&;R;mYPTIYxx43n96&3EHWqT9w)sGNI`A(uqr|@d9Q(%sDk;9B1KLZ^NvA!J2 z*Yx9@{O>JsG%}g3>@id(pK?;{Rm{j^@x{PPp6My#l)9rgf^OJCBP*{L%`8UbCR$!C zdLNJ_e4u+0K-4iXH(49GV2{NhTVKBS*Qb2V^HTPozBra$qFT(+%T|b$JV<{7(P)ig zjqpWL)m6#YMAI9oDYR`0;|=bNKwobPawk-|xT`QsaG-ugrZ1@HQ;WGOakzJgd{Nx~ zqPQ}5KTgF7qWZ+W`W$BsZ8xf7SajM*S=0IFWFP)vX{)9c2I}1*{VfEo=b~Zx=||?Z zGL$ZTZ61fwZhJ~OG)Ow(IaaA%jr=i8GHsGY4rP8m@=;2`kf~i0S8={5+Zao|+Dvmp z#f$ZQ%%xoCq2?7Hy)K5^1I3S>Ww-*sMAxkG7%98|mT&%v3@LsO#x`LI*Z_;#2Of8Q zx4*g$5*%I*&9FV`wfR60jE~9A9APujWD3(MSgRLsw;28SBvv!U*K9N-i4vMyj3tT(V41wfXP;u!Q;Ric5pqEZ>7{-Lc%x)@Rb|ys&vEYSAYQ8 z?2p+j=_2E^4lMLrUvYJOP=@}}_;_a8_uw>c(>#CDp{ja!P;)Ket}B(G?KyBbNNv#= z*)L}+QOAdqwv?ECM{c(lSalw|b$C-fJeIzsrQ!^b3-cklhi5eX)3_~pEE#X6^vvAK zp~6j+ddXkkb0Wp!o6d!Aczj$jYFrc^e|(}8a`JDY_Ll9yKVy_tg;~}{RFddy5esQB zr?8)7P6ROgL^-$4^^wOqj4|MwWwNJT#s}E`T&nB)Lk|NZj=7*FnN3bw+~=~OT3DVX zuX(-_6&7hGFd{6Za$g`tNyT_fX%zjQP)Tly#<3q2)7aZNFXC%W9Wsd{ag=X7rA}5t z%}uJ&3OP*BL6t==qH#&rgpO&^9)R5vjgawhk-)oxMUqn+K#A^Mk2 zU8iSpud=o(i`Lo=D+8p7BJW@)fEL5SK}qW`+0rlA73fyK&fb_&zGn z5z@|w!lw2UdA&H{>L0M*a}CPiZSMqTF1RtYx8fDcnwRX-*S&wUlh+VdNRS^D&(IKE z$rwPOw`Q?F$Q37`@**nnW(Dmp*;3ZuwX_K`laa}MWfW&omapIb@pFQDQ@>;o){RIx zcF9xqAJGxSo*aIYP*dA!ayZ3Bb5TXrXNr{fKzd2e8^A;F6srg6O z$AJumu*-jr+4?(5+o1SO0-DRlb>!xod@7aqAWdW@-yDCagQ;ZaG)|UVO54!G@8|2a zorrPwYsG0_9%#&DX|CNw6geBs6IfG0uY>9j=ALq57wddx9$6i$=Og=)?(}%w?!Rqc zG~MY{GV;&WYwP=!`|zoRIYA|t!L)_qM}^}4mR+c31L6xKagIKPLPxcjeU9f4W)#EU zvAe93hdRAC0o@PWok6n64^Wkp`7;uWjLR?SroHv~#bn&Jt4|xGs~*{au<%Vz{aj;n zZ#J^;@l+yt4X)GaQI|(UvCQGV3*4D4UX$|tvbu^Qxi;2hh~To(@O6>g5|d0fI`^e) zuRXx~69@&}VKw>I2c(I}UgxWVlbkhNBy=YyK_%p-Q#!-K6@&W!?Np#Naj9Aj7;|c}$7D-%`je3gpc$s2TBHrt+cqJdY5BUo92(N>k zqDQan@<;hT8Cx{-w;K{VS2{%q%ud4OH6-3H%cbjA%Rs+1z)b$?#lyz-Z|G7HIlnnBg?fv7Jc6EvCLcYJoulzKVT9(we`kSd;+J;am z;G6dNrQ=pF;_23y($n3-ykEq1dh7b%lQh3a{%B+J6eWElFve6<$jVn>>PWe_!Doui zX9p+s$)M*->hY-K#L?NZsC!~2seWF%)0MiwdFEiPR@#l7JE zBJud{=kIaU!rIO(uF?uy+OA-JT;8OtY!eRuBOugS#V;)ugH1nRO9XZ&pOIiy{BE9= zCfd1&A>W;zG@kz?nt?QW%e}K$EC=5aHbdz;Et-DQfIeb>k#+qy{_?bNv};;$%w}FF z-hvq~x3Rl8v6S^CDE*pCCI8iRnR0tZ@xKcjvP>Hx&u_3|Li4}FMMnB-2^V)hZd8R8 z4Jz3?5q-DP#Tum4R45}&*EpMafLdeHs9%X)?o);~^Ibl!rJRjyg-4A~xva&u1#lM5 z9=R4W{{t8zD3KYs+)o~oZf$$<>XbGljq=x-y;X(gBx|-MNeKF@P;QH=5TH2FrWqblfp3yaJ@^Z*TJ0Y#8Wc zDi%w8Xs5yA1*Uwwu$?d4rF(*n{UuuJ`s*gG5|z;)aACqIJ|1?jnd~W1tVrru7MVrE z$ZuhK^n+^iIl;aHV|GUn_jxw;5PB1yf6k~Xh6|3NQm>`R&|c4)EIhWug8UflkM@^K z^x#dAyyJo%P7m^mR*U-qQ4znc#)YmU#Fu>kaT#?!N50MHthoj?e#eQInY`U;?HzIF zFP&nv=7t!OI^W)v{0jbTDf5hK7+Q4O;r--cy?rY*F;pN`q}6(yM9kvpQ3kR3$1
|@lOe9H=B9(JIw!eNRe%Y@2#*Bbjw`I}C|Nm6tju8Y~ydrR2NlmEZ?AH7 zktMPJ!cwwZQ7g425f9q}MXij|o;j8XK`AM=n0wzm`lYr1jiib4^2|I2krzW~|2GaV z%7ZaWQzI}*!jGT9$7I(C*E*M}IW-GZ^ z<#o1ocw(^Eeb%#h1Ngt<{{LxxDr*-GwbM5gUGOEd!YbVA;PAvF3S%5%mVnibIhWdL z`2SO;H^d-BECDOeBA96M|0)y*F8_P%HJ}Aj-~Y`|7lr;8t4E7hudhoJO|E>Lz4Fux=w?fcry8fjyGwrM5FrR&M81m{07@D|}$smIoc zUmkdOQ)0vWz-bi^gU>j7NOF(pCxA^`I$>M;@4c#v{0GwF_RN_|nKUXBmsZUjgDIR< z5yCdluO7-kk7W0@X!kZIdH4BEw@zT+PS}3%akNsAAK=}pEzsj++XL>>Rw?g}ahLhF zEuh<(8gop_w$&&SK>^%$ zL)VDXkPWo?hR7A2#bz1HKHc(y=u zQ;<01y7=dFbG0K9zJ!aOVJ(Gnz7T_4PtgBw0!#?Ei9njz)}P1mvT&=pQyB8b@fgE1 z3(^1FXA&OO_`f?(2=Cx*YlFn6zfM{l|1+!zdGtf$xhZ4MluEP-OC4l#p2|qddeN+~ zF-ohw97oZA**kJ3g5ODd`L-Un#~1eX&bwPpynGF3hgh_?Y4QZypu%Fav{(qsitzdX zo6Hxy)n%Mv8lG4r?B?eh%%)9>Nb&i_<4~L8yfz=s&4qXa#N?Cl?Yg1Gi zjrvIV?`BDO54+TdhA;!}aaQVGEKfl=-jq)KD^M4ry^M{Y)-Ox~zKVmI&Zu7cAwjRL zen0p&j$Rc%=Px||c#6T@I(;ICx||6YiA1aW>M>P7I04am7F;fHbaPSZG}SkwUj6Qo zjrWPc;vUGi+FKy+36RYBg$bsCS>cS=XcptG@Eciyht7LowSybOb`P>PqE`v20a4OdI_HV?Xg(}$~;+>3i0@e^J0$7~w| z<|{DGtt=r}KFGJ%(Nz5!O@6l0^*3sEmRV0kT}}inm3HQ#JgVOves!{PT}aUC>t3Sa(QRPCtPSNkp($$=bw?N zku{q4&THEdV}+zZX#q!Ggb8B%@M~>~>!)Bi2lk!c$gTldG}Qm1tB+`ZHGI@sS(8%D z_Zl5-mmF&B)%tz{<7mpH)ljWQhoJ}6L{}4k3J&9c`1dCHP~|q-+3PvKYLMmGIzV&u zrMP0>J#Ab@Y7>-9r;_FGbBu^AqtAWdQ+SeXuV8xGB=zSnVB>0!?DmCrXpi!-JWxQkP zEUeQDS^Y`*@X@jH^FJDSPf8P}Hgt6($HF=J24|>;U1ihVV+1~{7uoVWe_~J;i=#pJ z+1GM?)KAkeBycAJzhEl)+K$T0uIcZz!5V7Zr(|8VNno~93_!?&Q!{=v0{MYS<&kLL z?`f0RX5SRh$7d!)i_?Lz9OSX-{<*zuL&!QCdwLS&PWd^-5c%&o?7V0U`QpUFyztc_ z*<+@|HzCBPVcWZ>e2YeJV5D*9o0h zMbg)-Xzeln>=c5&vR{10#Q89KgIZhbT`JNA6Z|JtsO5hG6fHTbnJ#6R25_&KBKAEr ze7g6Ga;G&iJ=}hOp8j9;V8Z)RU$}b99wAlend#AHTcWw904BRTDbGweZ&W#9zWL6S z&vWZRumQfQ?3V4^b3=Gy9LYwgITVgI7G@7o+Qh8QRXAYJ;K{Ms@@gu2xY1$r(dn0T z>3Hb_1}&`jb{pXjnGHSyu^B!*vAiqxyF~mun7EwJ>(Xg|zv+fI) zF&~h6J7Qfm@X&eqk=fGA7ea-T=yiH`MFc!AGd#`cSf|p>Oq;5ApgNB6{S^0mhhWOs{ksq?u zp;h0__s%*Um~vRH5F})Dtm4;hY;ctZ^A=L7qaAGg2yqspJNK2Z*@tMIHFGN_G;<4y zh^yOe+ALgZqMEri%jgQl)f4Vhx({hrHK=A1?uXX-a<{-5HZ)+8Q z+AXCe4WUV8 zP-%|6IgvqezM>2qEk4nYYbPj-o*${)5rXq|Fc{lY4cMFciDVAjG350PFW}ca&TG%(re};@# zm(#Cn8&{#?#`e*Rr_y)`bDehQfWFgv`5IZ<51bLbd z1%i3h;>^?Mw^=h@;%0*WRMRMe_SeEUGrx$q@B**afP#jL`Cd@*xqj-3QsXRrHK zDASe;IDq%XKH4G{D&eLQL8JWhj0Z_;&FqX|QagJNIB6_?DJcDY9iu~m{z<1C`sUQotUbk{?&aNFk3y{`u3w)ICPT~c~EcTA`<_&_o=p1@gGHv}73 zmr2jZKzK7uvf?R-+ea-*JVtWM7L@c;@A{UM+i3*Ct5;f!QAN$%a@TI4VS`lUgCgg> zFl@v@3}26<2^is{6xM|bmny72LKARWrO*P?4+*~pwRf1i{18JBN9c!KI~HeUEQ*tY z^C=kmvp#QleQJo@T1bK5-8n~4*LdDbsYV2WH|&3rWVyB)|I66NgR~oJY@k>kOHbEc zpw3Y57rDo(Vd%%iDO<$dD6~tbjkk5;u@I^G11Pq#$j(KKUG_yx4ApMi+UI)&>)OSW z%HN9^kier@`y5=9&i5|_>C)gNk{QzHy)l_l`i|3BB&{Xb2XYov$#g;sKUhwD6y0_c z#?zD3FN%iv$nT{rpt?Pkz@I40bKE^taT58VY<{?|;lx{+VvQT@!ZHGQ`psCR|ERM= zRzkXJIsCwI(d~9hHXc~9^DMNJ@h13N-YNhfHt;q*-5g(#|1)`bfKZ&t?(K+k_nE*F zSWVEl7zCLi3lQ49a}~9^fO`-1a$%C2d>3RucgZMlF?=0WUYC95;x9orI0YnUdqJ+_ zBj~ln>X*b!4q1K_DkF>{T-S{?+Su?Gq#MLd=NN296NK$=w5-X(si`!*kMY)9SAo?V z;=*{CmF^r1!gBr%6W-DDKG39*#)(=sXs+jR$ovvecIHM>-`X!`-UrfTB!rh*q8d1V z2Rq0#D9ZxKxV`87qG1Dq}hOq{rI=z1R-01EJ1AW z8!lY%z8NbpzAyK7E^J{-K!3KtxY=sB>0_1`hN>T%D%tpqaqkT7t}XgmgPJJfOP1Gv zKt40agGD}i*QbRj6P}Ut*B~fmtE~CKpsLz+qyK=^{U_;ODH_)7Q};xLM?=foG|th1 zYMUEmWl6N3BU?lH4eIQgeO*~=>E$Vmk#Sfdttl7MAT9qkq2Yr(e(mRcTX_H)_jmt8 zK~k4Kje)5VLD;&twfc{SP4nM0M6W6){sx`J{{8$ZW%HKuknT0b8w)3o-Q_DavqplYf@rgpz=ca z7x}l#3BD(5rfJVxa2pAO)nSl;FGw^j;5<6$-4c;@shNpi{lhc<+Itswi8B8NXlHih z2MTOA&ZJ%)T23RL?9p1@v>HwiGE|`~7ZA`1t8LScdrLWw_BcMw$M=q5p9|HeB2l%< z0H9R*P=QGZKs=D8P2x1lA=Su^JoS(pnTD^IRz{UlsK;P?FES6i)@2}Ywc}U3Xh%eA zFnA8%y@Yd*eQepW$g;Xj5FO{<|H5Fsj@Bx-?eLr+{s5%)wEm&?3K}3&qNG1veK~!c zP{C1THXJUc7gZ~_1S&YL@mx<|?JapYXAf#ped!pY{R>*Caw0$CH6)ldIxmxOUfwBz z=0Ea+<1M+f3X|YcAp~^ub4*N8o#ePxZJ6+dAAV*F^4jsrfjq-LPwFsov|x8uz%sF{ zi@Ll)X=Jp5S-{HoeT(qWC#SLy6P(AUM=}qXPQuC!J-zkuR^Dvth4O;sx$=cn@$~}u zA=pjyCsrzJH22@+zn6!d7LR&ztCQ!StNwtwIT0l^Gj7WLSN$|~&n+>HKFC~yVlLR^B@ zmUvt=0x)h`%cxq}hq|ApY+a&nBLDbBV&BAzxq*~K8zpwHJVo99+dK|c8vd_lxV7Fg zZqj*G3o=VMlj3WbT5xi*C&|2h1ziVym3SuFy>RrY(@tGB$O(!aF*O= zgzPPU^)YT+z+Q1-ucy~}Piyj#9G&kISX~Z2C$PTBYIEveUzfh^JQetcBpdvgjE9RP zJUZfY31DA@utV0@Il6Z@)0i(kM_rml_pIlz`UBq_A0IAf#fa^3uORRo7PTC1tV;S{ zEC@RBQr_-2fqoNTL4;5*IqZHP$#nXK5eGepCMdYe9SwdDE`P1!yJR^%GfeHn5;K!WaxEw#MA8=v8{=%-JU41R7QJ*1T^+s8*+)~~Cxm90`#=cRhjfs!E-9C5+ zKS3dxQLf1X=tfsvv+aW8`ZZ41*NnmxJM@38g$jyt!!?FWq}^to z*|~vPL6_b+)&FG5WOqljJw89cRe#4d-|Ta@*5&-WpYY7|8!%iN86z8Vx0=m&N`QTL zI|ns5d)dlC1@7>?nD(?Pl04GTYk>vmYK^uo!To4 z2YJeZ{`rpd801CPHwz{q@Az1i{*^-%dtr(;!SF4ZtV|FBO^qhsRk|DLPh!@&P*dIr2 z4RzB$P6XL+6NdQCf?;JtUu0bv_-d|ru-3a<B)UA$sd5MzS8ywK{Y_FI9AY zdZyy+^47(kb;ww5Tw#bKvtc6Xw%NM&cc-F)p&#{IN2l#JA{CCfjQjLBuSSyitTQu3_jlhetLcZ#<9cP*vYtYC`RUiR3 zka|0~<|rLRGG)1GISgqu1+!Qja}L(6s1fO5oSj7<|Irmx8diRHvCBb5-a%k--0_g; ziBat9Y$9jBLp1*%x!>k}Ji-7UwTGJRvMp|KUSUG;STF0~A`Gw)1{t<%;ZwQSPuI6{ zMnP_Gn`P?RL|0KOANwoD0qu29yqF^(@?!2aNHnOqWiQHRa2XsqH1&Z~&K>{23Gt>u zW;J$x_jHaW0N#0 zlt#EFyllW}*3hhUFQ+Ns(9ooG|0#?!%Ho_ScR;ti!|F}pNjuy+?-6&$y36MqkYULA zlCjRiKCkXkR;?{^iiLaH=oMfpnQvHi{2Vp%xl4zT;ut4&dv&7D%^}VUchpos0g0pz z6;OcQ+b=AIwewq{-aSjo~7hU z)szCo2damOd})ULL!?U1b#O{$pah%F3|-}6bkXOfw{9Im3d4Li8EN*~43*)gRjCS_ z_b855t4}X#ogsWY3RAPEhCK1x2Wv0Id)mm}pgSMtx;ZThF8uQFyEx5Y(Xa_Cq2!#Z zDs(LV*EAxeJWmwgz-amU+mTW%6TC*XCk6C{*;vspvc;fQ!B?1XBZ(2sdW4%tAzg#E ze(a|i6TSU7ol)nFT{ooN{Pd#xQ;{_aAPZ<_@H2Mj7Y_n8|QDx%|RM^z?hEFLgClHEP%7D2MBI@X>)k}X1&g-t9gmFGt#VYB2unXs?fO3Di+HsBi1(cz47Uk6- z#Ns{g1evz|Wv_xvNgMtkaqhciZVFi)tuS-LA<9#vrBlzh9PPnACUbxp21UPsX44jGb}qnap;U1WG_b+7@`H zUEv!~T>Qowp;0mfM~R%gx!sXE|cI#5(ZL zIv(Ght1oYj&&w&dm+bCvCgl1^#1m2^ijLbb>OF2>R9pR${$nDdGoi-^_;s1iA{#!M z$zli)45~K?PlcK&`gQa)xE|Lp9dR5laKvEyM!Q#}gH%L*XikM-<4wKz`V34=;R3(x zyY+hE?-@^=SJJRrPGPff)%RzA{dH-U0&1v;qC_WA)C1JkRlokPW8`5*cEz-DecXJM ze4F|z@Tl*1zcXcf-!Jz=vHjGfp2nMEj?3!;IlaYDC>Bi6>!JS!Z96Naw3Cso=ZTE< zc7SYdMb|9kzkZF+F%?~=nGnM2;6&?yQJ-8b>f z=37XSsy#4L?+Tlz9vwF^{EgD0h$XZ3a3L|WHHBO8(l5yU7WoGc?LC=9-ivxO)y%0 zP7E0iyj}jJz0N$2)s7K+UGgxqO-Jlvzo)>yr=VfzZszbpOc5zo^>AjK-DSoOGy1klK*JC2jrPs_#g#yNwFz5mP!+3zc4{q z3@s=W!3oaBxv3c)J5`6PFuQX{?z%cRs}Y%(+?R*883=Q*M_Exb&ac?-nljkZ_f7YK2vu{#TJHVD;!$1(h|Ky zx&L?Hgx|8_g~g8ko~{MUVP$6l7uV`6)elSDqzfo4?%D!RwryBRWzj~XRGGp!nPfi&+9Khkxrgn#Q-A;{)lEk&%j0Icn}^ z5$MWlIE@mM)<$-CCFl_iO_obTsu*W~&EeL`akeSwJpE*c8u3+qWD zn;GUM=~#K3{p79=gSsrKBC|~LS)uSwl4BU3;_S;mnbxNS2bL1Kl#hR^yu}Vsf~A=l zKuPm_b`OHv7SDCC((i{{@k1e_NXDMDD5+FF`Q->FLCS25rgFwh6gmCBc35GmXb+#m zYZm#pcQL=YZ$v|9S&{;W*E?`evGDR5ZF#+EjccnTyVlehvbGplmqQ(@Xt~c}3{@|( zEIKbz(ek*XG=%(60sLTXQF_nPVqG*TB8abw0;`7mmdt%?i)GQ|MPs3lqwF2AVb~j_ zYRV!k^^Q2aeAS`~HhB^0cvZB+UD82Ya39|Bi$<qa8ybwlBxA!k}_URChttyYYqZcI{J7$ z8K8uwjQX9ahH_2FlHzJ!NbRc`NEyF0zkd@^P3HHDW7Kw2kWL^GI-xB^^hPLclI}|a zEPZ2~r+ZS}^1U`keUL)53-X&J6YDeH)ZrLi`zYX{aAM8?tzqH*_<2380oJemq03hZCZTIPwsfg zVE_-Y-SK(&wWIiKU#No3MTv?L>&u}Fq1|tWR~%I`{b@A~a}%@?*O*);piDx!`lOmI z5qCH=f42brlzjbCX=iXsuWE{Vf9n{V9mn~abl@XST-&G8ukGW@fr5H(ie_k`k!eAu zW+|Z$aaR3)T2CwR&F%pUpW*8Cf2!?SYcfhbb7^Y?rEYUT|sEweW2;iWmlwy>mVkPp7#E6fa=~)^Zv3puP+Gw zp|N29mEhx>qz#FCnIU2m$%Jz8Bk0{(2eOZHat#U86eO$Zm>g<2vnijbDUp;KxrilIrV1Ju&r;R~d2~ zdi5RPE09WIK&Jsd^Fu%K``8nSg$5zGAigk%WACswSxYU%uO>ksHwgDOS|PGE8p))C z;28GhY;I&Pvn(}!d;GtjQz%s`z1NTZ zw9?N#)P`F1($&o9QTVx0xK!4x{AARv)nE-Kv6B5Ypk1rKHO8vR#8@Af{ig^EW2-~Z z8?M=8D(KkrjiDaUW1vTMWpOQ`K3(YL#)C|N9!E|1M7*7Gk;Vx0u5d_}ek+M=*N7#% zW=3X+uWWA>uWZZ<(e(|WI|W&Hw#Nl#2kEN@{i!4N#tGqRr$}Fy zzsyM9fsEv7B9jBSk6@`3?I+f^!^Cm~uzVnb|7{j-W2t2B*D%3`d?Z9IOX~x?Y<)Eu z>kG1F@h?_KG+-?Qi#f4Z1Z|iy-T{0+6}8nHF_Lo#G}eZ1)mT&Bzmuq@s`q=w7~@*? z={jp#{LDJ58L+C2Bb7a4>Om{K43XRy17-ExKpr{ zO6{rPdqiyBGjflJ2lk-vmE9krt`)Rb3}+oK|3B;xQ7YY)`u}Hth*Ig|)a$Y5vim{= zGk>S-53%#llx&7yC;V2yZ}FdHyVuYT`g^R4K9>i6;3(F?)S^|?`s#t_-st}zMk{P6 zlPW%VtJxvo-GBGvSf7KniDaAx{P&(d9>@DewYmAN=!4FS@oXpxE0zA$H#9C(Dt*|e zm3>l-#st|4mrCcQe)DS922bwe?p+O<`(oEv`Fnl_mi0|_K8#Q-#KyGiOp+z084z?8 z%mp=G9JMjLBLv8JF~ZN78qjXVJ7b^^e;T2aFFnk6;d2iDkB_0P{-3_-qaW)#=iYRx zI|uZXr-9Wol6w5!5@}WJfBNcj8j^K6^G=XSi&C9Ae?GC{{Nt&&a!?Wq-d}M1j$5Dn zD#!lRS9Dx|srIWJweS_S6_jbW+7oIO*81BD9C9!hdPyt~|K|KfhV9i$PX9%$V+LJ>1i zEKGs(#4_xIHvhOeWI#|OBrD)ti|@Nh#cMJ3C^F@vMH54QfHiVIq*BR|RQ5x{ewmeA z(y}Gc*>d{6Nu|=1OgVQ8u1?&ts8kxCw0e}?ph~4NNy}NK(t&=)07N0SHVp7>McwdQ+_@0{3HNx$O0 z0>4v_BWv`bzs2a9OIdwpq!j(pP-r}<~8ECU8rC< z_h4gWKd~tKnsjIf4BSj;=>z@z9NK|>wV{t@p9XEWDtqO%`R`$C9CJcXBy?N@c<#Cc zN7@~>kk5!1B6eha^X&P|;UEb+;Svt+cZ4QZXl+0b8lLXeMf@V)YV+LY#(5pT2=yhV zyIac?t`E3zpUK-68fLuY=#Ek6Kf~a=5x+wf&Wp@v{?qnt0)9$tk@szSE6uxInJ>-D z`W1LS6eB0GYCLw?W%lxY@ZW1BUvZy%%w3Kv5B@>Cs{9_~!r8c!6Yk@*#-TarPc-Cr z1YO`}shKmRPBaoPaNPKWhG`Q`q=9J?cx_0+6H34mX%cPRffy3Cx zcKpG)p}r}mTGEu}Z!%oC%h4Z(k_$;Bmu+>t79*-B+&LiwwkQ|5Wue?6P2x#M1+-{F zz?zYw9lKCtlL@41?@- zeya=Wy)89dbFGWhjkC6Mk3HqEgs#9@{tN%pEdNud%<`8?(-TiQB4H}$FK}y1rJLfo z78h~5Ao2Zhs~Ulu3*cB}IOX3H4mSeMcz{zY!#NTEesJ)6JwtE^z^Rwv^nOn`yGOwJ zFs2@G%5a|jo^aNUfU`4}E%|dXiOg-z0D9NX`rYJa4a;8P8 zbafx{0^V;J)0BZgtawj9EZ-UWGtNb@yrU0nh57~X>iJFQY*%l#vS%G*Lzm+m;syU{ z4)NJjGHk&AiaiVb#&@V6E|q4)gp)aR@^@-imP%`56lfbt%mSYlsr+t2iP4D#7`Da+&7-csqyD9R!}ecZhR_dW)@?G}Y|1e+VKKMz#{-CBTdr25m)sg#S$ zdSFAsyQ8QMJjR%JuXl$9&bsBZS~%MypVhqrs;vG{ zZ7S%x$z2Ulu8sjWG$?geV2x^0rPNs^*QtRzmz=C~X|!snP7Tz#M5*)1Z>h8SWS#k$ zIxXL;PTLQtv*cu*hD@EGM8A8TCDMuh?^|by^kILtPF<$Xr@vR7dwxKjPn@h%lc{sr zusX*NtCNR1@%#4immp3$rDpFp*8I^o*1RNJb4S5er<>b|eksUX4EHw7-wGNT&T5GP z&LlXiCptJw!kLq3;Ovta?V#4>hc9z^`AF`fDsD@(OhD z0MusN1x)?L?^hG}X$R&J~dLOvJv`nc*Z~p_WN z)fu|Rk_+vbpVG1l7pYKo2YE9_D0sGHm%D-y>E$o0#k`h%F_rea?haBSeGRb!+Dl_^ zRwK_m&60uM2Cc1%;Fv2~AmyvgcWkGmL^A9}9Oc!p#-82fxH&e!_NS} zJop*mS3p*!E8sU7elv;Vi#9#*4K=ntzG79nk%0erV_78o1&{Cg^{x_WW9lWxKf`L* z5;xL?inNZpv)`6p^1Ko!@(d%2?zGX1*fv@wu*NUEdX%2AtOQ^@m_iAvgR}cmC_yvf ztUaY!k1|vutw%3$Cakme;}C zXlGsMjWFA2G2@MRrFL%#cmppu&?CVzTisWODuCM;osrvb5rye5IPlAYqB{|;7TX-N zaZXYPP}K(Zqd@g3v4f_iJEmHH^S4M`N$9h0p`URC{buwHj|7nVWHNYW0|MRS*c(0w zEh~#$j&!}?`*4P#Zwqh+M3HtShQxdE6mnbc>5=3WawK_$97&#NHScs>`yV1nEt?y{ z=+O&u@^wO!VDx>kV%tPgMG|e4LKL~$4bQoKa2M#mgd|pQ&$>aLw0AoSLfM$I0e=`% z&K!ytQeV%lyiks)a$h9Qc9Th;D)|W)(zBsIXOJoA z4M)X@8)qx)1E=nngxU)u!xCv)615jbcO_D767?5GXeClr67?5GStXJsiCzFkN?_eV zrds!6n?C7NBnY^mNzJI`sRXYhiI@hl|3zY8_0}J z%`TCCyG!AJ;7rS(j$)Z5ef}LK(%J;|yrWfzon}6&3V$14*U1w8+ZK2H?|FX1LKf;{Hli@VhwZea2AP`qVV9OY0`Q)&0D_G;+kes z(-PvJ?TJwyrG8$5Oel${HeSxaI;$!?qa@1V{0{NqyzzNV2wran?=fZZED~SU;+$Nr z^GHlxhOzA77`+W(Ta+=-20;Vf4`xU3!7Buu)7|PAxBq!I7|&msNaelP{K>(G zmDM6R@{KuHB~l4`EXGPtf!w}@f{iT3d?o^3)I0aGtP?=aGe;XF0drhfW$27j2 z0XxwSSa@M=Pukqc`%0ukefUiW@V$hdn6*xFz$a;L0kWl=8YEd7AAkaz*NuPgZRhO zcaA(ihMxKzeJdCqf73^&>t z)L?E1H9SwMHHQzS1>>vFk4je>-`19g_dS0lz`M53BGPk*zsrYc-9GnAj`t5EgnIzO zOOC%D1{^2S2w02?@I0m}ZRk!LeA)JJEkcm58wFZqRv(ucA;B3ZRo4HHaTOmOCBYZF zD0!<(S&v-gDxOmXv;$AevfMd=;U4uksyfaM{H2<1`-5AkV`;@l<~xFk7Dn= zlhkH<4|VjrNz_##S!W-5ijsry+xC>wN00c`4{2H0Rl?fkT}CuMB9{1i!D@CnPPdgT zs@O`)#)7Vy>{o7cz)}eoG)W^Rk}-z4fO*8|!+rE{T>*}|_khPN1e*jhl}IIR{G%^@ zdG`QBMBOf3!B&;eWj0Hcsz9$4ZEAzF{m9WiAqf6h4YyVZKEbq47jAf4d)=4!Nv5Df z*zM>(_NjLRaFRN~T@a~P?d&2SDL?0+(M zz^bocmda*;j9&<}Vs{=fK*J$-pOrjQQG+}B@phBv+VW{3Qi&+y35 zJ94S@ie4wxd{Es%ta+gi z?Hv^!>~FL|+@nRCgy04SeXgP#g&=TrjSyTQAWx8~*RTcgg~pZ055C_X=by85SOfa5 zg00A5+Y+h>o)=61=vUU9tfzhbE&3OJ(^jmMS5BH!3nUdnLpZ6I>`yyl4?QUyY|l%w`xa z-@aA6#Z0V1a3&Kxq^fhkM)lQn|77d9FkJ@{me9D{nAJnKJ}c@gaW|g}7~cHHErAsxuKjSBiKXxw+xhxQhF)rG0}q5+ynD0ztCvW8 zg21)P#b>Vn9mi`6z`O}y+Tgh9Vw|7kJdFsO3c<^SUj$a6KVK~bo#xJ;Li7-aSZu}) z8FuSly(=dJ>jQw*x|erVvMluXZ6o20sI4SEd7u0U;PI7TTX+&IRk$&!2K_P zdm9|@U-+NkZ}|&%6x%FBSG|*LWOY)$j{}%Y+r% z?}y$9r3KKQKQ`mH0m%RrgaoI1!clm5ipS1If$q!e#Sw=;#+n1TB1y}Nr7JD zI`0Yaw-&IM5<2o!LZGG~wFCwR>)==+Wa2ntIXNc?{^d$`g={laU;zYQI7V5n2d#54 zU<6j!%Li`~=9`T&MZgmjinfFQ*@-m4`PL^IZ#fM9=Qtsu*PZKG$m~o9_}$Qp;~FZ9fX>pUDLe@IXdyRYMCe z?{kCR%8su=#1?fi{Aw%UdNz3k{N2oM(WtXc{@jSr;f1#0J@7^S-C8~*fJVDI2|l3z zNFSH8kntT3CIB9jSWllO2jW4w?$?Hme-=v)ux(cP$^cihl6f68qYv{lG}(|O!H&li zeR#J&58B)0${jH1hUQ~&N8Dohi-!iXPpb)otyZfO&Dy$E@()q2wlIt*J&GzQwFfH1kivd-?DlExpt9ltUk?_Y_NC_iN$3J@6iu zCQuq`v-2B@fT!ttA-Gt;?3A~b!|=yPpWaN#aBYlM3Uo`;Fr9q)_JP3*KMaCCX`;4v$9Vbqr$-MQQ1;|5 zcIg>r`nSmIrBps6a1vRIxhI9^^VY-8e(Qt-~j}$ZPN)>9WPGtj`B-8n!;a zb#JlsVq)GV^hLiNe(iULUv&!nyAsKbimzMjD#`e|sl-+KJ^gpkSaKcllx|oZ$rN(Dl*tS%md=NEl|vmS_{ASRwXW|&ziZ{%UKml^ z3vz9{Pu9lodKT(<8h&@mb(H}P%YHBotK=H*7*XS$a*f`THU4EM2|A%J2mJJpX2;al zrY*+d-`MM13jH5b#@~viFW{Zt4N6(v8OugvSl0z9rTls*zh#50pPKG(0c|5K=K{xPA^Er`cF zxPH1Iw0nS)|I_>n!q>&~ZqGk3zva2n`4Nmmaqa+1CBqOQR%s#&7-OnPIL6%=9Q}1E zD4K+dBQ=$WcO|qcPl8jOb@+-nr^=HAl`fPMcu#yba9#YpC93zyWWe+sV~9)|6TDYE z-?=ZQnhsB{cLXnLIp2BjqCKpbQM6O%Ks@U1j&ZMp=DFLrV}(DQCf#H_Xw`8?(x%9V zX=69Y==?|%=Qr+M(Xwyp8ff>ci$^hE+GZ)x>fYyCR>K{-NYA=OADj_SYZH!Hv^K45 zxsScNbOYS`^Wt(AigAVO9VNYH(2J!Zc-#24MmXTzQJAJ?h}yoswGneyHQ}qqbVKy) zW~wxOSB5mp&G1MJ*(a?{+3Z%ASqQx!2pkaN5Dq<5YxP$K)8^mW%C33Xe5;^)}>0qDD z19m597j8AbAJb8q&~t(_-x**0dQ4p!U9{Z%b4J#z!BzYNwW@M4z8Gq@jn?MAKZR{g z2nOJU3lGbj@a$4e!k~IR#$8{t2(jI|DDwQQ%$M@4;z!Rrex4awUSMn@3C_URX!diK zdv)$l9~)&z)3dmUs-`HM!?=nL-J(w)D};ML;>NY_t__AYkZ&M@y7^r$VxGL(kM|LGfEfB&Lae)U| zO@IsB7ka0I-3}-;82=P`*-^Wnvz_PUr)u^Wvj=oHL!W@Jah58gnpzSrW_j!dyjKGE ze(^Y-6~Wn$4fF1FUYee0ub2&2=EI|#8~?aph;UOmfMHW%*J14)+pd+{i*(;?egLqZ(XPo*0O)=; zKN0ADws$JfeWE_{l0x^1>WKEZr|G3kTkno@8b8pz9_XGMX)@D_deDDMlJx-%!@cpR zvGe8YJx58^?xQ%z$$8q@P|Q;tsMvLvSq*ZBGmLkMWJ*&=gX{WaJkK7&Q|_sp@J91} zfaiGZDY)~!@Z>u)c$P$*fG6tdf}}T~Wj1-ddYpW12fr5L|7g8@MP;n`OcVDJNaXu!%D z-Zn}FXYvuA+Tqz)N~8;kJ>F()ZNfgBZQ^ir(Lk$b99|%e0lvMVp_q~JQ#^U`4@kwA zL?V((8!hW_OzCx)-DcHPO^BPC8=}Bb8fmOLKXQvlBWX3yc(l@m+NStjC0yhea3^1* zmM&B`#_uZLlX!TlDcEV=;J{Jt-u)YJBpYX>EE^nOhO)7^Dx!9&GwnYwq3A=L=ltM) zh%tc%5jcL}RASB10b1P^q?5QqMw~HT`QsBr$0cT~s1sUXfELXE>xseT3#4-et;Z1m zn|jKZ>d(}YN<*iN3UN~kL#ini;YPq$t6k+$u)MpNmoDU;@!yrICgeo4(pW8>pp9Ue zd~K#gDL29SQ>E11r7wNvy^!mzOmn|BM4tN0drm3SB_19>G0k1{nB#?B@zcj9T;}Dc z-Db8p+d=1UaO~c{^{96TJs;w$1Xwe#cds(zh*553f@gm4hVzcN&0IyX^kuvqxVj#= zWtz+_dijmKhz=rgU4}wkao{_bHgokvoK)E|^TIFON6EhW!NDzXT%pjbp`GCjjV9a( zp0_`-Fn>x2B2k>9`PG8$R+$qcaRrCT860-Tz1vZ;W@d1BD^4moudUq{@S91cEnQ%w z(@6D~VLL=H#nL;nAM|XTj#p;zN4aX)s5xXDcrD`*zl-C_{ak24ZU$!;v>?Z2$Xwau z*>MNx{W!_M5ugo^P8=LOb}uD^=ME133y$5h2L}(r@m`10wpBRaEw8P&g!%Dn9pm`)R^KRyAJSYk*_BWB%W-XGKh4wlp`I&Kd{*zX)F* znJP|%$mh;6YaNGs5zcJk=OT^-6O|Pr1g@fBbOp5Z>i9(wQez6<*Z8BqBQ$`l5^8Ag zC{`ZX*vR#^J4UhMgOwl^w*ddF8U2R@%j--q!Fay0emcAUizdA=%MSm)2(NS4*)Lgn zh&!LFKReAWr!y_^|BLXb2)vzlBYPr|$J4}oVo1za-Od($@ngMkK@sSDAIh9X2U~C=^~=@l%@c#aysCVSqg#r2spoC5^mm!>5*M8K zq;1eoe7?+3?a@!4N1&XV;v;XM2-750;aRc`DI%`vS+JSIwthyKB`R^NO!p|VJBUV zv;J-bECAvpT3-SGzX8!M8^lX;JE8-#?GTm<&#)fnyv@M>D{Ri}+cWsbx{ zpnt(%m`?zEzb--eCjhoOF;7Jk^XPWAL}|wbPPrY|GH8cC@3F;=Z-oDHv`9LXD3T%x zd2M*pGoN{XiV^K(SMC5WaL;(04aX?O>=PU##aKiio9L=$3yym)h9@eI6Yp@$|C#qX z{ogBHl^Ln?MzbqetH4TjU8o?TLoGoa*QQ*fmT$COBAk#ua>_iO;(uy5TLNwX5evulc^jfwg9<65NO z0ZwKYeI_sSjUV2JxO|=XAVw{9o*#@GjIbxTXopBb;wAy&sVIt$+GZ{i3nCST>X?oL?DW8WistcQha^nEi z7{XcJ8kr$pBqihc<)mt62aGOHSUuC&&vDMiyH6{C?zON6l&1dSJ#gi9EwA5Vz_MF9S+!1WFX8>Ab16>2Nvp!(z6-d~xHm1Gt6& zM-?A(2;o=cOk7e)))YzqN?{CHBpDNURMyHtEthBaCu$Vtn_J81WZmH!fWCcLFHZyL z99!XdBB4<|Ie_yc2!AE`I>_hIxV*A0Lj}={5>?r&$kRlI<9avjLU|g6@+2TNA~7w) zxxH1<$4R}suR@V@LBD1Wv3M@SJ;W&R&nF3litt0R&U2JJqxF6*+v>VEGhbu!q4hG7 z0^dx}PVsG^s>fU;)%4@+qODEC=-TYnn6@@%?4mZ#Cv@RD0BTeFin{RYE04^3#C4}r z^$2i)PqS7xP$*Q${Z%5r_mx+>9bs6gG6tgu8}*JJ?NOTTj~BStNas z!ghP5e|u4vjO|r#L~VjuhgIR4h#8?*XH zTMzHKVm&ckGtWF`)nkGWIR`2B#}uDdcOHr9D&$;0;97NNUo}Hlk;D=WVkk{5yr(C9 ziLvOx--+EZvaLHUbZ$!9f#V$EXVUi0ACIV~2 zdy7D$8oRDSeVQtZ7`9#sXDl_c#EVgE3tpALl|Q;EvnmpybwyF<=cU>hvHte>XV2o* zloVn}<@XW4bx~7hwM&_7^NOSsQKZHl(IWWoiISjkHSjn1b-z7V;oW;d*IX!naSpVC z-s9AP=RvB-#Ox@$-gk%D!lqXA#57BUb)Yf(8qHdk8)^pMgH)c+2yipsr;P1uagM;9 zA3?tatWDe)5jr%j_)NPF=QRYtkVQ4?aGrqg5PUd4fZy;GI#5ckWTXQ4wa*h6e$Rfa zZ&Z=g+h++BNe7ce9AzyUHj_{!jfs-U&x9*HowB64%?RTKdB0V=P8%6sQUJ@SUk`1v zECl-GWazU5Xfpq9WnSfB{|dI#MJDJ$S1CKp75RE%d6yX<-jF87L!c2=4`MAwXq`je zH~T`6U~XOZ>NSvKEo7wX&rqVK&w?_%L=Ui!Clz_Lw0S`ub-hQ@X5WIii{Rb^D98EX!iWIU zaybKe(KoX~>CXN(cw6ViFFHNX1RwT?gUR%>knuWb$3Zq+KD8OSL5{pVrpTu+P5eFS zi;M*i-X$t~A1d?NJg!8rA4!{hhKR8Pk0a;K3#Ci@^VSx?lZ!w;>iutmeAH*;<088e z_@H1d@^hhN2OCpM)SIz?a^bqZzw1uk%7^oSQ$J4fz9Q(odZSV1gL;`a-byy_8h#JB zB}uGy>3**Z&b>*sEEyL)M?=p4XN474ZrI&@)fvlz(fg5IeFO9?u1bwU@x>q63`%DFqKw=I%o2L<*^3PLc`S=IBwO zt5CW50)%bSv~n;s{voCj&bidEk|wJ0h32P;#aA%DKE${_YC*aG`WTikI~j z4R(!IpsW2tP}*B4Z2&wgS1RM{o&Iy?c4P_j=MmNw*RciqU zXTukN)$0cAR5@BQN27fFS%u?^eR{feE}R#+&7ilui0$n!IZ8uhJeg4MnZvpvO7oa^ zibc}%i9<0`U^rJ-wzPp*`JjOnvsWC+Fnz3aS4o6Scq+hk>^yBp#zN3vFUdL5*v5Ls zJyIyW+c!2dmxp=o)yyJ$CBw?}q7SkzX63Vw_ANKQWRaKZp?8wiXpaI$xHgVE zsnHI`Q47_8MnezfkbL!LFAo~6akxg)t9+zt(}LfkPFv1{XEIavOx}^p|H1o+oX=h) zy((Wn>TPCd@m`JFPwKP#;)*^igqp6%YP8M;@i}DIFpUPiMy^GTmUAUYRzcqi)M!3v z2iXo9tr>iPxd0beN02IgT1R%DQKQwvyN3Rg8qKR{w7W%RH*!UKaAv#Stp{zUQ8d}Q ztR|C^dFxJUGVkl4$*fsT<~BY8nrxk-$v#Y?R2~6(WF@mV*$KK#9p=}gHrp6i`HF{W zGeyeW@hf-n>*21&*r99h%}CjAfNsmfD7B_IFYB`(%lb?u>$4eg^k5zxrq3Ye4UUqv znf|b9lZst(iat|;K2vQvlU5VL^`O(PQgoUh?)wxyuLH(F(EDl=*EHw;#_OV z&ESk$YradditB%B(L^~~=?9$zX}W5h-Z znE)}{?0|b0_bf!_3(f2}E@P&3tH2LIeQ=(*a727w z2pX1J29A>8s^3uZp@)(w(AIb1I9N3}=z-(eV+IFT!|}>7xDVedzrm%*w8|#}K9>F? zF+!ck?3LZe@;NdNJmi>a!#Ht6W*VX#qa&O1Ma*dvC(gBj@ljO1xI2f zm!eD?-pU=Y819QUJ7$UC^PSTZ;|nUF231!c#A@?nlu?@@BmyOxW2e?vAJav$V~P-+ zL~%qJcX-LmU?H#VSXn4N4R|yI9vlCQlDRdCANqTL!@Mz@?sOhdzJuL*Bxe5Ekyv^1 zNX*og_XyzC*b~#gkvm{8fF60^zGyzL0?E?EatH3rITEYff_Oa|_3H9u+_=+li${5u z%XAT|t6IjdQ0kWVBf+^&RhJju9Nz)$-6HrVbm)9l9eUryjvSx0!{Dp#$n{}eq3BTC zd!whq-yPLO3SC7R*bnw++s=&!`>tJ-P^&EEze-TLGe{@mDi0$oV|g2(rM8ol0Vx=h zc<)Y1{(URYlfwGhF~aRT@wbbM#-WElvai34li>5e&aS;Mx=5|! z(W-p;pAqIK?xnFvO1)$C?w2Rm!FG@*l>Bp|Lf1kU-I}E=wE#y& zohSA$1i!$t@7QAO;c?AhQ3-lk)iw&D>??isD-~UE{ElU0T%q(z|46D|5Wn&cWe?7R z5pWBoL;VO-wSJs<75D*I2f|0#05_;W#@etZE{Js~5KDme1YqV|M5=Ml=-1BCqG~`; zfp(nL9pegc2G>wGGA9gk)692Ze$dE#oz|uU2mCwKELUFj-X#ik)ox#4pGd3o50e1{ z#T*udbjcWiG@aC@!?cDAQ*n-n87=<3AAr8a(mSC}C~v^>*U07PMM)jz)Mm>IP1(Bg ze^6a}qkemVbTmkUOQBB6x<&NCaOKi!@xi5}2G8Gew>Ei~Dm;t$@CF$da~2nzEr1fD za2gdbvkL0YcbJDLhU-3f+v%A-wAvIj?mdtexZ*-L4Dj{{>}|xF4u6>DjkHDx z-MWj5;Q7K`AEu4OtJNI%Fl{BoIwnZPdvHHUu|ZVUoCr|oDv{LYA0a~!7c3r=#i>E0 zwLp>ae565a*hO3J(W(z%drv}=b98Y`PB&*MQ@n8s-Z)v~6$_$qhk=~ zuKh3M&Doe)W&nEST_e*4=v5@sKk^UIMs!mC;q3$7>kOf5;puvZI((IRzFeX|JT4Oa zbn5RDNAY=Kn6@mCyqDag%{!o!e9jEUPi+n(WQ*Kw*F6qBRdE~wV zss5F(e}y>MLAFW{^K~O7!Vf)!@{{39xrZ9$9Ya131I3yFQ+U%aa|*ShM&RqRWgTON zDBo!SPEhWB9>zKJ`(-;cRo3|$ zQ4k^SwHek}+&1uw|DCFtLn>D+#=c(e#NO43O8=sqq1{3K<93hKnPcYM!f0hrOx3j9 z$vr4kYM#-F^g*GHtkJAdtv}L7b0GdGCO}au>*>?xeEIpYf9ub%b2#5|_i6VGnYi4- za>14rNVWaohuua=5zzk_9N&Q7$=(OuskHBc%vTN!zC|M4PAc0ooN_93xA+ZORnBo7 z(yBQK?cr5o3p+*ZGQHHX|oyP{_bB=@&Wv|!B2A$sYIJ6oDJAb!z|T{L^8<~ zoD16D_Dl3{@)*w=#8$D*VGaEtI-Nr%52sVB=yv0t(Pp$aZp?W?J67Uq5j{>)t$f+R z>aGlZb4{Z7-RvB(h;Fp2UCVHqYL1PicC^;!BX+OfH0I>d-4rc*ebp%;`d`kv7v=l z&pdppe8YV)py-fl{ox_|JG?}jNUBHJ$YH$(HWD;{%PtBwa-ppET|xg|?@~(u^***- zX!7qx4TsWox+j3`esw#xT5e$o#{~Il*>=tzlWh&PVq3Ttr7h{e{~f1Ln(xMMP*jG# zi(jET&987ldp^wUFnUi5`diq_q9FXYpzqbXgNbDPmVnWc%L=4rN!^^~PSk_m=*2_> zJoEY~GR`yPbQ1jd7UU6xwJ1`rmSpEha`uvf;~T{C2L`@ZFwNsS$l-{&~6$*J4O!z{*jMs?EiPI~sy)tC>3R$J`5X~ni{(@< zzFzr`3=KWLScvd|;{%DDlQ?$DHjY>p9Cy{d7E{yLVp`%}Y&i?}azw9SKHyb*v*H)v zyR8YMto`%n(sB5G0G(JM!>Kq+m?qoBibdB~x&hiWz`_O)3jpG%*J3)Og#k9BkPgvb zQ1bCFlr`hlVZH{jPFB7vH?|?bi3KgbCIz>~FYeb{-I12=z=2rK!mWGael3vHxf3jzGoFw>t9A`2M!+`%7_T zdBXJtQb9uD=gk>hy-Vx2|8V^77=~Ygbi7}|uXV3?N1^oZD6UX0kbJxLiS`y;sVXpg zd218sh+$U&99ar3IF6o^@$dE%gUeR7RKz(#KJza8!)M-$eGY-O2Te@*dJXXDxN`Or zvfA<0{5;`J>YTM5t0SwZ<~M`5qSgritxVW{h} zO^*7%KkS&XzjJA1J0~s@9};U=N7Gx|Z&>7pXqW?E^eoqyOyt}dt%(#MX04C6RK^Kn zcFp6Tc`xg7+yI#6%C+CXHaR{xm>02E2y71V0d|kKs9C!s`& zbQ|<0)`V;4u5ZD*K0Qi;txG70<_->;;rKsae?7><@n$kONLpH(y5UEb0uA7}qGh#X z3dn2QBAU@_b)c`kOAQS7)@lJgYz|hp;CR6huTaa=i(B{l0v5177SIusT3Q23#WJP= zY-U8;;eH+CTJVXSTL(X#t30#LuRwYsg?GA^wulO!bS^#hBy}xqj{N-}#IyzH1<1IC>2b}!!!K5x{g5NQzad>oY)h%lwwRv#l;eXi zu3+%vt|3boEk($kOWiW$$VtfC`b~iw7DpE091ww@cZaf`Uv6Ja`yQ^}(1LezO}f%{ zuR|B2)0RQ&=B1|?=~7xp7t8H}pI??dF_6nDTDCfLy+b?*@MRuU;5z{NG=NU!UdFeI znV$VqT-0J0*Mkg|vA4@j&Pia&F7H=7GymQLF%_+LTAi=K5#gX7)z6y^eSW92+<9rb z!lrj#oaX0^vpdrKtWZofPVX#pcE?l|sK<_v&a9`dmUm_%=3p@+HB??D8#P-bmG(JD z!Tvn?+sp-0O}{(vu{en>YH^Ee0H0Cpo^qpe8a&DCHwG}XK-!x($1{4d2w0uF+&R@b z$%$X6D0gy*-?@OttTM#I49^Rw(};JC)S|2(y$x^~CA|{#@5p6*1rJb(vrz#jRy4D)xPeorpjr=?*gaFH(Y zVBluZCVWMKG(ObV3EGKh=x#C#(Ez>{1tcAla24Dj&ojmIpCQ zk8r*PC#2Rl!8WXLc%|Qa^VseIb^e6j1@XCLw>)b{h{(tQN9Klh4+!}+y&PM}{$JYO z2EK_ZYZ$*XnIw}mO;cK+qy;9WEop%g5TPJq3GF2yO8FFBcby{Y1X!)Q`qYnITTrOD zvZ_gR`uKPD_-8@+r4f7LBt zEwmDaGjeeUR|&t*Mvhf#dru$G_MSfQRfH6AE+OF*eaIo*?*4BogXN0sEagtz}vvM zFnk5xQ9Bvo?=Y5k-8>NE?lZ8W3>(v_{XU)dHg|d2swGDFTxvkh8^TTIz*02~ITtKz z!?kem_q#}&eilQ24pk6xE>maGnnT`&^m4kZ=7j=2kF69YsoQ@xIQ5MvBV*>1Z zjh1|keir-t%U&$CE!iXZbP4oH-X%}Jw~o56mts>&JqdNq{MJ(6T9^3sQhZ7&R-*-$ zTUoJKdLv5Me_h(9umowx2pF-eW-g9+<AX)tex=xoz zz;N8rg_3FHX7M^Lb5H+OV@_R0U)7%SamM(o+-JQbj^90ExMH$ACT54XL0eAx7bhR* zSZsY+?rxC4`G8$nXp_julPflfBNDtYBiJAkK@df;SsaLqu_vCEq3=63cMR;+8`#0m z5ANX4RA1D0@aNzTevBC81&zo>iNGazaxu2XBds=C1zvwd&l}?48j+jRG_Np={y@Ww zN*Npl&$E9hSBX&PX5Qp4%^Qy znlPiSUc?;h20{X^+V{XJ5$de+c8RZX)r#V~W-i<;WvVwSh&_C2$ktN{gRoLOoM0S) z(bkWXdo7LH>UO5u3MKaeWps?vD&>)YkItqy zpgjm)mL-u!z8j)!4WfaF0*rt$1zv}7>eV0W`^kPGan$NB(y zQPkmF4;1zJH-JWO0E)KcG>B6ZPT~pvVvtv~bDhcE>4Vl)Ss6RH1p7W(R+*8j z1}q~>JDvkNg*&A()lIQ^U>CvLPUIc5js&o{#vC;R%;goFr`c;f!NKoEbc0u*!_jhL z$=IC=3zn1D#wlKsMZXxqUxAhrrdia8CTE0VG_MzjCwUWO2Iy(9572Xwb8{t*evfIRA0zL8@o`!r$1%HY!zCQb zMuZws=ZLygj#{V1lLJxj58>nd;Q*aLmScSuyreg;-9aO|Os$dw?= zTF)3?1I(74lAvD>MuA`JDm9yR5A+Iy*_4l(0MmID9Io@7An@Buf8k}ISKO-EPR6t- zcGj$1i)WLVd+C4Y@UwJ#)?hTm9R|Hu)XLkSSEk_^tr;%uj1~cVHpd}oC(&Fr)qr)g z#MBA3)#9Nf)`93Z<=~OiXr0~_%~Wfn&L3Qqhcu9feO{b_I+Sa0Pdkw!4*}%6!c%OK zNttK5w$gpVO<&eZmgjEpxT zK8Zf{R`8P7Lp^7EhYoWYS7~AHMw(qmH)Dk1ZOqvW-0DvrLfE6u;S` zG8~?MH!5}fWJ<>8g{DiJu4jZ|iJXULV8GMMl9KK0T2;UbC~jJi(0zm{`6dv*LZt za@J!N3`AIX(K>Jj7EkgJ#_lAgvrnS+ovCi=B_9 zGxam+b#HQRBMuS;&|+x?BN5-WH#cM6U-E925XSo|_5zF!@bL2;RhnmCu6y=OrtaAf zdJif8LoC2~u}|_te_KA#C!1)!2D!~i#`{j958DKNlc^R#&y=Gd>ku8_I|>b#_^=;G z$<;SjW`!+^Wad@I2t6?&FH|P2yMD@7Y;GC&ZH~6zRQ@A^<=}1dvcj>5!-*uNza5Jc zNi5#`7D|)QOiL;b?;I@nmpFhHNaE1^Kf+;Yg8P4jLoJ_*!|H>pmVFxz^HOkF2{_Ew zaFD+fhwMQdCM9vGzy4U1jKSFaIc@xu-&CIYU&P{7b1Dw@gD))oSN%Y`|3C6l;{O#d zsissMUOn))B@DTE-Fo2ol5fN5>J*%w?!ug&-`_98zO7$iWGbUex;*0s`bPa<#B7*J zpX*Ie(ML0r`e;_yp0@etUUs!&_Al4xl5bA+*XA8Q)O3?IjJtjj!$c4>Xnl#Xp>LC= zy}9=PkrvXUFzEBX4;sH4t~1L246eohi*Wso)8UE+(`h}}2E=dG)_7RWcg{X~vt%9l zy!fLPq||mY0QQ=Lu6I7?wVWvNO{OK<`bMTYBu2*iWK!e?=tw>po2l|$lGN&*b(FSY z%ss~T8!6wfTYDW&LrKO7C)9bHMAXr2v1B{Xp6OpP$HFM<4c7%nNSSji@;L3;T#G^3 zXu#(qq{canXN0)Hdm_>-#q;w0F4e$1n!66_WVN+0V@I{08H>>%wu`LHSAY$qWgA8u z^A|AWNB`BQ#kP2?)kH;KAh~DU8n{c^w|TETK6;W%9nA!ly3tLcdS;q@r??3|i!2_ARY!9~ zskdMb-g+%(?9%X-;NiGnIsw+_E-&sCzKoLdT)ZJPj-GRNJJoW&+%acff=gR#@zL$1 zKR;8gQHH9ci5R{~0 ze5Z4|JWWDdX?cRnIFvhu`YIm|nH3B1hy{|I>#Hn2`jXcXwknbdb<_=-j>0^^X~J~s z0loWfkeRmM3u6cP=$1HWwS+@J&fBh7n2WrZ)A4a4+kw0Xa5=IEqfbqt)1;+Z%k`D% zCoqa7&I9a>O_M^W`HCax_a{ph(N^$TH_c}BkH}n%g3zpUcEv(QRT*-)|IC`)n-ve5VTtNgf;i{ARs?lT4R^_ROn8>qU z{=`UM2_31?14h5z2{I|vsnOtgP1&AdI#KLITAYpQw0Ojew0K0L#cN7)#!#SzHntgo z7N*6Nl;(wS*4+xUz&U$&kke?PS)%%E^+x^o%DD{L@L4KeL-szn;Qv2f%f1CKnu6E6 zfY)b(cr{&u*V{?FkkZ@D^E#&@G|owe_d#!s&Fo zBwRB3M5XBj&WqrDQ)%=LX{emlVO8d{m|1h6Sw$s43ipmP`0ps%(u z+w^=9!8|YT272AllS;4g8omC{x6*4vl!RJAN7hy_r2mvouXXfMN+i&JjtnQ`Vw9Im ze~8yDys-o0^J6}dH_r9n#XIYh*+j&QrVw?I(s^MlWjN|kyE^Ys%V{fds2_EU@Tff2GoEpzpCzfG;~ zs~@O1s`IAD@+8=@OFO^{og>|wJ2IDyn^<91-r*`lE_~CdTSxszxiHak^wv>ki4?lV zFN`f8Ru&>fa}z~X@Q(K;3y}<9u|OS*wt9)Ok)%cVM#IY=L`{W;omp=(E#@6YfO=i8 zRfhXJ@V;^9h&S-Q;bpKIdM$(bBdyvRrUPe;L)mi&ay30l>u4UeNVozFEl&P{lU3eg zhdY^xOHTUQFtTJML1f!`@(;9KHhPV8Pv}aTFO}y$lsg`*m`o|Bynarm=#ogxPOOq+ z4v*P{nBoeZ#z^18QNjY>5C$|eahxA6NM@zu)_XE{LZ3|O6(piOLIkl0tfVq0;~stz zBeFwl1}zq~@(2rW3HegddBZ;zB?=wGr4i-7o-_y6i3{A(DB1R6<&n5xF2wlGWqU&R&=TNE%t;+` zuFCx+K@RcfP3PR_%@_Fd)-TgyW-Fe>bD!tV?oy2Qu`#O|Agh^DzEHBoI2+VQUsTMN zgFqM4xw4S$yye_jY1W(~5uV&Ttil9#@4XhYvcdco$jU2DW_-p;v?Z^U+))0tIai9; zN+YGo6{XU6u;(YwDG_fJtr8pOY;OQ0H%bTNLI#xQOHbk{y?d$gJa_(%nAI{`5@rFc zRijI1NNmi)&cOD@8qb@*EIiMDkuA-QapvKo6KgV$7O#`c0QYrpJsh4G;mO4|PJCil zM{9Jt;^duFt=touO`)#J7KJe(h4}NvFFw&IU^;hsd6BeB$8G7K0Sml0tGq-qo#(!s z0k9(s85L&0`5_CdY&7mt7&9{wFkhN}@{d6M66jARjYQZe-9P59mr+RyT&t6@#8<=3O61mJ`jgD(fipY1@g7kgW^~R( z-eufFPNqq~n`Y$AWr+fz2pVFZPh4VV9jkMvcSHxC z>}*ynJg*o*ANOB1`xIEr1oZKp7!9q#n+dwO9Cb0dx1AK>h-8;Ba|?5&DB;YXC?+C> z=;^@tk)c|9)={g%n~P}~=*IJ1%PW{G&2h$jA+iU0({!>*TTOGQKT@z=w0%J)UwRRA zkT0oU_w3i_ZNdNOycF8kl$9AHPYl3oR3!830B?l`FN_Sc_juhQGc5;u)s2~A=57q) z^J%AQNrrl`8{k5?>vXtT4ekPMgk2buh@V)MaufPH&0SVyu9>;g6lYCehnh`=`o))0 zp#I??)V|IP_37@fL;ie5ZVKcr0D0ZQ`5j40Ya<_ydqa-Du8n(h9e-@Y61JlmYE3up z2hpMCG^pJ`?ee*M0IS7-)xuZ{*#XekY0!TR&~MbB=e_~`3$gElzHgs4rj12vd~{lX ze*Amy*D?6~5)3-cm__gEK@2bx80G=X0t_$@*ha^Hwqc2Mz`y|*fFxz=IPieOml_V@ z+yvmDb|DU(Bnmhj(r_q?S(QI(IPl-V!TX&!Jo6149@cQM({Pko#8J#;=gY-xc6E-b zIj!DXHO>bM>;|yFZul+WvEE_0z=~CstB<442*1Dl?(BB!=wk4%=945-F&84&R1OJ~{AJySG|&b!=i&!*+g()|HRM+&xbe0t zcT{S*?Vh@(67ajTSxgI$AIy~w@7RDJy0%vqf-Q$Mun%HCa-W{*keSsYR%6_5<1OMj z+)=tw<8YPmztd=PzDJKi@!M7sSggnD4iIV4!h*m<6$tg4%EATg?-u%u@iOa!6{RBq zmLXunO(K#vPT0fRNhHjH_P%s-mnh^J(PG!nP*nD?r@^@9Xo z2NtMy4%rwlU}pI2`M9gy0i`niy(OhB#*FXO+x88`UGEyG8d% z@K_ZhxbJ;C%9Z1ZCKBqra-dvxO1TVmR2Ku~kcae=hpyDmC)j+hpItorB#3+jU;rpF zZYJZA!B^~z30iy&S;|oJ6+GY2bS0i&%uH|-JD`*=?~qjY8rZY3f%qv{ul--vyFaDg zb1{9lScbZzorKDhIB;|*&e*^kQXanXLd;!T?pk>Ez#`r;>$HZ!Vw@<6qa%wBY zIpMyFbg5Wk8q57KLwz-tuf2<&Y*rE;JQx3X zf+rmG3lqpto4Y}4yD>rucp#r(CTnI#hWcVRMj~_s8IYDk-50YzV66=RQ|An<7y6bn zQq(&?>y{*pstXna;}<^(8KEBVRG~2hR`;o5zAS7<%+bYu9`lNfHt)e~4p^Y=s8Im_c zpL5&@Jvh#{Nz2JMl!gU1jA9;>Lv4a&Rg9KpTCTmZIknPX5;=85Z6$qc z1>lZrXiZ*L#JFp^X2<=ZdxUn12!HSCW~3v2!4;TmqQ(}y?pvk4x(Ih5*OY^&ay2FD z$V7R2YK}i6lcD~;8(VirO-&~+&6xr^^WG@*3BX@5U56hddrtR}u^0~nxsVHp;ZupS zx+m!k&X>XJ-%5`I4t36V!NOxoO(z9uGBvCbXw%$Q@6{1z;`Eal+lY`hQQsqC>WEQm zoH5nnju4U|o8t~LEE$Il;P0GFO}Kxl1|zYNKnyUR4)=fFO9XY9AUz9S9=p}BCTyMo zyvv866w@>}b)RvDx~ub`HzTq`Ni#8}W`O2;dJ!JXVfHR&j*&?LHz;w&B<6|Em1P6_ za``oHn#{+D*>h}Q#}RtQ4gNo`-r$`XdUvIXF7)e9zQ}DBhsGTl|IuNcaMf{%;I6gT zy(`0x3BIGhhqB^`jovv&3)Kv^Ij21*i{AECy47(-1^oXiveR1@xlaCtLTLyLF&y7#rnaCth=Ei=K4Bk=2q zpju)!Ih?qX=;!cE;=4q_dp)raqvpz201LdjwU?XnTYwW! z5M`*fy?9d2u3kvSCtI(@Yigm7f-Yethr|X}B=RzjCpf@~2^R?!ay!`MsRb zDR~0)UvGhr*;Rmm-af~_xT@)~|)=eF) z7Hy9kGTbMMRD<1CESde)M(dZ6c;#)> z945kb32x*Z`0V$ViCX64aZsnKF%WGCYjm;;#QeNXVmT2=_q#ywn<7}Vo#aNiOI080~hXT+?X{KtqGH3xv7 zdq_yQY#{$3M=N~D6&G{9;z@@F@9Z$z3>-l&C15jbhze`PAn>s14*J;|uwstt8g>)h zC+;s$KA4?_$D;Nz8BS-#!q`hD;|0^XoX~%a`lXjg*+S{-!BSYpSyAsD6<%=W4dzd0 z4l&PPV6skFc8*~#WaU>ST!dA;AYX5o?DC0(gS56GhU~WES_G#F5sfeA@N-EKK6MA{ zD^p{Ic&bhE)M|VJBb+pe2Ik6Zz%IO5m%9C0E?ezf8)*CmQFd?!(~zY3ke)BTe7FD5 zWQMS7HG5IZ-16R5nsdwqbOmVi!2 zCP~N7JLNTEJ3s?;#Qt%&>2&-%+y^>_i3_M=F0KZ;n4e!GuYUf5dFnqbJBth#h5>EH zAZ=KpyvaKJp5Qt>52#^o3Rq-QqZ#mbS5ukYVM@kIVRse7NO8@|CG+oAsL z7tCWm2HLY1vNADq4W5d@T;9C@n~@Np=NM)><7xe3=R=3#xAmyJnt+Tsx}lymoJU@{ zJ-(AP-;5lQ7t-||dkMw2bbfu#*sk8tO+q!32F6dsevBWn$61QsTrjV!_g)rmrX7|Q ziR?Q@RlIn?e9z9Y?1kZ%bz6)VhTjS>*BF#JhN?tim05WUy>)|8dCPRr>kJcRow3aS z%}5w-DQ8-lv-OLI?%>e_f9RlBiD0HaMuvXjEl!gEF4zl?It<0uqljN~7e3`YqG)kG z>R^k{9%qUTVYb*1*$EnJnIKdToQDB#yo=V1O(}mv1z;608P;rvKQ8Mb4yGQj!l;y>d2uTD&Eo1EIw# z2A&vci}&G9HdEJvqq=Z}oDg&mYQY!w4rXn4HJ?Vh{9K>gn2lPn(sxm+%mKl_)17v7 zXPHnff{n`MvW@HxQ53*#y)Plj&|=oHD9bK#zU6#YTT@Q!Sm#|5S$Os#5&BbMcd!8* zHD`AH^)&iFrT`JHb&z6XfDbW6q|~TU^x6)j`p%F%Oh5a3~ z14cEdN5GyQwi)D+-ObG^)5f<^UDeWN@0XDmC7ZzRyydGpYtSo5bKd-1ssL-IL>wKO zoU|oON{JVzt7{I-Cmz;Urz=LAl|Ra&u6@5+vj-)z@`7%L*uH&)U0eaSz$!I6L{%yD>vN>|G(1s$Sg0RvoJb9 zE{vqPuc7^wAOQk*lk4^PCLY~MGnZUma_ zrMCl3*hPXNN6K=rQ_|S>f&Kww~OkJ?&T2?v<|g zEl9@dygv^kepbx8DfVs+A9^qkV{_Zp})$$%aBg=>r<9!p7 z{q~3M0sr`NdEnPTE)_164sh!HJ3pG5uf?wBYdI4pd~d!MyV}}$F<*;G%hzI8?LC;U z-(totCKf8b->p$-6$2m0{WoXXeteOP0UKzzX1SXlq zeNs@;EORmH2{Hv~vfY=F%>QNg*^`*h=q3dh=N-TT=rjz@DBx_HT@80WF_s|(V;GVT z?K&R~ zBTk(SdbCUez|Y-UA43h-PZW zFxPATs0(XmDaH~WL-l)q((dibXUO?K_4V(C?~wriQuyWp{&M*4{6O>B7Vd`e{D;1w zG()$P@k|pb4e+(|B%O|Lv|aCGcbVdxWq{*t9%th`$_7kvkuac<>|KjAjWj`9qZqHR zQ82hh;iJw*(uivm8S2{3{8|qD%dD-r1T^2pYLISt9B`+O&<@=(M{AePP+O6 z_|O#eO0A0_+y2tmZv{S!!S%j9ef<@G?(6>?NO<3YzW#s0_xt<%`eTLPrhCLe-NWU= z_?wbt*RJmEK`E_KblvkXyuY>(*BuPNyQ5Co=zPhd#fauZ^ZD~Z;@&RhP(DzCpCn%6bnoV@{jxT}Es(2JWy z^}IlMQjH~;o5-&2?0vTlw1~h=<(kUoAy;{{zB$*qr_D%lzUc9UnPABUor(7JxS3~) z{s2-+j}K%6e>P!uFg2pYB(s6frZ|6uZ#%-nz>mY^akV=or!P0j z536Aewa5U6hufCp%SqmytUFRSmHs54wOHxzSMhsi0 zAc>-UnuNd?Cmo|0GHqX9|9`*L*S{ZrFM;11;5+!CF2k?2GL2@s%4dFM)jTe~3M7?_ z^TzusND)djFCq6$Y1Cy`Xfy-27E}IdyE-{`ebSbgT%F`8ZEX=(3+q}xNaWSo)j-b( zuqMo5bJNB7XAWGc8MS+)`5Mh@^APTtK%)@>1zUT|L}$*dL{*t^f+?GSACspwrPB|Bp1pRA zK7PCiyngRUhGg#T>wg%&Pao^+@5^JzkoLa*pXBTF^ubmW_*SW!*b~4r5)Ix3VJ}z; z4xW#5#zuNk6X!J+Q!c=RCN>0cgr1@G=R{2tmo{E3#RO1dSn!ovx;?c+3xbjfbTN)I z*K2lsPH0Mjo91g47DKrvQjD}IuP}x5{w6Mv=jhO;y5L^`dv2H4iTbUhn<*G7JAKZi z7#SDKEe@>C$_DcV>#NT-9X&U6~X0r0B{? z$sV+KlhA(9gGX{1(iQ3JuLGSa!sqvJ{lmk3{RaiiDZ$p(Ya`3-Jf0%FC4*~%NL!39 z`h;&7P1mW5@z#kgWtm-HmYh%oheYYpI$4X76V({d3IX#}Oc|z&x`L2O1X6fqLE`-Y(XRMaz ztj_>k3>TvOgL$MhJ&bwh%)iFoy^dysO$MV?C+7ZQX5mR0=CCxUV`Z?Vbc2XohR_ zKdw4ky}LGVr$U(R-p-G&Km9?J%v?dA0PW`lRP#@tig#~!4RzX?;P6jd#^Yo>|czH4ZRJtlDwx$zFest6HBtO0bzW$G3 zoZ8}q@jKYp|1i&COzz~fF9)QD?jcq%O;;GDUU~bvE_0)aMo=`4nyp__5H&7{OE9c=?v*bd8iMX zcA-3&2p>S(6YL44Hh4N{(lmEL7e{ZCuk_7IwzNgdD{zZ8GS2YLNEsQ^)eYLSD&S+A zb&|%%Pb*Qde|_*PplF%0p5=e7b8sd9A9-YgJ&bFrm?cSDA2cB+rh`3WLQcH$OPnEG zF4PXZaclAoLfB{U4NIKihG}m+-@_%}Ftqpq>LUu5vd);U-XGJ}ZsE!ZS9irOdQ|D^ z+L&c9&XGX18PbjE>btRPL1%}DgYMbY*S`n86K&{^Fp_=#{S~+?rXpvE#DWK3NWnAA z5GV`w8G43bttzGz>x@(MD7ERTr~Px#V{hi__MQDZeM`Igd5lk~;d8JQ($%^iAz9Cn zJxx$YomLMcIsPR)doQVNzgF9d!PbP28Y?lr4$twd>|Jc%7{bwDgBP*$DS*U=PG_tt?%= zWe>*D#~Gt^TJJ~Seyp}$j%^7&;wnbklDMJjJ%7X8N4yUwZU74wEL<1PjUJAgGQsv? zp=}3oW31<_Fex5@;o}&>a4c#c@-V^%zHYi8-|SlXFx+iDFgqx&k#7cjHO9E$j-&bJ z)&s897zwK08xP~!<@H2db2w^uAhoc}3Wu-~ZR=;81M8nyr%79{3c>j#)}?z1emYaH=5_azbRH5Wx{~Q?dQijDI=JY?-Z^ih5vQ44!b~qdo!+S>T}!m)VFp|o1HRJ9vx0` z-O5NkYjOXt5WFtNk+d)~!SXRFz|(K6ZS~;eh<#K6cBfBgx|)NbRGAs zg?^v#Zpe7S947^KbxI6#eD!-ii+I-B)v2-HudSnphJSqe?3aH%KQOn>uPqDmQU=9S zwDo>Gp_ZdNdS;V#ZtE<--q?`Opa*DwkC4oJ2O;lKI*g9q{ zt`f`u_}+=`@m>~TN;|`B>BO+G7VoUsH(l0O2aiQ9lNk4Q#b7j@#OPq8Xpxh-K$c}g z`vyn7Hv^!3Ny=YslHSXmx|%eyJ6ho#eu&%Ys9=gJofv^lSnKyP`F3?()PZ}OF1N{e zK8bB=UIiTHs=fs%m+7iL9JLTq$PH>Sx4uhaeY$#U=h-iF&yhU;sOxW8ppG8(Z7 zXy$0!l2}TJ*>#Kve7;;QRwJ#NtEXs@g=Y#2Re=#!@S!qS^@^3ZY!{gd2Ke5P=?^vs z1wSdQ_vVH9+Q($<#YXuvEh2F|k{%z;VS&<8=UF58#8Lj%3r<02~xupQAdTia+5bZbSyFD&_b2BEl>D<%_=r# zdDQTKXhO)dICm*V_MHS5X!MqatQ6Z)J3Va-6+u#<55{0VwzP`htOWi#v|T!um??jf za2(oPQCtDmN&O_u+#QwY8r+76uzLIIW|5PdC2p&`0@v?k5wNahG@5LekQR+zHbh){ zUzw75U$h-O>uoTep8azES9BPzeeMi~qwM4-y_p?X=VgThi7L-YlkwP)1T*ud^Y#C{ zxzZR}GU_dnr)+}BtC@?ui?MVUje0{QF8rnMJ9rev`|EudZC@DG*XkJPcAv%lcEZt`b@VCdcT$`k`Y<81ei*g4uBdoBk=g_~MYgaWde+XAy ze$X}rZ%2*$-Ue&XAxO8p?03c)k`W#UKKE$DiadCBS!eZn@M%7b8ihG|FIPY5HAFJy z8|af>dl=dvb;0MHgV0MO<+@t4t$)& zkiA*oW)q~&`J}7IQ}*ShtB1OAjJ!9w^UtOp+8=;AYO}uECb$%y)=O&Jrqy=sU~OCX zlhAyqt0e2+86G@f33k{1(KY1TkYT+2vk z37{Q-)(6gW>-GmbXt@j2kd&*=Zu=01dk_!W46dib_1FJq!KVa1)8R97B-D{7 zyWsx_c@+E~Cg;QdEIAMUJLF;TKV8m+|5iC0{+s0y@Sl^1z<)*_4*xNVj!oSR{*kci zsJ^YPcUlPYt` z*mg3O6dCbU%G@%5?qHXRniR9uq*%;Nzy-K}3B66@Ne?Zi^P!i9#R?@d;o;6h92eG4 z`q|XG_vvRkZ0e7CF&@4tB_2L6y&E*e9Y&kh{gS-{3WL zOp-7Qk43JB+NWU2(XL<-?KxdU36vTuWq@T;Am<1+)z@XFC!z$b%RfdrhdIoBEe`+@ z{um|Xpg2}^O9-Vid7|&K>JS`$4G$c6kZi3Y4_Kg;kIqonU0Uo62)4j_Q z{K6N4lO^})Vp`-ML!X8biMuRUa)(?LJXLx&vct=T)BM}K?hyE+-DSFu2QnJpdvRZk zO|9u&n&3wZqtn&>-9)HJa0_t#Wk3S!*&&Q-p~=5_RuPT+A6*3wNuiKnN7RDA2vEE%6#`qqONzMl_ z2bbf((FBi~nS^c7Pj3c?By0<(1he4|C%md%J=1;=eEIbW+o9n3`uM`wqRh<+o8wNp z4s45)5yycXsll5Y9zjcG{53zkLSm%rMU1fZn22>_WYw*bl`c+jS3lzgKbbm2gV-d7 z;rr8ff1Y0-Y44ov*CU6Z@kYX->-rGm?yb{>Ch{r_(H@c zyXc|>e^ZI{yw?=AN}1Z#IO$2~c}Cg}up33pI>F3X2NsVD`cLY*)&FA9^F93s{)&YD z3i3?3f*R*%F^rg5^I8OGZKXIHWDH*|tqD45u0+ONh;$_Llo%sm57{xEtx>kpC&4dZ z?0-t|o+qU|X$#nNZ((#%$t17yz6CWAb!**|5=v?I17K%{AD5mIH%n8c&EA|4cX^4J zE)5lTiq}ZXMD+4@is=tDc!%DN*$v2e@cP^&QgZ-f%p1at@biR?)Ev-TXKdz_p3VUZ zW=Y$mya$F!&w1H!0YE)UUe)HLR7P%Em$1p(q@_~fU^`DsFN#k|rP>~jMxbCRog(Io zTf`B_R}vq}f%>w7BOV~dSA~~KwxH{QXxoz#*0bJQ5}A}zYqoR?;GoyqC~b#NI%bzx z^EA|&PRENYq1Nl6R_i6TUY)G9dazbLjQ1ZpyJfdQCSyc;>uCe{tT}hr99Sx42ZaZS z`x>ADapm0YkTUO{EoF+xQJbK>dibQ_E)1>BG@2uN#eg_X&I;x{uqU`w!ncIGtKcn0 zTJ$|{vG5j=9kgDuKEU415vH21!q67!Tbxhjkyph*K71M_!tBXnOU7{@Usng2MO6fB-Up^C-yu2cvtW+8`sfgY6BH z*t}m7Bu9IeEJ_VQE~$ePr%8bobPR!~26^Bvo>fUiaP+JRPWL1Ia7;FIuo8}ZW*PG- zosBRf4YH5UgOQV=Fc$9IBW5JW!aNuYGbBmExy@BEeJuReZ<42OQ zI2Nz#WT?l_SJ(J`)n!3#B%a7j9>86YYJygPGKXSpVMB*O!n8}hDNtrgI9?C=AHzs1U)9b9?vZkWX6R{r!%Y$2e@1EL^AYtlj-`)+wNvC{ ze}~bRGH8lN2IY9rO^hpDwZ#xaM<;mj^iY&rR-Ulk^mM14JPaSqWn@$L#)kRG#M+8? zqJ$e2N{{md+et*xA~TBYD<4J47^VevxZd;OL z=km@D6GN^igbcu1>LaBC@fYTVjjv$)PWsy4^315+>1NV zXHc|J4@Gf?-IUyw@m>&D{z!ht7_!BtuI$3qTQY{*N}kqNZZZUtpRVqTUR*OxQ(x>Y zr|-_incHmbo*C{v(`%Loawh}CT{y$c5ANO2F-cR;^pcPpaJipl$WOo?J_dhj^UTk$ z{HoV#7$!G7eNOQm=;U{_TVMNS@*bjds&AQ_-dlQP3tB zrme8&nFh`ZVc(kKJl6!}8|kK$^FkEHgd@{;Nr%Hjhm`9F@TTnSr|u0_k{Ssr{aN429@_US3@zUYx~FQysn7 z$_ufJ=YrhHb3tk9YM{qijv+^k==wn$vin%i}cA!3w?Q0N!#!M1y%UvK;OJ(3}LMlWeuzY=8x;U3-cPE$u6 zNPYHP)J+S3%15-_>#0uy@MIM{*{?mpea&fu=X4gHB|^Gd*2%jLcU3zMJZI3)nx<(p=%R#qt7hkMVf2@4*xHp9J z8IzJN#Vo?1Gw{ZN{e6TK>T6dZWA*em1F?a$b#hZ+a@Z2L@sH7RpxQ^h3n*}Z&C*2n zO=QBPa1qdw@wa;!x+la6s9BJXx913HYEd_X8vOwxz_>#m7hNKrk3g3V zTFrEnHjg$8#*wsw28wX#d3o6uq}yT%sg^THwd`ajcHjVzIPPi0aW^_B33754{4oY`8#(x}&e(3NWsM-`if)=ZhL( zj9V}uf12%L4itvLD&RM1@;9spIV3xSxbF#Ltnmzxs`37Dbc=V7HjB{`nn=mGksyD+ z@U99^_iyr6pS)jM7tEwXz=FIG$&sh}rVemG=b)6C7t1ri3*twoN&A5FvLvT=l`cIC zoHyCO7x->cbM=KX_lL^)R#B(n$4TBBHAuw~ z$=xhA(1&Hnd(ArUAs#hA$=2=_!7SfhxTgv@Wym1kWg{)eBK9wKn+L6`GM%Oy)6`cK z63Pae?mbV)M?lkZ_}&S8ak#awKL>ta``f;LmU3>c!&SjCUX4A3Em?gs&vc?uMjEl&;3*@QWF^!q^_Xxm7 z9`SM^iM$WLjBbb zin$Oc)XZhf6(Jt;t(-A1ymv^55m*-!t0G^Y0kWyDcHs;V*ssYsoiw$$os3z3tKpXQ zHyc(Siju5#B4&IJ!^rJb8Fs#yrheMafK{KSe%wBApVjVnB(L+6*GIH+Bp-htZrAp0 zQlHuQq4492`MKS2-F*AS>rV4%ZG{-GazYJrTg)p$tp}RdT$)2wj~l_bYAalK>UKaL zj4A&FtAA5hv#8spQ@daUW^gT<%WSUJ&*(mLL9^#)*MW6j^pDF zvrFm0J*YmAJR-OwMONB4W3;X=Af>XAt47vb-obvd0f>yoB!i2e06 zuR%t-jzfPF*Snbibuf2fIn`s6-v}_)y=GHOyKo;snp(X_@3T$PIxh)hPHjAwlcu`b zYvyJKQ}1Fad{gKmZhZG2Vb*6za+ITe%Q-@>dlC0(p!dBZ2-4cs6hs@wo-8w^2kk4f zk568Y?-{1)eQg%BK%nFA#C3iV>X`&`S_9wLzKHw4N!+HL3%04xD7X6^m*Yw1R?re% z%DobvmC<7gq^ZaD=xs|u8!f&M=Ov&%xkW2li#S^?)mGq|9?-kB z61U*y94NOmHFaN0c(ZC%6&wXeG}tn&l4?Ijvmk*~Q&_+zp!J%$H~SOy82v zTJs+iGc5}i_!cL3zo)62x<|-l>v6DUc+mk+?d&uGS00M8zGa%9UYX>W$$pSESCts_ zd#ZhTt<}gsP$FaYsLFvkbvNEKM^LZTOXU`u(wc{0Q9+uOTu{{;{;f>khYoB_8|3*1EhI(>WOfUN$l--GCJyvyl2xER=B$S~P^BCvT zG4#c1B6$=19di=dcWBuMZ^oE?Ts)7YsekIs1ASp#ZUyTZ>EWV>qZzl(PL$noIEt%{ z7!T)Os9TS(GQu~I(~T3X>cL*rr$ag&@Ow|M0ou&cD9lQ{geTESl|H8q-v{mq}(r$Bd~p;5!ZLeWObfei2=o`?!-&|}DH-@Y1ut&Rz6Fryn%MhIzZeQVMwbKmsfz&>`AO{#uk*H(NGwY+p+#SgUDDj!76LwJuVFrA_=luu25 zV+#pX(N^%&t=}TA%Y%RR<8B6w5BxR?uit+VReOI?#T{#r99Tg%g@ZW>p{VL7Q$Jb$Aw0QizsZfiU~4 zLso}yBq3C#i&pg~J!bk#-#+@sD0_qMF_(!~C%BuE?Pbi)OKtB+lyHWv);MqC!M`_# z>%FNb*{uOiHtnz`wV~;Elfa)m^X1xqTEFF_zp-gkLI@m56cDb-NS7t}U*rDj>@fQD zjC>8P$C$>X*~^{K;tsmMi10GsaShI+X9&R^wEOf9N}yb+)YC42JUMzy)D+K#(fpk# zH~XEa$?*<&jodTuB=|t7C??k!MX?xkdox%jdwOLF&&HuFp3!2%u`e+q*6;&O>t3DI zQ?tc8{fy`n`O{Rf zx5dwRTB-rM48{Y{F{C&VIh@FD{;mI1f~zAFUaHOx|9k6mR<)`J&*^*|C1Z3A@9P9u z%CX!Jv=Qa%ls+eJ_E}S;4Bp1QXJzpApC6B-HQ2FBd?4GEoLlujo0MmatYTOC^(|IGbqs!IMa9W%PXci>pYJ->S7?3NA-0I~!79?TXPP2OjF|#g%XaF+IZup0At~W_NFwe5+f$PVjj=gxu$8ZvYMRqp)uCZp4rFeaZR zDGjtM{^f=LCZSRl#%G%5f-!?>@UkJBHhR>|#Ti44(4o)Ok$5>*54r^5aQ9wKmw@&0 zT<|w>j?V#Htp1%|D;*dgco-itK}MRqY?uId*-q^CmC)Tui*jX8a?WL;RsHE+OFY}m zJV|5|^=R_rk){pG&$L1LF>IMB>6&S^qVLb;s+v(Nkr&08+Bw$&*}?OtE{bz+X=--& z#ksd*QDfT`!JLs_+vo9Q3Ekv-Y#wHe(xDsDbA;Xi*4559hx;K)hiciZEFj~IJnd^c zO{}0xEjpB=i-WU3moBH*0e4QLGbNkGo!I~_2OOqxBI;81aMa{NZOUy$$oZt^=S3ZA zEIUB(I}2| z2gJC|+X2N+Sd5Ot1VKn(oMG?aIPT2Tt-%38W^Pc)(k!=QfCgvCd(OR`5EN#7p6C1h zzCXT?aQoJ+TXm}H)TvWvsaqATUxBm|Cab;%#!i6EgZdS~h`ub%OCNRsKk^}0vAbYg zQ{YIcFt)2yRWLKTGyBvJ$F_Ps&P_{B$#WCrBJ&H0_=y`w6?GW^W1Ah@gFB(GcSigA zq0{)TIl{ZW5i^gzY4!Sikn0TMfz$7>1(7^c-A+hhz8^U4oF&E*1ADD^jZ7?X+Ek#T z`wNE#MwPteuzdBHE4|mcWE4h6tw=ljSdomb^}r9+>wfv*4hQGIWAV`k>G-3Iaje~V z$_A8sZwJmK@6>C2lO(KVG9$A{J!+A9G#)S(_hlw}*$0=@kA)tc$8KYs5FY{^WaZ`V zCprij>%H8a$-a*6v6>!4JeoT^fJdNZ1+my&pF%%>3jO>k^z)|?&i)aky_!Zxxu!<3 z`9Vm=W|O3w;4kMq8c8E)aZSTh)SN$8L(z+W=$H?`o$b&@=U?laLH}!pUTlsedXfHq zO24tt+L$Q)PL=2v(<2Q7A6nO!j_cb0`*eI;=n5SRCCc@5W8U7};*mJk%rbQ>IED7O zck2=AY?xD;L$CLvJh1i@*+6n8cO881`do8)*N*r4@=asM=I@9<6Sxcm*`I4A#QwUh1H4{G z*SMLhm}I)9mlZ4n$yDhb2slXes%j76o`GRrd#GJ?8&{%OJ-_}S13dR==1kJ$nb8|7 z7}p+@o^*oo4cuL6JhZ5}U3Dk)oZGk&R})d;{l=v(*LTpzgbOcSFo{O>~%R<6@Sg&TnHfv5k=PP{J#4nZG0C*sHSs ziPl+_%ZxUc)m+JZfb~*I34SHuvq*EKqK@AWD0+}U>;L2!956!r z%Svh-%Ha4CEAX=Up)!}bUfa92ATPSMV2{IeWo^Oo3DVkvKRH^0(eF3V3IwyNhE+0? zG_O7z+QGQBF#FsMvk#|!jpW1yxEp)$y$hr?8Q(fV7sa*}uzj}mR^U;HUEoP|sC$}$ zC+Wnm&#qtwNizDpUA6Rckc>VDEPNi}W&uB{`!PSdgK-;bfge57-Uj@r%?Wy9E#y`y z-)M@Y%;Gj~bs(qLgn0sdpHq1?;XHDvUE{5F9c?ET^x(bZNb@JS<`!lJ`+=@FGLXOI zAhQ8>KI^D^5YJZI>{77iNSb@_%wgtA$B3^$9yUMI%kBFK zhQVuKJog(o$2F&L0*eF>wLa>)OK?QzfGLGn<^YrHO~CVG4>}4t|I)=_m;u6z^Kk}f zw=(n- z%i=5cTC{iQMa5b3a$I%bT%r>j&&Xb1gP79smdiZQAf|Q5cIP?Yp-s2@!l7=o%j(3Z z_Frv>H;9+p(GG7AFSY;fXRpN6i3`rkR(qXzOBAAf`lbx?csuT>h)|C}D2e+s7_da}W9_azeg6!9Pd#M2VXBF~bk^(364c*(&9I9EB$G2Wt@dvF(S{FR}( zmmoZ>BVR=P)c}t&_mUJm%Q+x>Td*};5w?aa!Zy2?{QH(J+v|QGYViS-9IGr*_U^+s zCt_^SyOuJfX=jm4rG?T8NfoPfJQCRIcqs5SXunsjdmKkbMuMB2XI*X1-`D5;n_lfp zSB}$9x*m41!o$HLw$)J(EGk?Qz)`yJlm{e=Pk|HHxj^P7q6_8D=z79F8sBp+nlY2H z!el8|!Kr$e#~FqZJ-%KwYPMus%a4{`=A<`holm-!LuqY6v#TMZ@|s;(!Z7Ev&Kj2$ zPi2%SdmPkcPr&TTijJc!7)Ld(k?dg?&8u-<{%_1Eji<1U{Hd*uzX$uCM$+?T2Q`z> zW@!h*o4%}(b}+19xQC&A0PbO^>)pffww>}0hC1;?NZ!FvC;m00WivZA6K!afUK?_2 zP)o$GJXl0EK;4uledVDS)7$YY50J{9{17C_o-aLg;&XeVXF3f#-iqVu{xkCVpZ4>F zYM8RLp_8N3oCpx~XGaaxvQY<10l%+>#j$E3=rkE;oF}<|K3_d)mrfmeqaXPpK92ri9P@Y~$or2Qn+ndaxZ#)jhEA3G z?H|+`9XiDigGMh)gLk9T%SZB!WVQGdEfJn_&|+> zKVC?Pt|C!FNcQ6B#7)t)2T!)j*u9od!Cayj9cPI7-d5sY&_zcTON*m3=Nf9Ub+&-=K%k6UrM`xOYcKP&Ike6UW< zo++-lvJ(nlR&1}tGE3W^yajzfRrRQE;=Vcd?_YI4B%NNT7t2p;8MP$`b>b^$h)ZSt zJ}_8#5NbY`CsEpu2=(orwM#ltf5zUs z63E8#C9VvkslBL^{^}w2VJAsK-kA=ipE`x`)qq*yG(ztTqzdw`MMa&;CqC>{sq&x) z9FX!zZ_3Z2DOFNR+B}JU+?pEoZ0dkRVk`4P`(ZrJgRysGn2^zMnSllx{zl0DWtY2O zD8Jl24Z^>NaDRwThVTzCM!U`u(g@+=rI)+w;9lan+`UpHL;>N?AnmHJ38{qpL+~7U zO7^W6b*i64?H1~)!F99Ps`67vFDj_(6VbZLClTX%7&9yCR4paxdhwA{>S(Haq*UPm zo{@sz<}|=H)wLjE{K6hF^61M_#x;OkjB6oE-`B82TOtFQP~6s`mBtKOHpVK9wvXD0 z+QvR=SLA=xu8J?+zvqZ7mnGUj+mZB=o>K@h#`Ve3%hJq29|DD(!WFE8n>8#AIKbF8tpw58kvNs4BQK!gu}b5pkK0MI z1$~lpK5kbH8Rpc96=x75+G1^#>uRDQo!D^-cSFFpe{CdW<8zn0KZN_fXD)Y}qwTS~ zs8!XZ7g>kA@)qqP3SwS_yr@p{mE(DtBpuQX0j>(Ka6Ehz!u7fzwku~*GoDnUimp1* zi91daDP|6olU#=DWe^7L{!G&4{K|AXM46!%-?=UfZxlu>!1(eh8HO5QZ0?0Y0R|lk z)B!LQfxomX?HZwHotqB#Umhx-phEnA{fdy)PswW}NQt@rEtvUBLx7b<#4I@Z{n!tM zE}8QB(j5!+&|TgsneHM}8caQu=Y$-ZrFwC6sE6({qp7UY>gxj671}iSrb#??g*LI= zPwNw*_hXy1P_y~67YFSKK!zqQI| zn0I|i$QMsu?iK)7n;;wk8bQ33zE84Zn$%FkS@pH9G&VP71=P=r^~T>sGXp4Fp8Pd?M81qblauHpM->ZX^ z=qxR2YmDkx;=64~4|Q$0CXC;2ep;xP&d-rnA}FNQ1GCdE1%{MJzTV;If*?arUgOY6 zzF%3UZx8l|)Fc1TcdggT`P1}gf(j{pM=Qq3>)`d`{Zc(1iq-=m^+@b=yuFXVnU|m$i+s1pC@0{?1t!tz)88 z$Np{3dO>O*wP9UBeeJX=9b{qZ zmsiv%>Pm|^l=u7-pwF(KulAbxG9jPhOCo(&L(Hn3F^pynY~qWvq}6N+7tY78wb$0; zOfGhm)z>;=zNC4?s&68e^aU~5DSmynDrlKU^N{DBJ1%LxKxvo1L|fDFdXj|{j^9)o zgEY(Bgm@;|=HQW?z>!bQ6xSM^%)S3*hj;|W!cj#?X``-y31is{ij>Z2e*0F1Y#XRqUQV5MJ%pgB_R!1OEq%7QfjS0`pex<5wqCrkJL zR6G7>*N%wR$hB*CCiL@acP#Yd+T~{}zjD71?dx#wpQ7dbcX#AJPQ(HaoiI7O0(Aa= zw8e`nXdWF)ZFB^+(xJe9(r5}zq&ziJj;bi3|0EI81!~tR(nh`|0y$2OkVX<9Uyx78 zhoph*BfH2SNFCWqYRNmKhO8$(@*44yS4ag}N!;XFQbwL2rQ{))%QX6c2TeNmmH5=|qs<1FT_oxC6XlG6Xp$CK{tl*9-b|PB5fv1Y^2N_(|^UhlOaa z>}am+(js#@4f9G&u^65Sgt3+i{SZ1kF@>VIkfx2s()U44xQ2V^XAaJwx7=MG)ot) z4;QSf2koM5t%ZX(>C*4Z4i)4}YkOOI@*+G6X@{$V_?#@o%F;)58z=RcD)~;zTCly$IiYDp>(*C%~$7>C5D8^weuagDqmxxC0he> zz~?(K7bk8zi_$<=fKC|PD+PQ8v-wBBTR(sq{Q%7Adtg@oBh2eNU}oP2bNjo%fj7bY z{x;0;8)1&G2Clpo=K0ky)BlE;K}DehmH0Ai>-W{JsEq{V(V&I*-n$cTp$3m%8Y~w3I$U%jmDEo35l4^i|qz znImA!C!ep~{*N|=_>1XNiwdXYPriBL_;ELk88tFzc-F9tA(p`d2c-5(N{HhtTd{5b zZ(OwWwpL>Koj@$LaBYDrsfAebozS$$N{gZ)PfrMEm7cK2c_mf{^NpIn@~nqvO`m52 zFXu!nxIA~rp%^`}>~FmiM(&GGCX4+d)hmTQZ=CWQVu?#{h{W*mg1mQULnM}uPdD^F znfL_Ytnw3Gl$hSbukl%DNtPh$E%DObV2PFPMvGp$$5=GdJ=UTSuGHe{`pQo;&v!4S zZh7B4PiaqxI-~ccJt2>~Cxo+jPxxLzO7)mizIzr3atbYfyA+x$$3H$(x_dm+qwfto zlR^&p{S%Yqd-;UudlP?y6dEPR|0+k$U!E0xpTG~5LT35>lWFpOMN0I2KR!VUndJDV z408Sz+UWZMyg~{cT;y4lzlbh62sD8Gi=6ce$LPLr>0j6881J0!%Q04f{B=gLQ4q8R5nkG7) zRw|nmRnyWGt93#>Xo-qu>5B@%nwmf8QIQgot}j(a{X43<(*0WT*qOC|#yZigU4CdK zl)NuYjUT{0t_gPpqT@-HF-&7WfEvCMA>=D~1J6d>`=|9d&H&xE6epg*j1c&%An;KL ze1wK1D5`l*fFY#0R1i*cwjJlA`DH)C%DS7TldNS0SjO=Pu_;z7*U;d-0v)95zYjbGv*SbAX99P3#4geX9U@QXW+nQe z4BSyD)*;$d4$({>ACcl;mX#O8`RehkQNd+dsljF0wm>SL7HU`su`u5-sP*u>0G<>Y zP=CqueSP>YMT(!M->I8x?+PBQS5$EWsTcPs;tX`PyMC$*`;??BN@rgBO()IPHmS0P z`f=czGPsT{Q$a~Pcr&|{XZw=mQ=M$ZXIiy%zON;p$ zI*WKJEMzaToop%_5TTQQ8@4HQ*}5a{Li&ANITxx>Dne5@njW`0)cV_SwqhKcl}$Q_ zdoT~qqjwT3{h$2JlkzQ;es3i`&;Px@KM^_azTUjIN}<`(?_ZkM zIl6_cq80a~TG6_v4Dm2#LLs#1&+dg%dx}6FXdorh@Bi+P{l|FrZ&NcewsjIw#;;*@Mr*%_VkEZAu8R#G!4}+R(YoQ&;9L%opq2${UIJ`o0(0-5o}!#;XVr zv)Zc@`uP&PbYQG)&6{`0Dlo4>f#q@H`m@9u4)SZaF>WKtP*uOy zN``C-12(OsbCc&EZM>L6Qc0fl_YO^kOaA*Kg!fCKoZfi(H;3>(9Q%hNX~J-;GLT~( z8^m$2D@?f|&@OH#%|M=zEiBHpiyynOr7EB#%29Ki_n-hhohj!fqQ{f;UgGu~>!adG zon2hzN%rMfXeKQ!Ycb==+WPxgKWNokk!DCgfo%nxqW|BO%^jZ#TzGyq7f`Lm73A}R zBZM-DDak$`w6T(0&VR32<>h@g>y)6GJpeG4N9@4mKiyFVGPbH5p@R%1J`v%)aXxE( zZCJrU{Y|_4G@}gnVe;<7b(R9c&J2_xQIR-E7X0RO{(R;wl-6O3Hy17er*Wj z%k3vrK9X?==5V{n5v4R=;H<#=w1V7cMEtZHaYu*n-j8-DePz~k=o7{3gF%B@ct){d zqJ&x8fn|}$unuWBVY$hNo)x~zWlVzy1F3(bzgF?l~B_KsVZwvkLhZyw2h_XDAZ4S=;VzZ|R% zJ+E0DCQ2G&)M1})cXTL?e6?wvZGt*`5UcRh%ze@+FoW3N!c}9Yp07$c2-lW;=!Hzv z+UHZajrn0h3|^$_RRN^=#Jhk)cELR#B9~d1YbWd#Ti#z zvrps0c3&=!d6S5*?88}f{z;^L90fA=Y5^h@mB-ZOEZN6bCBF-jfYNg-y>UFVG4eVQpX$c4`me(CM@hE~L2u>0#5|Z6Xom{; z-CG_tr=B3g8#+g?!g`+lu5S+;q#ovd>fYWxc3JLO1N7`*=vk%Iv!$n%eR}pbi8m!( zw_i0OHD439sci!0=;_yq<=C$#;JbNNcjuUu#8Mx+b-AgEg#JSC#1c~_=1B(3Krbpx zZ`$(a618J-ns_0o4sMEqpsH|#FB zANLp_^%yoD~v~XR63Hr>|aYWK1WEJj~CEUFFDkgH0O&t zG}@2neIIO&n7t$uI9SHVt+DJcts5c_^T{k9cgPs8ov;Bq4Vd7q_ZFynokIP26zCb-;M z?r@EZSO@!KeUuRw%>&unIg%}gGU-Gra2x4FeC&?b_HTLT>-eI zjzv8{Nkc6^;hIcUB8+t>l=?yaMxin7P6;kIW9a-f_I2IFj>db6r0nF_GA{K4> z?$W8OtTeus6SswkbsTGL)`v7iDIg?$NK5bxo#BA|eynzX7wwiaRd7&>7`sRF}Qv zNaA*+;5-k^(FAAa>v1^EzmV5#UV-KOpMU;)4j1Q*Z^4kM#pIJu{HA9oOqawQrY$h?y(KGYvrI>Pg1J7R29QS1isY;;kN;K2ehRgP$wq zoYPydwStS=*u$stwXu!Z=P7|}^|-0ApMZ5xynY{xTLV4bv6U${#I3^?U$0Jxv&mhr zZ;^RJS}>nIjP_m56{0B9I35d8YI+kbzA&#^a2FT|+sVij+yfY%0QV3sWClUXM@&`D z5JzO(r}<+*6Gv#fCCtt8;Aq@buBnQHw#U5r4?$gp?Vq^<->U-Zs)OxhR?M6KCB(eh z7vl%rGR6=P8IG?za_kpxX?z4^$A|>A#NcP=l>7l>UwDCZFDAj-T1NLJH zNRvQuYM=rg5vTt!+zMI{NW~>Vlx9uUQm%PPwTYXFw=OODUCg;z$~kZa$+09^?*c(|hT-m^Wb7(lod0)}aoj3EIjsK!+$Tdjz;koM&8F zR1Wu&k#=#1`(%qeMs94E=kV*{qD&f-HZva`mlNLYz7V&k?`X&eYDau8lki>3evI+h z#$>=aa0j0}7B07KW&eI8AQzEGL;Gf=x457@CQ^f+gb4-enpuIgpKq#`Ry8|PKwF3x zDn}EZnAOsby~MJBO>~o~aq%D)mgw4Xxcfkj|cLBi2b>=eEs;Irb&! zEF=pka>)J!$2c?Q21{YGHVdz;7%|`=vCtiljPDy=EQljm3fi z#s>1v2Vpdj45UU0zgANvNFUBEg2~74{l+Cz=^fgV#sq-2^6d4nQkpioYuR?JyG*Bp{EJ*~yDA+qN9EGeor|1q z?ecRa+qD482C%kDu$G^5ZvQE?TU)QuuF}Z@a17ZB$khQ9t@zT}Z(KfrF=_kpR@6A* zje2s|IH?|c52K9nSu3`HatRX7dLTAO>@|o#wQnoniX5w-NK%%PpkqSlTI=W(8f7uwG7*u*_QM=&Kq0U zyq)G{ZtXC@pmnF&WyiCa(%&i}nOgCkQ?u$fElLv1B^vRgQ$VeO8tH6yqp+w1t^037 zDsxF(0ZG@2zd41aZCX_0(uk3>xJC?5^U(%OzF8d{Xe5t{)G(jvg!yc*bW$WzSWJ~p zlj5JxmPJp)q5fy<_McL{ET2565l4iur2~bSH)M>-EhZT&TM?W6q+U(E_NZx0fn1n} zn3uF7E_2LlPa@~jihIsnk7B5V?ay0F-#_S5v0`mPV}+I;HoF??8M3cT%9-%Fr*b%h4Ry823lM%Y6}~u2{o?b-S$pu2MUEzS>tpBpk5J@h?oV= zJxU$KJg=RpSwu5xTtiAIoe|a*mZzaT3TmR2&LYAf1Gg4HauItz2M(&oV zEiMRHP|m$n{=IIv;Ye*E{r(eA)Q_WhJ8a`GE=Tzr^`j`3RaOTy~nYXmg1T5ViF-m@z;_c?BAI7wLa_b!t zPV&Q;`uJf?YgGQvdi^jttu)=VIvZd>ts_Rs3zNB>WX1?+`G4f%N|xtx7Uqky+(1!= zJs_Rc;{GohPV$0iy*eSqm*}MfQ!1%T8}%+Mb(?S(=Tf5428$#wh-_QNnYaivAiehy z>!HX{K@+@>xze^W*&C81{60K|%CZ+1?__>w%{WFSA;MiN33AcB{Lmws@un73V=sQI<$*LM}dMc_NIh$0eUf zIFg@6#80Hs)X1+x#M&ABeJjB=6WIqlU2e2$>V1pz(C4wmjVGB|Vn&Z1y*Xwx{M#Gz z#pcZx48wm5AsPF^!%f&`Wnf=8$22BLGf<}=26eaYL=Twk+km-6(5*fYUTm5#wW`O% zffgW*7c|WlG7KRR(dSOyhLGx+U0e@bB*#LBQRi=<*RaM^tc)OjR-#6$BSTyx)yJoT z3^RYEI-vJyzA1xn$;gXAy|2WIUX6WWn@QtM3u4Qkh^%C&r9NXiFe2-e>FM z(ZD*RPeUX1!{1MkA;(XkCj2;_wW6_$C)`-$`&%@UB~;_VRB4i5;lrp`pg!sq_(S=% z_!0@fTfXfC&UMa0yZDC}K>Emw^>UJb>o+SCeJN4vcf~$AZskg?4>&$ZeJfr-4WyxS z;q#z>*Aej-2aq@2+?u?tp2^rjOAZx@)F#X$Tf>n{-w?dQqemX8m8DWn_I?#U-@~i# z171C>fsV_QPAH|KD}vI5j#U#>D--xFXS1n7 zTGPhg3^kH#@jlc-xu2M~GLUB%>V<>ff1!|U)0ul0XfDw($xNNHd*0Egb$Y<6&)8jA zBLaFTNx{VWoUAlFO~=NuyN0(wET^k>KuMZ}FF*MH3vx3Xzd#{swRE)RlJ>$HM}CKv zj$~Q$M34qknO5M~$E{^gr^;htX$sSA@VD~5El_iQ@0D3K@tU)$p^=AK)yeLIUS#b! zs<*PA&aOHij&zWO@^s#9;bnx3L{2!K#k>J=!?YXiI?|!l6@nHrT>wg=v!T~@S)}uy zD^zA;A)yxt@5Qw?vFs%W5#v^Rp!fMIFT?)l3X(P>on|(mM6oMXVbjBCNszoZoaDW6 zUzVxV&_ku?HUn)eO`}5`OqUbC=BuM7AJVFRLvewJ8A2LDfESEv)%h4>5!L5d>pWJ+ z>d7r>S{O+w_2|)j-A!*s=(8`&{Cb@mTaWEb4`)}F zK`Z99>8d=A0bgpXQfswhMVpdQtFlSwTj3y`;pgdaV^iF4{Skgm>btrsJLA`B#9KP} zb;wapJkOX~&_XPOUVI30LTST4@i+9>c|Y+FD#$~tPy@E^SxL(pAkjm;cz*~QisvQHxJdBi9Y zGs;bU?64Iu)^N|D)D!nHxAvpPW332TD{9(sto@Y!&~kUvn$eJ`6 z2J$WR=T;BS5h?zAq4W~Zk+38MD+aQALR#dFQyvd#>5nb0{F|sRr?BWVM@9~3DSj`j zZINxOe|Dq12=S79%~y&rOORp64KWt|gK96%@SM=YQM3Og&t`Opy2{wK++LQI1zJa0 z5cuG^L+#2kD-+mY(4Xd?MQ`Cy;X~jT$}(boAgZ15zO7*!mAr=DLX<#ckD)q`+B;H~ z{w{1&%J( zKM*Q=gk^7VVUIUh$FIYD>g<8&SIpQgd4mVCBYnKVd(j)5!N1Oj6kNP7KTNd5I=Sn) z?IxJ{Oy1>PPj9C~1OfSvJdYlA3ogY5Y(37V=^lADrP6FF{Dl7O;X$4n*N5y%?|zhFD!_QnnduV7aWA`l0DZB9 z@zm>LTpiN!MXV-l(~S{isMGpjyg-=u?9E`U(67UFbyxz$a?! z%npY#>ndMumgK9gDkLF?4&(Vsl%!S%WIX;RDA|N0U+qv~rx2xR!dLCe@9_jwfYv&v z52h;s)7Wanb4ApTHOF&3Jg;;ko@Lut53aGaMDMfGs8(zsIm^4|ZR;6VNx@ywwHZ(K zS)0N4S)0)>x;DejG`P+s>SuD}4zaR)mpe0n-io#5T$Qe#WPa76m3$TNm1ovNDDz-D zahn8`ijYV4cq+b)dMdtkYtd8THTd3dL4F~Rq*JHmk%U}h^0^b+q9Y1we&M~hT4imx z`zB(J7p~;_@~S+~ZU<^J%NDytucB&mJ(ial)K`@NU${3bH~49o(A~XuXuglFdYFJ| zXY{6hILKeM0%j_!lvco4g`O1JA3+05^;)&@jlQ}h8`5R>*tL1tuB}50^}X98Eqt$C z`$frW{mboVAP&M(ESV}>wdHp+whJvi<(h+7qZgqzFEV~ZuYWox>l*%P$en|Am;KW+ ztjz6uTKHc7pB$IAy{_eev@#4+Ci>kV$D%CTDiku5*M>-^oVPHOmt=NdXxXDhtGahk zs}{VyWl&tf)-D_Z0fHt32<{$aaEIVJxNC5q!3QUJfWh6}o!}bW-95qGT|aWpsn_bg zRrl1b`sT;%>Ze!tetNB5t7i7@?p3zG`ds!_nO>~@`eU=JY#=)RLT8S3Ns)E07JRCsk#+1N+|9&z6tmegZ(sUuAZ=Q;T6dD` z%_z-xqw_L6f2Bq;m%C1~7sYt0p$$9-Vq&#N_AMq|qf*fX^f#*IJhdly)d_qNayPcS z?JRKD>(7vG`o7hTy&F^HFCoSs;h{WwH!<0w!;g(ic(m#x1R@ z^di-3=Q(TuV*x}(Mjyj7<@Z%@Mi@5<$So;A(OvEt2TCAyF`Jc^8)WPYQwNF)kcKBw zKf2}Fkg|5t#GEf*o3rWMwODk3dzCofC+XGi98H9Wb5~LV(Q+*O-GeCK@nI;OODBls zC@Xrn-4V#i^Q-^B)HrCv=-0J5AEShsTV<%e@D7ZYVei!FPmQLLE;X_nzBtogKte5b zzPBoO^To|@g-+GLJcp!d3x@9bYg)@!q&*y?b&>IfwQ-YC^{DnWo8GA38jTXVXw*3r zck7x}9j$O`!rd`0ZG8}tuP1|-kc?&4&4!-&h?PI!+%xAB#aW148(|UJiP9jtT7;j~xE$EtyD&ZO}!#1L=r$X$O;IB1TjO+6ft80Mh?XMNw|gTWh(a>E0D ziA%Wak;;vP2&;?S`m$ekioWdrNY4ym68PIm)aeABN8|)qP~E4dDC8b+9NEGr@3>ho661k0 zC@$Bq=$#q;h`{fK%5IBzX|?Qu+8!ugv$b+fQmqoYh-96`BpteS zloQnkpw>C$3?vnu`1qntKm1F1pD04ZOg|;zrymG6Q)KkHh)+@rgJ)_Jq{b|(TF8Zd z5qP6>AKXZD16rAkE9$$Rg3%1)ubE@KCg#p?b$)sNSdhx&y7NfC8AW|`ddEw7^kQ5( z-8id`G2|Y_?V*&1-fhQ1MxLn+ocz>c++W{g@-CH=%7Z$KBM$PFf%~Q+ZLga{aimeDaNsJatm z+;Xcy!s!Jualh;)V{+8GXd~{#e7?C!@`XQ+xPGaF#8Kb}Kp*CIAw7zLXALoGD$i*` zV&WvHD~{n9X36^Nr`KhV4?k+NV%*Sb57>V^FyU}#l>`zLCptNhJUz0ZndH+Z61%A^ z|IwpM`w`?t!IHXu+$wvruP;wMSs9{-g4d$s?SGHvaN)+Zk1U}D%}%l1W93;EKMeB; zy3qOzWZJ!q#wF~Q93Db4Y-vb;sq5l!u$V20;wI5P4T&}5_D*_zAFq=QaIjiu4)8p0 ztT}=}JYb>;6gBY_lUtiNu-qMttw(ajL4^Kk6fFa&wAK^^Cq8Bk=sI?gK9q)nit)S5 zC-i-iF%-!@*YD?VIJHtVrzZ{P4iRrM%P|bd_#}V!6Fql~l!=Urw6*{Cnq6Tgj5EltQ;>pzDVpW%NxoWg5ccV-dji9iRaI3 zJ1et)1g}O|ArY_Jc}=)8_k2Fwj(_&Fg_3`3#owAuAat%8EW?hdwfQi9p^DFffyY8O zO`0>wPeLl3Fv0ikQ4htws0wNf4QR~ewpSKO?1CjT9&ajJiY7uvt+r@mw(w&&nr&~I@(Wrk5_)f&T*lcw)*{HoyYpNI?+ z?r)=wl^6VtnPqP>;EPg6%O+NYulI*D@GX*)KN`itKq>bR>K$veBCHbRjT9Mz%%PZi zVK+;e9VD;MlZtqgR^l+>8oX(j%>dPx52;<@Kbv{=(%-d|i#y<4@#3o@l$vmqkRg%_ zicpeR^DLe=d9klkjqa3#4XO^Rotr+&w%> z0dposelixTIteVYaSmxwBq#Rhztf}yw1uM8+rv%sL`IQFW$CK{WcDTQjZ1nLBuM(5mVdOURI_5p$xn?*~6AI)8qp-h0 zMcbnE++?dV<)Bufw#ka-0PI3nCHiK$gkTfV8Z)(efaF#Y5(EwSZZ*x<12nHU4g9&s#<&7I70Yn2pqB0zphZ)NlCctS|h%|46o};n@<8V8LbABNU z-aFZ!D`h3gw8dc!z7pydCm+&tOo1v*gedHlMyR9Y>|sM`9$w?K$$R;un6(0)nlRxm zsqfM2DMPzo`n!i#kO$t{f6+nCYkxQQ*qq17wn2Sz9B73{>-(^x)KGXcf~X~#FPY`h zKqZqEyxF)ngw({uSM$1IRiPpLaIY;h;6d=lvEEr92U*_R|De3pLU&Mt`vuB)u5c3& zaee8z2zP>h$Qsd;1b+lx*}*zN;w7q#U+1$DAkm~%W1fbKhdfofZr|0XRZ{`(I`c-Z zN1Jbtk(u4y?yI)Lso_knl{@AwAFFZOjTs^IHeMn>qSB4#2ADS=UN!=86G(bL_OTgD z;6vywNf}}KNQE6Vfo-Dgx@-sEiH>Qo-3D#VxO3UiU!R%Apf`SHdk)91$i)R8pvFX7 zBd+Zw($eKk9%f5R2<>!Shwn*Io;P{@YQ<`GD9^^S=r5Zh=MPaSh&rZA6U_jiU*`v$ zbs|#`E`72I!eB2>pZtJ*pRmEv3;wFhFu++sl(+0YPl{tuh)U=?!Ex8Qcyk?4n~y12 z4xW|VVWZ3W`Tj&l-z2tFn9dtz*T?*mQpnQi@IdQwYx~+3Xqg&pvhs!AwAgvXkk4ny z#Lhx(gVB3Xdc;(W5=K{%foNAj93rc5b(~btO$d3?Pq-;1of2rtE>EqMGUNCT+U3Ed z-8i+nGR8O{YwUU(IK%YwQxC}!S_gQ?X?0p_ni)ZwCm&B*h@Tbh7_a8&<0t=9URNFJ z04-{S8@OqXKcG@Leh0w;62pWHjcAVVY~sdHEM&Z2*+p8t~yk-^;%BnH;uhAhC{yj%oPR)HhdjI)H!;(J9qN-b{rU^Q+Grk9ynI%`| z>qsoZNKJ*FTTJF_XO#Q$S)zPvu&wab^yx|P$;>tOGKtD2>kF!|p&B+CJtoGwh;+q< zoj1Y*O)#7$BZn?Sk<-vGs49lqh1@JdVYY`v$!(mnz>Hh(0plOV)||UB-G>$(Y-}Z2 z4zbkax@qs0#U3m-^&CWY;Kr~cLt?v7CD^kPii)+^pDBa1Jzh^;HqN|4b1#5UN)=$k zHZw$z-kA0Nh;Ao83h%rC`e~u4iuiCuh2qk!O-7#b9{Uu|x!W;}{L;#Sz?XLc@-qOp z7-D+CR+y-I{X$#>X2u`-5oD5beYRhS?7@yX-X>`e&wCW^nlRPT6y%$sV9vXQ6kraj^J8*-YIRL0_|(N)=I!v={us0{3+l zngtukr7?&O7V=cs;)Q5zD9y*wk4;VRx-8vYO58<}uj?p;XiOWozrz`5tbATni<~G} z^&{%cMdcz>?aOeKJ+c>U#i^0gbutXqywD>DPn2<#I1>ukMQgx=+}Z7kGn#Pkf6OP6 z=`yrU23lDIPGUy7t#!U^X!f4f3w!_4609rzet~YvHgwyY1DtH5SoqQB|6^jgov5AP zBM&esN>7(x+CsSBoRXzybsBGBT*mQ6tE`;I!mo6}@aV^#(fAkjuEaFKNBf&x_xHh4 z4a=T)L=8dUkRE~jE?a`%Kj!C69r-+?lRvdQ!7a=4Vza3vVehc2_Lr5~8+#65O>?nC zU|hiYXhBJ(CAZ0(e@528Sk!VG+WgQ4o8zv8s$*O?1iR*SCso3E*04q51Y)LkUl(a; z{Ng4H{DVWev-)N0Nc#F$kNQ<{@J{nc$S4T;X{ZP1SO;Js(kMch_?bE7>Y~ub>rW3= z`J2mKgGHrj8&m-sc9^5t2DDmjxk*q(*^+(c()kQ+=2AXj`rF-ppXN;f_3P&NnrM)F zIbQ%jRqI}x!Z}lPiAmuSUW{=k#xV90yd=(o9Qswxpfd7P4 z`@8ZBk<&LzeWt(WUF_ojoC;V31c%YRrOj-mgO#k(@U=s=kAqu_x)=FM4u&yfouw@I z4mrcWk>;TvPbjoV`DM%yUxMEi$wb`}taG<1O_sj!xp^X(t$Z8L#}CiC3!~)La)YP9 z(l|#~QnVcDiKZ~@Ak*|D`P z4R;3MML1(tM7eOF(j#RPf|@N*q8GGCZ$B&&CGj;w%yqN1-w27UrDqil_q}CJ=76t< zfg0`{g<3f3I^8ctV1qy@ql$qvzp2@Da==)N<)hi88@ZuWrf}4~sR{Yv*(~Dhp$?T9;qt|D-yEjk?;d{UvcESd z<|2(tg`=bfUw=#_jGqX8O651nNEoETtuwH{8#xN*+aDE|f)GJ)u7;|@1nal*GbYZx zUh1~a1afIlRy`Hg`|}ItNt~HvJas9buWEcp5(?ShBtKl5@|7^vO0)lAU3R5d8plK~ z3y1V@KQyc4Jn&{6?qj|jvRMEpXf~R%p4i_Riz;nRY*gWoh{SLZM4CH?lGN{FO;s96 zWsVpv^A8_qE}*92pQiXJ{hAe>*&MUgJ?Re|LGO_jk{v*_av);QrP&vA8p z8*2|+n~uoH8=M7us7@WjF?{GE_LIpPKuI9cFi+$#^$ojubU;bBUW9m(ua$KsAbwe8 zHz1f^?neL*)O4+~ATi`)f|AD$bipYVcaHE|-P@m2e3*Z}g`Iq{MgI!z0j0tl5l}FW zR~!iW?R=(rFhAYg#N6W(jJ26`b8?N-px!%gDr6M&r_EV>tS;nOyT-C_i9a#!*ZTfg zTZB+uI^}(}5-Y&NPdu~dF1{SJhQ%WpZU?-%b2u584L)_36kOSnZ=VwpdI}$4UXx}n zZW+tHaB>22B-F@V!N*N)D=k>dscRu9jiJ6=tz7j14SZw;AKGOM%z?Yl&OZuO3TMaU zntiT}ZvHH@HkuvZ0eEgoJHQ6DL(SOMnrAlOeuHM!r6XP4=dhof8Ax_;J5zo1V{R86 z8l@^q!dqBt9r~u;F)@+=a@zRA0@0MTPGyC3giQR0XSX9qKaU>+v}PIIk6w=k9rv!G z3`UP8d)JbQ>qxQHkIBP6$5?K+hO3C{eu%~ulq2BF3UP4n{PZ%mNGMM8tn9IdDTo@O zzy=dPaeQh8BVrD@t-Uk}AH;)g`6|XXYINjZEH31oya$5fm_r?1tm@hw;yFF; zIzjHOoM&f0-gQf;7xKcfOB+2k?z#v&@6!K<+!uDZt6|g=_qN%ndAzzPBF?ZC;cWV| zgoyc-(~EfYL3;}9oN&YONmvvqL!4Je_;$nv3?YsiJ=R!Vw-^JKU36aO2Tye*C$>+r z!SNxDiZVUcJSnSkX8KnUY8{A7Ru7w8waTz%hsQ$WEf!z@_Q8an!H>l+>-@Vrs(9QL z#&HXYr>1SO$+-IOs4Q?cdw)k!~xbQV5d{kD=J;DyWf~&r+1NpXXN-)VC z4S%FhHZPXrIScj}#w6>YZP9Cjix}O!1BAwCIuL1Zh|UGr4Q#$Izsm5v>BH*|E4VqJ5={gj=TVaHG4h>z6Vqd5^Ft?ggWNACV@@sBdy!pE+pyIbngu4L zZ+gdV3boBAQx2zIJ9-yk)s!14i>m9e#%dDuQSE=EV@q+oD~_ys%**4-a6UU<9qlCZ z()o8^Ngte-AJuwbX)#4}WL|Y{Xn1ASIfs3VUjJ53->u=5)+f~FJrU+cZ-{qR5mg3* zR0Hp*uThUo!z*5A)qPcEwM=)(Fq3wLY#`vp%yF7UF9Rs=OSTKz*jL%0*13|E7Vr9L z{Rf~rbd5Tmy0oD!foP|iX!>sGv+K&YtdoY0M+?OiiK=hK0`4q~mS;agwfNSvu_GD; zu+ekLrala#pPPi2zrX!HHGr{7(wILJ^qnUGvNG2fofS=wJ6RsdsbS#EAQQZ&yO!;# zL0bk^{Ly2khT5|1sphxiR$97Y%BLOq2k(#4^V;<&0#EV&{mss^6pOzU3n`2UqAjfX zr(nmoRbi3`0E($gbq_e9WUU%lR2yq$#1Gy~buG?sVH7{1e4x4i$|T)vK2(v0cxmCC zi|c#b5`l3^d4n8+kDm2w{ke&N!7Lp`^*Dg^caT4qo%Dp^xk1ABiR@ ze!BEpXu4^MrA7M8P&S<6WtQt8v&Ge}vZ!?jB4Kqo=Sv3^gySmsPJW-3w<4KpZ)TZc z8gc8tt5Y0eQbg{Nw>+!BSBMPpUg0+h8JRf^aABHyn@v;VzKofpN-kI+C7aM35EXAK zU61J)fg1_Jnqqp_jj34bJcKHbcViv2ly>>N3H`3(QNq2wP|AV7=zbu--s|veGu}qC zx;JJiM+c@R7Rj=*^ zKdpZ1?`mp3B~I_$+tAO2IMG#Iwvl(xihr3l`}mNzlk;G8V1NC7FVuqUnsuyVOnwyO zbNXq^DlhGI$;(Iu!f;2MD!f?>Ttv#$`U&YX|KdZ}i~Ly~%z*j_%s@4a zdaub!R)-VI7Kj27jm_6fB`Iyq<#|U@WlNC9(}@DU%78idYEH0~ z)>a7qvI;K5c-1$}`gd&i3o)1!sRQdxSor^~zMM73tcrE#xVcXh)V4ZQJc#c(*7dd$p-q0Q$lOms|v@>0@z!l0_u{OVhTIYhR z>6oYaPvsR2&FjB?1{=Nhwlla8-hwZoekiU*bw0!U2fS5nEb8iLaC!$HpOR)X2>JLU zyp(JoC~Ac<88z<%T55b`Z+6h@xT){8(_*TY_@FDfwb=j-=I5hPqaCsB&(xAX^NJpH zm>6o&B=uJ&?h2>Yy(g2xJ*j`{E9OOO&E0)<1GJrVH?2Q>F!c9i%$jfq8=dJEj(0+` zgpE|h1;Q-Wt#Z&otgAj>sw>HH@A@ivC0VP!X!TsSfQqzKx)RV4kKl-+J zaThG{x2wyyuuO zcX8dlarWEs?q!T|fL82V*FcUL(EZ47o9B6hyuEKbYRc{#kH|>d4QdU~kC%-F=)9`l zjIYbdFZDHtz>OvD`Dyn;J=m#*d-+a#RsFmyLclvNacAVu=$e#g_Csgu zrEbB<>Lb$xzW3+uQZ>cP){wWca!b!Pb1gE|Q#-nD6lu>VNSCVC?{jh2v=f>ybg(N> z(|fl#S=wGj-#dNU=irivVPgH_)XaAkz=`QjIGTJ1?rhd`&+l6wgfHVOXn0;GZ$i%k zuGK$}EnazAH@m9Wro5Q8tZ^6!m2IQ#k}Xh#@M=-5k3`txv}Y);br>+ru(zYFx7 zZSLoxo*D6V`qm=dlV=oYqt@MLHE*_u^XFIFMp5z__C13FEh^t z)39<^Vw4=V@q-d>xz1ALp%@xV?E*4t57J{BYqx##yQ4qn7I$m(Civf9G2Kzs!swRg zDZ||BG&fi0xre~7b#rNN{_?v0!*Tn2uYjZRnUCa<8(~gmbu$4pz*k|~hA)X)Twdf< z?<`$kxTAW7;W~PphSv(z)qpe|%-j0tfGwTuWi43X;l^mF{J%W zTEFLoFNchYxwOQzfm&NIa+;E)p9q>>k}k^LxY7&%Y`||?&k=?GW*0ZJthdw8dqm%H5=900bo{#;3N5AhPIf6v2E+S}sgwB9j0=n(i>@wrtk<6($`He3<_i7 zek@ZOt5RxG+|Ox$%Ir=j*j_?cIt=8T*%Fpi1!5_c<{c!&35%{ZFH@R*4h;CpJ zxnehkKZ3?zlcj~8_oF(J{xJH~$#|%ZaG@_F!sG@1j~D6W%~L4R{e*6qkYello(k!6 z;=1|!!DMWe!vG=Dd^pOb=`WACc4pnjdyDik3m+{~iK4wqB#`=Q11YBc2s!AjvnuJg zL}SNxvx+j9FKXEh3?lrC(DmVE!b2*tThQsf*tZ3*#)o6CGb@i!cZ};0K8GElWTSg( zIZ+zd`BU0SP#~~WS2*pH^%JHn<=dF#baHJRr)N>5|GG1E`GP*ZnGMx z?ILm|a5*u70c!kcH<;X?_SQYChAsP{WjC3#bo&G~e?D0RM;Tl)hA;e@EuE7l&(LFc zXUWg+PB>QF9~jh9ZoF1Um%G5(pL2B4nOsMcO4Ti2wpdq*)Vg&)8&tMh>oyBKlmq85l7BONXdzg!>EZvsgYPJ9F?@h>x0_~JHm z2hnOK_&)8~C&v(Pf}qA>R^gch3zAH=L2f@4nHG{M7Ot$b_7n#R#+#hmA_6*rDhrq)a`th zb(g=)IlWmOpX}&x6q_PP2p2Y6yk}Nl@4ONkY2&lz4dl*lROSl|>({VCHn+aMF7$UI zPXP5t$wbhGoWf1$?Y6$#_0zzKstiQ7IC9wzG^r=TKy~Y%44*HN5a%XBJJue@;0v!^ ztyV|RQy2Uo`_XMTtfRv#RD+=N`;_VgcI}U#%mM`8kDDde{EA}qS+1>iY{p7O$JZgY zf?@hxB=vCafiAM=b^b5HPkuyzZGpjd02f!ve*OJYXO+Y^gzRL;SVnR=)@z^rAMdVN zfP5dZ)`N-gB!rZBIB9`(!gd?{!qeo_WZj4IqJqf$U#_X$;Cd;#vw!IDb6PVWVjm37 zVz+hB-4_wE#WNkcb(?~N!-aLHCi+BZyb*11wkE<2AqWw1*{Q7z$=Ql`{1Z>(K859I z?E!ago#TDsh5pV83BFBA#iBBpHnelN8=9DkJ-w$M6ZSY99v|GtD(VznYeHLgJtjVu zi9fIfQOLM=svN>-3j4nx3}j_+7+lI{u?L)c9z@BzvUyFCm-!$;R}A5chr~G;?a6Xs zhsD~Uj&Y}vM|o?dGMCyvj^=3RVa)}^lP-j_NZZg}m!1e-Mt049ToKx^SD(_1d0xPrIQhELcpWxQ zI?@wPb0kLR$dA0mfa8tgCMP2MU{S0ofxbuh)JhThjB}`i$`MqSer>MDd+%4*Kl-z~ z!hOx_>AG@e4to>>!7aEVocN?i>xV{*&7YHJUt=wI22`8zAfn<*w|irq3I&sXx3vlK|a+8X&B)}f}ES?+Xa=%Cj8+;ii{tJF0!DPDGocB72U{Rz{zIwCc z=RkU)We(4rQTt5T6-APj49CVm%_uWtNh^b_S>kuktaOF`%6IeB*9h!&JHu;J2tKat z_Xd7t--rb2&`;y6O^H=(ET=;RDDTgC?xT162p;MRk@Trwt;b1lebt*B$!F{?;a30a zIv#$Y&1+T0!>Og2vrA)2+s%r=9N}8s@7|)#IV&R_edAi z!0y<CfxV#6lQFe+zd%Z}o5fg^1%DS> z{v8+{S;9jn+fy-dRJ(_~voXBRJRN-p-myrH1l?U=3ux_4s`bqq#+}E*<_xR4W2YeQ zAS<{ZzvhcUEz&hovr>2+yj0s)cNnv7w0UP>?s7f3SoMy7YoT&NCT~`Ns>m3bbyjOn z6~1#5*SYeB?31+U45WastUXy*%q;fCwdNh6Ff}%$*2qUFv${;~+6ZF)f&G8xo&e5JVY-=hZ*q>-_okNPxxfYfwk5$%io3HmbL-V&|HD zh*g+JV5F{IsFU}-U&ph(r;$pcS;yn$E%zhNG4;KeLuHyZ#`UFp7q}!?mhHMLFDj+~ zbJYnH$&=c#isO7re>W>ANyRnYLaH?OP)Z0Y40scbFy}}|!+}&h4J%@*{!u=W6 z-iHXJbPmYIwE0)IU-qkRIRd;TH|#QBaANpwT#Q?|%f}}5;CORgV-E2#7X?j~(#wM^ zJ@C6YQss*qzBnQr+1!i#akNk#hi~p|#7+}+M%Tu*;ap_ty?drPR2L{_@^Y4wBMNFG zcU#r?0tx7)4l^QHpgC0DJ#Dwc{&EfMAVawPen$t3yvwgkk7Q7BTjcMln28SJ*d8M8 z?UUWXx|0sre8`romZxL7QwV<~y~!^qli+;!8Mn>qQDA{?_Lz9>{`)rh>YC22rFL#Z zm@)p-lF=<5_Edd#om4sUktx;HM#OKVqhOjmlcQjwXm{Gxdc-nr9<#}4$8&Il#KW5r z-fb2Z)C~rEaCcL9Mv7|aK!Gp1%rnD!2Rg#TH|i+#4}IG`PbseR&Bj4qCKZB)$3Kle zri+=2&l{CSh(&ePwC@-kWry3RehHAATBW<&4zQvA>DO6rQ)=(H;Zzw=iS#0fZ?f7Y zKvA$0I8+-(+uk|vE&Gt-OfNjv;69)a5?-3;%vYUAerPN)j@;xz{>(89xPG{bM8Uok5hmA%pxjaI zMISXHF5nNSF7TN_9fktUxR!c%H+;88=9f+n=dgS6PR7X6%*PDUImGLeZswvQQ1B^; zRhVaQm~-UXR~$@BNR>ZXuq+Aka^2#@Ww8ptvh1q2kDLK_jf1M30o14bJ;eN#DG1dm zehiy0F`gYDEQ=+lkZD;S!V3Y%qS$hDCEdy$NBn&`hur{au1fePkZlm-fnh^!4W6W;5M8yaX z6Zs}7e#J{zUf-N#0H_bqmM8tHM}i#pn&GuF)pGrEB!c~XYkjz5d`E#y@>fd=?Zj8! zVf&E!01Kv^DjXill)n3ZHT$eD^SL#9Awc1RC>To#)>+wIeFbrrQP#A>+=z4_%1h|u zYi5X*_1XGagJXhp&^oJ)iqnYFh$V(relWo8 zwDdRiFGFo>p z5yE(KO;1cLzI5vO%bjewq=)nQw<4xBMN#|W92g%mCnA681&&oD&65*$@K4Yk$`eyM zTu?{et*=FQENGtA8`spG`pNbh-rzs5rN!h7*Hr1x?*vFJcq(FD7g*x|?y?CAbBzoH zTSN#}L_*)O80QSKo!{{*x)J5OwMsoxrIiGZh5m$XGxdKQwjkDd{Yl?`fdA-w_xN5P z)m^_kgq`iy<#CxSjCE0FjH>r1dRmVR8BDj@ZNesc{$$d=IcvHd%S0g76?NjV8EJ&E zK)|EXZgZb$PDa;OXlw6kcqxaJMQ*K`v9&)RB&DsUN^50Yp1gFTG&B>d4uHf7-_x0OPmKy8IK3XQJ=L@=U7fga9f3F zQUPg-8K3)Zl;~2h08s2AT&p9l}q%!Wh@l>5`=+Siovi6CgZ9~6BaE3lz4ws>>kh|U~ zACP;0)fHH7$8~z*uqbs-28Os{>rWlA%c3Tj2tBQDEpXk=%V3CXHiSyOf z(l4E|I{NeIvx0r1kc%| zyUhCZz6rg)cC1;~q#k)TWP=?O)|46x!;Y0lP=B8qmR_#6t^$}zqSAvRS%{32@%`!M zzZHGL6!e+5%gXD92x%~>H?;q5sQf}}lO`Ao(%_5*NlD+J<*o5s5lT0|TIL~oGCu2m zjX_fSA?9xZcqOt2D`f#zx*tx>a#U1$KF+O4k6lfOU441KFBlukD2;cLn(OGK)Wku% z5*w=rq2#|2E;XiEVezJUI-ktC+{%->myMT?E-E6HuBXa7lG>Y^&AQw+zRPv3p{{ju zD-=9Y!$QeBsJIlO(6v0xFT5QhH>d^6%=4Tc>{>VnudT0Ml>G@kAq=K+VA@c}eZVC) zdqmlQg*x>TLOEIW`Wk%f7&h>FFK~Hr5||kcb$-qFYMAhy9?y8h+eMyP^ityx8yuRn zM4U19mO=TU__%Y-dV>wgcJDUqdnuvpy^T-?C{w!wdmm1Q!6VB?4Ac{f&b&J2!nxtx z%K%NmnPYWk)f;XIIV0$G?w!KfVXkArhBE0HA7q@BK%bxytX_d&>@`9%#7cxjY?UFTvE!sdxd%na5KJn_*W&I3G_DO)U#XzK*ln# zy;#s8+yuZZ&JIf*pv}YQRoV=vefXBbhnBz;7J-plxD9e>EA)nWwWlGjD#(s}gQr&pSDm%|o6cy1e^oD6LKS5&mez}( zx&!nKx0i`kU|_!Q_QS>#6v7HJTkdQKw&OSA+~|Rp;EWkqoAHI&5gC0k>bPAGQvbIs z)$wmxO5gNV@&67R{eMe2uRE|a{_m%azTv+~=8g6XRNv&#%p>)T6^ag+#f1P?hg}Fa z;CpMKRybp3hu?I18-Ccq7~vbmo&9qEzqeGt*%st=pdNu|Lr{5^Yi5CN7r~7c=n`%{ z0A#2$Hb3IRyg}FNfU|@vZ#p_btz>tDYZGdcn5D!mYR= zF~)*L%j=0O+4KKPlYjJcPu&EizM>_|`BTZ34UK4IL`OqAZ}BlWf7Wjqm8nkrGNiuM zn%TeZP|R2AAze(5osZ@XW;)LhYa}K;7M8RnkxD=JilNe1W{l!Aj3MW6g*4Ky(zY*( zx3OqrkNgx|JysH+4(%L6U04~(h^dHL@M#&PNLoW7SH5+ff7uB##`b#FO6uxIrWgn42wC}^g z5tTbKyDwK(<+DQ!R$KDUt4U1{g_nZo(!+by0->730#bLzE3Ic4)f%4CZPJjOUrcGy z70FgdC*yavPo=;?eVo^qgb6*M*fpEks<)4$cUDW~g!!wR_AiC63yAZt`qy_UHFwQL zIF}lU`Szcz9(IWG%Qx-4PduJmZ?3~tyH9#wGX=&Sgkn}zN!|r5eA4x%A!;jYoWiPd zYdS}-S~I>|mM@(8IsURB4?s|Jc)=?t-hn-PCanDiekvj(63a{##j)zm;MkC6ZR>&_ zjNE#$uA28oB%Yy=cle&pb#$mYG9gpt*GqN=x?qDg6K~e~o`^}>(Ed1< zP!#s5;@aunv8ss3FCZ2nIz-}x&5H}*uB=(KOl#kcy+0cb@+(1GCih1IfiVsF)-{^w zs1ncba=%X$(*TyjvQ}UrNN1$$+%yPS6?k_HtAaaDkD6ksqFhhb9)bO6`$61w9_@l z&9;hru~_5FN_BtkuP)-=%$955wln8s5e2h<+207>vYHFQt-YzxS!#fmRbT3F;EH(P)lKe=VAhYiJt;#wUjv_@(D z4515Ce}bg%ZCd4%Mz+^$gaozZJ{03dL_EZ!9*8{-7yJ%lP3qX>5nbkt1-^V277<&X zi;?9%hb8`CrysG||B_SLV|c%9>WVZZw#>=4-%L$}C%dL7WeMTzY!1FZ4h~{93fhX7a(mU~v3p6;A`z#dLStO4-urTbBOe^8ld@3W(bs6p$rsEW? zV;JUgQBii1OKS#=cwR-zGEICglZ$7q#gl1QlVizH#k}D5@wG|3XIUR(Ji9-A{Mx|+ zU5*%Gj!X?O{=g=s69wG8>&<<}(o`isOeik{>qQgrBPgEc>wSTkMFWw5Sm`>d)71R^ z6pJr$IMt|4lE>_JWx7vH3Ni?Ym7Z#6{H-u=NO0laynXYAL>KkV8=N=)_>g2FzIo&H zS_b%{YQn##3zQ7JL4`qho9T-x{R)Y{g@Iv42cW{g{}w0-V*(5J7UtcnDBR6|io#_2 z!tKKO!fm>fIh)u!Sb#wcAOjl{G9EH!MgSv#jQ&4hBe3x+%uG*aU~9`@Y~kQ&Z(-=< z__u+htL@(gUB;`Zz~02##K6JiwKGE}kg>H1g9XSG{I@@26K4}^u&s$b!#@~-&A|@; z0liB9x6v4x*gIO7S{NBP{v8y<-;c1Egp?eKh?tU!l(>|Lkc!wpP#q9ZN=gLiCL$ta zXksP=krEa%lM*wK7h!S}6#@#Inc10JS;{LYDvAn0RE2;NKo=1=A!%VVIW=J+O%)+4 zIr-NfloTOiW}2dEii$E~5Jv?g2{k8W32|3Lb#5mU6)`QKu#toiv#OYg3s6yoRoL3l z%G}(@hS}K=WM!r%p=PcFGE@<>1d53LLrTa6Xz)L!6g7k)h7#76ni@*BhAeDmiU2W) zq`8qC&{7Nnv=nlE<)9+vBCi5;QGZ3{M6FzamOz*Pz$}HqKt%_Lh~hsuN{B(EMO7@t zRDr@$|Kw#3l+^+Kk9)dEs0eBNbDRz;Vq)A7Ep>J&O$}*BLl$;+DRCuhO?7~ajHr;! zKV^U_Iv`2F|Bwl$2v*cLr#%3P~EcFtb=H2pfxuf*r(_q_mh# zG;CbtHQkgYbU@M&ps9nTxvDBRK#a>;3ZSB)sRfd=F#|F?fSsKTO%&~fRKUzq5LHnj z)4$9mm4RXsqC)Cs!YYR5_C^*uAaO@kS+J@TE32{^r<19exT%4ZqmrAD{6C}>xrBvG zxx|EpfFiwt`ugcTj6jUh%_cCt>~U^!JaGXtOy zL_$QwPC^;T#{Jq_R9I0+)IdlGqNOP1A|&l-08mh5v1JpLa$>S|&;iK;jb%kd%@o;H zC7G=O!fXl>=EBxMGh+)DH&ZT<6}N+}ft#436ca#04q|KS$fYPG1(8&C5@Jy|u~xHS z0_%X>gsjB@T%sUDX?uBjM|qH<9Xmu)Ucp*aQ|16 zYxQ4i$XD3x5Rgeai>%g=x=(eGBvUEgWZoO&b6O9`QAFj`G97!oJ2wBW7g4dw5t?IQUO* zMdX+<0T_P^NS~19ZB0Ou2KF{!kSjAT;PYP;`O}C0f|9717}zkA14#c?!G6N~uT?^} zw$^`x$}4{o5g`E4XH*tu01JSHndSA$uJsv}jhmT;mHA&qfbIVy2>^icpCqXNPb3uV z!KN10CL~J#44MEkwu#oc#cJizj^!AI2AaQ$tref54?5-HLQCLuDFHUlf56E}=$Nw>jnAw=Q{>vo#NAdqhCeDBl|2cWy{eRPLWMNQZPGVs3HM?6mF`Kt} z&U;?3WB)Yr-z7WddROn%<(^Zv_f=%%#pv0K9GZS@yBx{l-tFr?qhOlT(lrad?2P{% zvW$oCZgNNe4R^uCt-SYkEM4?FUi7z`e0R}Z1x?w&;z-Xrb9VO+i=7M{4ER9_MHrND zSPhtg6lzLhWJ5|x;#L9+S4-ABW$<5fafbS)8ByhYXHjF1Ii0~Eg~^~is$AXh?Dz5& zcGKrxi`de?PJJ0y?|GgbRy*Zd8?;QTVwNtH(VchYXg-T_W~6$_Y$gMh)hg}zv1^ps zgG83}ep%3C;ALOw^0UH%9+m(VfxkP0J1Q)46KbOhqkr$oe&gcRq!J3e>4xar!iQ%mBXzjRbpXL&3&|MTUN zX6JP)*uJfOuP$}^+GO5cJIt5V6-0C%uahp=RJLr}nIMDkEw`p?m<4RzzW&f`sX0qO zcXkSVzBog%^GAKc7H#<-uTDPf`=uMYIN2Z(rEtQUMo36wSPM6l8iqN8!622%Aoot3 zMf1#(_w^foSY^boJZ?7c@jij$*MuL}rV02z^$5M+*&vy*-Sg9xSKCD|y}Bj{EUb=k zKt$pF%_t0nS{^@-NT=2S_iN(#p zg-L-kps-)vHrgXxBll`N*E(^R{8<&r{swyM!=kRg>!^Ifq`+p+zanyBsKQn!L%Vfs zou?oC7Czjbsq|@QTWQoxo;ondF?C3yh;R_C34jv_P2B=E?8EbuUs2 z1p+oqFDRVVz55n#V1yKETtPCtA;avb3t!BZH=Nl0D@W(JH;0A5Q^&8<9V%=x9H*R+ z?asOXsnT}Sw9SG{_7{r_mj14BU^0-^Zn&AgG)(`+8BW*B2cGB5I%joxxzoA=na59g z8!D`>8e2A{d^@hOZKJxnP_fjB`q9=2ayuK=PQp>OjJ8fjTPMW!*Kj1E(bfrNtrJ&Z z9p^~T)(N;GrL1*gY6u*?G%z#3(mMIEWZ|UwlcbbabQYYRZf~PH>GP6vde$Eo_4~%o z?b8%7L#h^-SQ%K{4P2QNV*fom@*u(DAE)E3%)84ZpDR}Kn#?T|$)0xq+47yIv|lqR zG5~iD9&~HFq`#8U<+wy^@Z~EpC!IH~KEik|HSdSAs(v%5kzpnVB!IxfF+d?WGhM+c zCqFq`!Ndq87vRmvB*GxVz`+3=E@n`)y5=Jtv>4bb@nU6Q;AUU}X+r|Z`FUxX>3Uhk z`Fa0NVQNMmj+R2w#=!6ZXk<=iQetkgOJYf4FnDYy1UO9Ns8^*|oFCxL$_7%-1ca?X KdiGUNy9fYiY83ha literal 0 HcmV?d00001 diff --git a/test/resource/ams/ams_data_ability_bundle/amsDataSystemTestB.hap b/test/resource/ams/ams_data_ability_bundle/amsDataSystemTestB.hap new file mode 100644 index 0000000000000000000000000000000000000000..6d0c8391b82611f14f455f0ff9e1310b8b0b2627 GIT binary patch literal 119282 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

Q*It4{T{+g;wo@&>8yp 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 y3>!)?=hgNJNiEMn;B*hsUMxZ}~ri5|0S)9mvzk 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%0DNoq=;|W@mF4ZG!rR1yg%A%GVzQS)&#mv^*l-p4 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 z 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

G2V&CzP&CJ(kL1maa@ZhH#nV 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

QbLn0; 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 z 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
PFWYUuqgV3&2ldJsL4 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�DD zej3u`8W=GpJ$gt#;>Kfcq!cN`Cu|jG8c}xmLx6P+evX}bc$knxH>Gb+AAoh@SfSO!Pl3`+PKiAWpaeHb|oGYje(psCWte(k19vjzC9n%T{+`x_VOC%zw0kG zM_AD=xFgl*tXTVC)r~gYxBe|ATY8ZA3S*@c`#D0@Hm5C_^V-rbiM?Z6|F;F(7+dls z>9=ib`N{h<73ho82Ec;Z_S*S&v23OSO@xp)Q|=qjv~XgMFBLDxDx8Rk9c9JiG4WTV z#@pC)L0pm;Bs^Hnk1wyOd93&rceKU>DqQXwr`uiiHhVkg@H}Cg7aY}lR$4nU$}QSg z5PhP2>Ih{xD&{oZ*{_siopLE3l<1{WTzqxSG&khFq%4}d5n|`^$3>-ye6je1sAT9@ zA${}`*M3onw9HqcvLy%XkLsFof>#Ic$X(M4u_V7j9xzOAvs5FbS*mNwTqj6+6)jQx z5m$&6QqMtw>nju}4MHk}#0t3&Eon)@_3SiGg$q4Ce5Wl*qA`)rE~m!F=S6ABNNx%) zEh*qg9a&sZ{XmUPxWBW7P2ebOtFAKNfGG#)5yl3oHn3+jxP|?n;G^c!5@o>Q$%&Tn zZJXgL+@6AQ3C+EBUL{Te%|c5zb|%gMdvSWNJY`uDsoDf*r?aG*Q}^R|VP~&g@8I5M zZRHGy_%U^qC<|TE%v+blLGe}uaBzCf&#J0yIw(k7Wi}ygCXF-@f zyX|=OlUB-O)ftMl=t=TeG-jC0y9d|15cT!m)y-=SGFNSDaYepK8=ZSadeD}4v*gE zz*=r8jI*U?C%hG6&<0Q%;pP_*+e=Aahase8vW0(illqg||20;o5#kSZ14Sm3+n=NR zdO7OK7It+<`#=;AyGU-^q}*nd^z{IlpXmW={EU(*cr(y49{2SF4C5vPArnISZ~pIm z{Wg3hU$ceU?*IS!x+X01b<9=xn)@&KniiL@#{ZD7T{kJvJ_vguv_hD1F5UUJa~EsL z&5%~Nd>e>zm%Fv4eRr%Vx64iZG$WgI3Xq&Rmu3$Z!TZ_w(?}kfEab6>oG(}|`|z1c z`hOD0$tFw-lRl~795M~h$SdeaMUxLW2 z%BdEG+zQFB+n9DQE@X~~rlwP(sU;g`^eX&nS!E4rBjwV)CPa}t1?7?lqfMt!rpR_6@X<0Z~Rzrim zl1k!viBevRI||FIYDoJat=ikBrz&E3 zP=!sE=^+P}t#IOlm)NPQBNlYzNtpfZ9~raOOfX1YCUK0kI%^YtZF`OddG&kK zlRJWSkK1ir|GfYCsSJa%Va5$m=>avCDQK#WnEUGU2-HW%Q69UU3aqcDCakZd9NGYZ zTX(+v!n*UN5K1nfKrIG48p7F<-tT+Jl5Sa|#HV=uyRGgdJlfNM!NPxHiv7B8^X&I= z`F5w!wB#xC8j!)~5tKx%z8gUXpVyIkhr%k{4Shns^@rTk zZAE4OFpaEAJSQ>^`IOn0Fb;jm)3jYsniChiai22|Je1?8 zwE+99cOC0J^X3v&_*q1a|CCjSovPD8Pw2`zy&%=;5uo|=%j)!HzdGFub?&Xx2h*N~ z`VbGja-E>=mOVV}*~2RxT4oQges{lwb8~n@dCZ0wSP7$VGqepztLXafN;)2p=oka# zth)wpt^IhrdfF9yop(c}r}9fNz3EHQ+(M|>_}w7yS{p{q*Ga*H^ z4JxEII6MgLRi6=|kd-6tbuf3e)|wC`ZB@@TmUz$1sMCj6^tMzzA0$#s4-hY$A@92L zl|6*koOTud^EKK=YJUz*dSx1w4LtH*!lPUELcd!O`l?ugI0)xpjQ9n@KOo!>!2_X# zg|PyHH2%YAxD-l6!!G5`Z@}XG2j5>FPY`)jTq%#ea&M@xOE$!AUWFH3qXr+w@}#n> zr(Hq)ys?$Fm3yIe?~S%@l4m3DiprRBVOM_{e_@^|mAV{iapyH;?BV-lJV%moU*GPP zGwD})|F+6#ziN{7KhMTWE|p5&CYM|*dl7TU>yv*h^gL;M`mFi=jU~6Al>1x(^tn8# z&kdLQTp>`{Yi0COhnO-~4y5J9c!IJ=5uP}%;Br%}$2lH8P4Y8Ae#7J%8?LA^*r2Fi zjm>dd^_Nnf+bRuyu@Z7^c@8X!ED;4}6)Dg>2;V!Qoj~wGXoTQ_@av5bAWaKx=OGAB zKv)1F1JW1>PeA%I2sQ{~Zj|>F)K{55Nav}iC{VrVVAw4|p2}XuDg*Um0drUTu0<*i zG0UqSIO~z-C6~`Hf;^qw$QptK`elvg$mQw%aS09jvfe!na>IAHu&6_GRjP7`oC!N-0Bv$eIxXZa9W$l8&T6F1jQjVH-968bg{1{aBR!!8uh~(KMmHYR;rIRhpYm+(nVfbpC zZ-Mr3Y?1=K41tuD{(mmZ8ZGOou=c9bY5{3kKfe#k%AF+J#xJ+1@U${CyuWv-WM9&s zR*HqSE5&iO2YJJzD@7apY9Cep=^#%(3a!w!p?alghBy_Xo2k(#Vx)%)86Bs16-8wy zt%<_lyG}GSkdMQ8F7OA)3uYq*>IhG#glblc4p+JpMWFMH%nJO@{kI{X{QTVcr*$v` z9#7^V^t;1_pTn=fTw*y`mgFWXkr3me{i8x4BjQQ9fXv>%I=8Waak<@1Ri}8G(q*hL z(HD$o=sfdb$_hGVVR~_HwQ=mA;+<}4j3!*FQHP(?l#=s#)up1=jGokpN~4VVyotJC zjI3b)`!LyuR`{&KnXcrR@2M1NozE(mx(|($ZOw)jMZFU52F^)*Ya(B@O804iL#jvr zryArZEUY8nIG1N-3|c8Js8zl^9UtTeTFbE$W@s>1L$69tW(N1P>Q&9dh2>#~o0M;Y z^0#&wr9JTkc;3{d_9F|_diW{vMK9EPxKkWwR{Is?)-n7##RB-Ngg2X6-Jr!YMP^ck zm^0$lj8{#H3z~D;)gQ3R;|)UwZX7P$8CHj;1Qg+^hz@&Ek;oX;4c6E0t|nNiPgIEM zBgj`60vW%UJ_w&qx(h3g4<0fcEIw7}4R%t14*vykQjKaq@pA4IjSJ8)Qoi;+pior4 zcnao>>%&N^KI^TZd}@J#+S}B$@2+-3g)%s!eTc&eHbJ}h6pVEnBjc3wMWZo&3*}xR z-Lz-i=%>ZCI+&gP9cE`pP#uMTk3O1ef0Xt!Tjq-eMn%JN;(5SN+BJDs!uvu_y>_;k zZY10)2HLDbYS(NrC;HC7yRqxd$T+0-{U%g~Ef@*8J)~SKrrdvZQx<<|ihr8)jNthc zucnr>_Cw`3$6DF5L{H}M-gm2A&5`hhOvtBT5mR|mKf8<$ibI;^xyVIX3fz_v2pZ2U8U}9qw?mrRT@hilGB`d%xEbUx- z{)u1Ko?rY+C41VYW?bFr2hlea6eC#Z$MkqYpW@xLj6&?L?N{JW5{gDmgPp zI$yGkoqOzg)3kFNtdD_JxzSqBDvvqv$Kj$Rf1nJZuv4=QS%t(-6n>79&z&3v9#c~` zxa(Z4@Z=(=C6LSYW6&0=bdSNLS3fp&3tJe_Kxo^Q?vZYf*~-BVrp zixrCq)=!7Gut|ri+{=eZc{(<@>s`Cxsgj&kpsQRz9;RA^9gJHY#uN(IK`GKZ=v{T2 zyx*6~B;d*(uO1Dz;&-66c=Ze(gO|tbHEAP3KQ_cMqkjLD>*ZF7Swvy z8n)z+7F&haJ4oKUc_q}ej#^)Nlvk$A&7ejaPL6?6jBRgU&{D4I{aPwqBvVjHJmQ$2 zZsn;*kMf$7nHg!^*QSpn=&qqsev3O$crWCqL6ub`o#ds0ysW|x-As+6n5jAn?UL+{ zFNMJ1-S8%Bx!1boRc9miVva|q;&Xed4xH&=i_h)8*O}3JrUQFT=mLG-L)I0~d;(*J z)^Qu~dgfI2Oy#21Gmn7eG{;(c3XYC(mQ<_e0;L;?qfGX%~C_B3{-!;HRzLrVOiyz^&!zQ}+i#ZiXfKnJi7^vIWyQ`ju zr~MFfj7N`u23E&Go-(}?Ht64tFo_#L^CGJu3>rR6E7wQHX%fS<`gf2U=mSkD{63dn zDk>*EQ}MWKuBbc!&j;=l>56A79(F(J`h#n_NIS+&e7OVz3|Nn2Z>appy~FjB`+r^6 zRZp%28+Gj1%9))CL$ateDTxOYGc%5kK}Z41A}4u>8$Vv9{)H=e-=<=djG*tuXeopyo*4|I{WX1SL+rCz4b zSOq=jT`ROM>n&41VCNjlc0<3K2Q6$~YsPaX%>~-!EV<*@{tS5PA+jRcd}ZsLASxR(&D3EkY%!PgdY^%mQ7Lx(E&1VFm=6>Fsx1O0JBoY?WpSH37*x z)^IXM`$nomSEsyFupHO3vpF>;>!P>YW(2hnN?DIrv(veGj9;WGtb!lr=nvKiFw1HE zv6Vssg}_3h-iq8QeTQ>2o~kQ^zIFHi*4ErPqSWYZIx9Y{;TX>y zHf697-(f+5=6|ViH<#!+2aJK!@C|qv@#oO3#Leta!2*19NeV!Zkf28ZwD1do)=D|3 zg31V`bw+nG)}CM1WBSM_t+id}wRqM?a_HOg(3#ONX4ArmQKLqUfPe6J)Mfv!i0Gdt zp*Kv1wM?>3kD9Z}anHPbhsX{qg@&EAuKuZ3tkp8+aOT9n(`w)az(PFe7 ze*cb8ekGTVN$We&=?*<8tqJb*>O4jER$+(tcDw5E`bZ^xXzO6;A0K%sA&Wx!(*Pq^ z*wtAU3V)D}jez@k=d{pY;aLyQA9ogq-i7A`cy8&O63z2ZkS8UGD#r+OfD(RH6^&uvjLu$ zb|#06mV}VrVhANzbRlHXgg_f~($_nnW$P>`M4()ql=NOCFjVD){ae-cS%>KB*RV6V z(U(y}12yX4)KDMfhhPWaHg8v3f$Lr3B1 zUigV~0DfSI6&U*UD173vTPMQ)KnbAo>4YZvKiQ-q!kGn|Dxwg6!@lK5? zh&1*iM#drt-8tnd?5cUJxI$Ep(z!=2B7PWA%9v0(q=vdxI3v!Um<94*+;JqjCq}ua zRgZ?*itXWn64qY8O1KJ^D~2`lVONdPq3Yd7fqB1rgaREYP@sYl@|oOLcLLCw1hl3~ zv^I7RE>}ym>fD4{?dWA~xhPXA^Tlp8P9ooXm)@4bTLQdQ){u3Za<{`pb`u|T5ehOp zTrg4!uF;hbR}u=;F$!v+Y!`$V3*>d5OV^8XVf?@PdQl?ae48I{y(m|h628`YQI_!C zXDILu;J%qp);x?@g`ana+;waU*XGuFX!opYU#b1c<*Yu~P}jk+xZy2|q6*X^NyQMW-*x9J2oPrhG3&eb}rjaXMr6~fF5 zQDLvH0c=?J2gjke9N}rj>tRZpk-?VaoFtaez>{b=6(Z;M+uZx_kY%XGZP4;)cqebm z*rXsezOD+OAHRT#t1B)%qU8T|(f#O&68h)M>e`CqSxjr1GgM8zt0;7KY^ zcM@f1iVCM$R8+jh8iUl>RqVNwi;9Vi`>!gJ_S-At7O-N1yfPas_Z+a?bI5wlf~n8A z-(W`^qiz7(*+_?9RAw($d@xHaVD5H9sk`3@(}{0}jmn2g2A*tWwcI^;m?zD%nN5WD zM2%a;o(~$siS*^A*7hrvXvepHA#0mUU^2F zr_{5_hqSdrLaW8Oj53mnR%}@*QYJ`&7M*lBAwp4BVQX7rh@>S%Xn5PyrU}XE1}?c) z{@w=_{oW=SJFBRvSCg7z|$ED)z z3hF)Lb@C;iZnnd(o_vpqp@u0MdcUJe*-gRJo9JfwJ86#>qgSkgr$dE_4{tOgJwOd3 z7CD)_Dg74VLqIjMOO~V*-*NJf|a_P$G3 zdz;Xcl2p$49IKpAEY1Lm?Y}>mG~nW=GRPQgY~Si||^<|I~DD$z8aa zP2&L1NX{|OmGFEWX)xn_JCd%E<4h2@tYZf|1!kC`8j{yAz<;WPsUdl}sw_}HS2cNV zs?Np{nY7Ge1gj&d>lq2&vQrlM8!c~S^f+=fE$vr4)R$ij$qL6+f62MkZTLsw+NT2 zAMtF3lE>CjnKbqD!`Vx?sVP_5m(QgoQ~5sF?Zj&QD|f?0>&Q!)>@i zEO=kzqwq{onWU~?Qi6mJy+DD9`hc7}GNMFs%No(lN^!Ic%9YCDK%*L)S@SbyZF8u! z?^}-+VNzJ*C+p~HKXU8A8a>EsllAp0MXQOntQ0Mf0|OjjOcf zhso*y;S|xKr+D2*M2~8lsh3fnGEick(LU4A2z_xrJ|QZ7$x_dTINkA*!oW0KwFTKu zh+2~^dK17R)OH{n#nC4$p}&@79c~njXgFY+oFH__)qc)S1pZoyWbE$h+W=lAarez|y2M?@sqLY6 zSg-Jjm%2Xvy16C$4wDwSC8YP0I|aIWns}Wk@87Z#C66pe#p0F?_dz?>DPFm)L=z+{ zHFJYR3Pb{Tgw}@*6x8Qo(mP0+=4EYQASN|^o~+nfC3!$SNgAQEIb4C%KC)6a1X`sb z>_t;aje(0dY5&Y-2J74?Pa7yQ6ZixuM@|22i@}rXS<9M&^0!B6DCwuei6NqK%Ij=+ zBDM&QFzLT+9ceFI$=?pYdz!Qbxg87&^=~tzJ-p77_F&*@w<4PsG~Y*J1?ts)SsXQ- zVnF+u{wVEn_S#jt5V1JdyNP9Bb!m%bo7xn+ahfcxG+KnU{9Pme5j34eP8jEgA3sgy zpkYLZ-GouT+#0KRvdi_Y_ZYOrsdza%ibIUj3fczw@eWDvIhd%fL7-<$gR6BG}dDo9s(iF99Mhs31&@OFhC zjZ`-d;tZZao<9>CtejYXtB#w+56;cc7pQnZ!j!}pjPBWxcm0d$7b0u0SnoN}A6E>MM6(k?J0n>OWSc}rVA(ajIlhamhKFF(_%KA^( z&LE9bLpef{5rKuR2^$r^mG3D{c1rh@?kQ1m14PO|LwJqcCSpvrU-9It@LEK)j;eA0 zR&8LK7Uj+7lpB#v-QdO`5v4X@!NY{y&QqPpKsS=F#FLSM+(-c|6<{;uE5gWjV{jc% ztMWsvg2d3a>yI6SQ3BH;zw+z!jPP~z>-12j zKUyY3Zp9F4d)vOz4!z8t8dPqm0A8$V@B0Q4BW&*0#CoUn4W#E7;XrqKv}FFYR5J7g zDAn}+X=O7bEbB&rrZjnEu*@Ju{SZc|f&2zggA*l6?v^~sCv^~X5wyA>~%!SaVrvfjRcRU_K46^)P zG`4)Dk-29$D=wzFkJyA@N@&R0V^1rgyal#}WL0%YV)HNogDtD#?4CR9<^VZKogYkU zTqhPHG6D<$eLq$E?v|qM>%<8rB>akKo0>~(rW~4($xr1`9!1cJFP?wBM-gH@PK<=- zexY(VV1iHhWdeSsb)%8#f#2YlPLHq$gA|nWHK&TuI%L^Wa*)?28|&2^<+r8=+GhSYRK?>4Cy?;o{H+bK<+CmcxWhu=tbwP=e`&(|t8JcWi)>PK9@#t~QgK zx+<<0KCMF?lAjO4yoJ20@JH;^XP3Rd;xvIw;PjAMF2SOX#1L=RM={&Onow_=j4Oug zu&IIGsI5nqQ=N&1Q=R%DM!%^Zq>~)2%LXO!AKs}p9PFfrfbIHo-xr1$!Pm7;OqbrY z@U{ZpY|@(%-j;MxxmBmnq{?@iS3sYhUDkI7MCU6xH@V_HQI9GzXj|)g%W*yhtRXX}0A4_$zu3SCg0Oxq!=kS3=`&swIL|eMoLTe%<_~$3!8hP?+agy z(AL?XqoGb+Y^K+2)<=8iubqwOfBL2I{Exq&z}G4Addf2`eq3^H;w`{Y$1NFj{-l$H zpD&gaa==T)>(D+G5h^hOC*ge0#C#36p(LMM=y||AF@G`^gOf3J9m=NibsSk?=vqLH zeVaYcZ7LZB+#D486FZRG#z7;UlwWE{~>Z3e4go7o(Y_ih@`Hv?sF z|3YNGtYs;l&`;(nkoicExmuFBi%^*OJbtO)?^l$8}V=O3~U2!py4*NGdMR; zIMNoQkfCf^&aj|h0p(Z=(%ua8wFM^ueG@sDMGvc#cAd~G!-UoCjnaKvItV(fLe`$D zUfo&Is!>OEr=t@wpgqy4PTCOForvg8Wh2qnvi!?3X`As--;8^kSsj(bM3BR1sO>0_ z!wC~v(;@S;yS+=X){}snBE{5LyXBbD|Iao`$jH9rUoiw*-|Lj@n=ehD31MstjILy_ z#1=AbCwl#9@2|TA-b*^D7+%VBdxhP#;C(b#grI z$fE-!p2Yq{Zu&~9U6esTC^cOz$I9eAp^jXeGDVO{nGZZnZPujw_lLg zCH@Hd?t`*{II-W#M53<|X3)Y1jWFLQvl(KG|JjRjOrhH_`S#Zq_X*Ghy6EcWXwQDl zZJ5Mr=TPHDdx+&>43ujhbic^{aQHqm8g2?%B)kn0Uhk@?9q=re#O|9zjkm|}s@;DC zJYT4PPL$m#B-hzJUuk3r@~*1``p7KXW(+)Nj?(1mqe+g{*4jL+@LX-)a0!H6f*`Tl zT5>|Eh1?`#h+nV0U_rG=Cu%mh6Y39k8Vq|NrrC9ZH>T9XjH|_~-AFut>0dRDdBL?4 z;AD@Jhu~?I`=-jBoeIM)!0@?FfJL6}_zM262kQW&;7OiMImQs*Ka?>rOS{PJV>O2c zZ#RSyH6M4M-s(Ox?Bam2%XZ~zzbUyitBy9}bu3hMEVAY3GwzKI9ES!GVJwLtk zw8Nv1Xtg_`9!~8yJY|4<6w2lzJfB!3ZMLYFh8puxo}!7RRs``+v=IvoF{e6}L+D0z z1MMT;1QK4>*Q!=&N@h)r zjo@r6y z9BA3{JwaMp(e=kxbk#T{tzD5X7~ys@mr|o6d=k{zbV%zpM^|_YQBk|fvS`bDplczO z>{}eBHYh?Q1;zp@NBHkRH#A)4W;I5Pa|S)n^f#`2TDc!3c{w`p+U> zTu7(aSPh3No8^h0GLDnGv5HUZJj^%-r~H;+w`~_Y( zDlpk09U$3`^R-moAkLVl4??XN1YF_FNM1*vxkdWW;ApK?q5ie*-!IR$DPr7GM!A*3 zN2N!B^ytf_w>sE-+6^_>*MrMOYms@4MO{g(4oJ)Zse%2#*H+ksZLH+*?6A-6|>< zI7xtKV__+;xVKbP-e+C!9-ie2+}gj4;4Ynz|fm1sW(%x-W>HSq9o;|wpEdqQGs6WZ5b(2%Q&?4 zIP^?t8KX7OGH%h<#QN}8=>gLBK#H_~KUj(ki~~7>uTzQpOB#WsPsH|WdSz{H8`dXl z#XYjDC&{wjRPt^x0J6>!4#7NowVK$K|K2{D?y`L}Cbo~Ji|wN^LSmTgqcPGx8Y5`K zWFJiz-A9wZ7u$ayElb$jP4>}pgx5RBKAKO}+h@JFux#Bm3I0{$ ze+uyb7o~jOIN`FsHtpQTTxSOKr`*=qS=A?`zP2CwTFIH&vs%y0nRRJjQ)4%$4rA1c zvV?EDpr=v98rn!^R^gr03ds&Q3jL|3dRisG(ZmV>8)+;G??QWcdMp)5r}yy6vCzMM z_X(TH-3qhvTSe1?A`-}Rv|pBrrb(r|dTbFq7eQS51abxy`smp78^2)xi}cUAD0Cg( zO!{X^lPmR-UA-*f?XKvqp0amWFH2b4^%k2OJvSC&rrptB-ufA8`u2Uet zPTs3eh>Lrz{raK8j!#iwGvF`Kkv5R%o^j4n@>Mm^{_xc5&Frk;EOD&sAu}tEb)syJ zSNzW=7DIi^tqa8KnZf{-y{IJN@FuWbjN!fN7u;z0CiW3G#1H>51IE$p8=Q+usKY4# z?jYd^%9nZK=2-WNDz^Fsw=uknzQx7y>M^U>3QiH8N&}c91g)Kn+FRK!snV2t|i@#eY*{jm5>Hwu3yACuK)!wNj*7jiYy0 zQ8qOcM zK&YXw_iAqZ>Dl)QJu5nNKu->H=?(ur8Xko4fP?X=Ox^!}d<9o0-Hvy7{5a266x2da z_jG9R(K5g^p`1(ah~MnW66SWOfZ9}aOuAKhApRZkhx+b_?*q#AlmSEq$&qsGhrb%>jH8lUU<2FK^SF)3RK8!@V)n6;6H2|`6-{@5Tn z61%<+ZH$%$Pc5c&T~?s|sT!60CKJ>)r-TYCJXie)InXsSwK1;B71t2G;#aI)hn=iMO2syEEv6_a)xTDf5t$ z4MSiY{{y!TXkT;%?bQTA{h;}`5^X(ZLffk)-ZTI0HH2T#tYFpQQUenH=}q!zqTT{D zQEvf%_r3#|l!F@mD9~0C^0Cu7xqUooD+ejQ4kMyBtitzRCdWN7IW7vT`^oW+D{tJ+ z@4IoUWn?MN3(xL%&s>&aORo%FUzmrShL&)Hk2MF1K!z%g_AJO#26Ub$?WD~v`gxfd zxPkJxH%b{<&~p8^_13?3?GJ;XeLQ_u z*sKU8Nl)R;4d>7InDE1=wfGOv{|8j!DBt z$;*?G8;%D-Tl)mGY>r*Ut&iM}Xd88Sq}>*@VGAAu+G1jx1~;)ZS16ss`4DV>#xv4p zl6v$L?Fr?-GspK~_QPp82iZ=@5)!tP`=d48CxG4sG#QV{iFR|K5+q6m$w+Mlss0?) zNhkd$=KXYxob%7hB>%Fa;ott3m6e%=j+`d`plInFzkDu|oW();{cq#emc~0DNo?CC zl8+@d=0uZ^c*e>WKJQjZzLxBGJF5>)3^^oUOT_yYg`3$FZaeFMKz1%1mv~!pNKnhV zBtLG?y~PgX$l7*_#K9B%jpd6j<6pJ87C2a2wVnNYP!lWVkuD0#{W|y#dw?tS^^D#dXT2OJw5%uwsC2Zyk%EwgyLGtl3rc&p=BdQ_E2qNd-QvI0u8`0Ec z1v*cUID(F-kC!ZAIiDd>85;qV6|p?3%~WAa<#uS5OW#kC`bsTt z1X>o=^!hn^%uGBT_15X>v$gMQWuJD>HJo29nkfZ(2`P{o!ix|v>TMf+_de$3p)=RX z_ddps9Xn#w2>2mSm;AdTqJP?mYbHZFBCVvZ8rgpi+AY~aT9PGxOpl(DZNasMO+?N01R-6_8;LLye?6&t&HnCDOg_;0q zvoFI8aYUIiV$uwhJa(TF-A&~5B3VsIh-kIPrF++iSt>fwQgIU6%_m6r@^?-qw5wx>>?Y}qYZkjcejwr8h)G&Z^NaFTDOSO{~taWK0xz^@IF^~!_dK$MQB zlHJ6nY++*8S3kBg$X6&?BvUaG4vVy3zVDnREN)Bg=XX0LIurA^p@9259rZ(}!7!Vs z9*Q#`UXC*=i_9gWaa27{$7aYcTgd3Nxh+pF6&aVc`jqHs+Rdw%@8)%M##!WADi(mo zC#y5N#c^J!nQ8m;$!EoEALrbZOk~jj7h>dld87t1%}$+MgKS}K z2ePf_bfHUYv>a-*hGX27?$@i|sHtPq11fBDhbm2E#sRWtklXF5YK^`XASzmdY`r~? z2g)}xGY^CAGULNydei1GrSN6|H}YR4=UDQ+CdCEAkLZHoOe3p49?Wn;sdGDz0S>wK z4Kp`#k~vtjne;inOuqr;%Io7+Un*17)2dH&C9XLx znp-}TPS}lKVrm{L-OblGALKLdg%PIX6mKB+m~JKa6i)GpDeRfUii2kovXhIaX;0twrXf`ospqt5k8Bw&{XaJ)L<(r@mksG|oa! z0L_?sVy2-H=ox=QF?GXT+IKE!A9+-#xnLSQOB~K9E>PClu4|{S{uk*-qN#;=71$-Bmef}j zl>=WL;7XJH3Z#B^P@D(pIW4Wc=CeVKyDHP8z6Evy>_L9eXR3x^Co6y)N$qAe+&$A`D1 zJCoYqzVXHz`M({d`t8`$-~UJ>wLg7Jlbd*XU^s>JOv7_Vkld=$W@sDKc)v!|kRC|H zb?ml)8tc}+4R*{E?-RMSw@VZ{CxrCP7BZf+CpIKC8vOs7J7+ukxYN~PXfXPdUM}UtodVx=BG7Mcl0G7xT`91sv41zjJ4jHf^K0|NP)How<`a z=bqO+=iZrn&oxUHfnDSgZ(?fKdq4}Nd-O^6=^Pc8#UAjzt-tNSnyJ?hZYKv%O<(9~ z;8$U*+7(v04S!kAVjF!q;S80~OXR&>7JJ-h`}Y0sZQmXYf9u}cDr=B1e>TR4EOFQ) z;hZH8Gm%*zBdl@YiQ>25OfQrb`#cTr5pfpDPdRnt5#A#nU7pa4HV}L!lV@r=+!;9v z-airmJ20HZ!~jrnz)7B4!)Gx`wPvxEzGS|KF#xX1K{AmnCSO=_PKXYUuEUv36gC;3 z$wa|tGQocfW-0pQF?npl-PIrIsn0&k$Y>eD{^07H#YC}HW*hV7+g?QDolsSGP32N1 z|Dk$Ux_Hwy@JL@LiohccVO=h9w>QFhOn{=HI!>_%j~j8l^il=RW3oLCe1r%jqeg^P z3cf>Xm9qGqe2I*<%HTH%ev^)OVzd(X6o^HRf;gPlq-wch`>s&2B%k>$r-&D<9Iq14 zc3XMHa-4NijvgR{|Nlh)L}{o9{?ay0+jMS(LdIt}k%H77wd1lF$`9KWy)v9+vAev{ z8BVg;?OvSWL}5MP#P6HF|MvYKOU$FYy_u?4eiH>zuV36Nze!(jlnmZz0C=Mm-Ww%@ zH>&LRMgzecrS|eh13!}V@kYg3g|)&t9cp^Zi)0r{sVj0@9ZR4SQk6Zc=?RE>t$IEO zj(xgYmQ2}(u(|H(Zb>p>!`36(dV%>n;47)67vXpASn8)rN8+}??AE8)XM`oe@RG># z&Hzd54i!s0S~Jen0@sVKx^sxD zVCl>8*SVj})dEjN{^;g-9+x;ikBed>_B zay$*amz=l0CzHYd4tPah;hB~^mCHFHvGaW&R6GQIFFJu^ov9Sh_gR6kPeiva*Q8_@ zGF32kX$%#MP`1u3OVV*_HQsk=c(snp9XG(NgSP%IT&u?oo1J88o~`4QYMon>6j5>-&aM3Z&h;?nDvg@oCbep+ zrxe6poKm8hZNe*RGsp(A*<{kdNN5RXc0%uUz$G_HPEG&c^f#36d*4co>s+CK(4hnR zv)E2I*-TnBeEyVwe1rG7ltBMsiV_VITj_Qp4;6{+heCA~Q#xBw7JJl<_eY`{NGtNL zhTaCoA!^8CTixVdqM5MbY#0}UAjQ;I^)frTpSmB9K62P|!P(|l_1`*nn-vf$eVEDbTsBo6eS?v^#?p|IL3nt{*>v z+P`!2W4ej>s~K5Y&%CH7?8BKqVi|0yD9!rp9j^=#*`5r-+lau^5fz@DV&t{gyyZ2? zDm*6ij<-%i+3_2YEOwvoNwdWJqDbm}8OE!GXqvMXXW#IcBv>wE+OSkAd8ugK*ftK* zAQJ`hu9WZBYwg1Z6FKKINNN@?PPGd$yB3Kf@ zpG@q1SuU}+cuDzvOeJ6~@V#vo3sPvD=A_em%U~KWgMBV60|+c2gZn5 zFywrOs9O%NfE-qesJpj;9LRohn1SUW0y&ToIWSRjn8y5yc@SivhvN;9L%tcoJv1^b zgAtUy1gKr%y2Me9SPJFPN=;^}#1xjpd{-pD477UbkZNf4`8eOoBhYJ-RxQ`xV{c@p z$!2mX3!xXU$TIwqe*1grAE)G#-w(R`DVg~DK~F%Rs-}_~S}FQo@vP)~#f;r*l}3{|ZNA511)x5H$ld!gsIv zk2vGNdq}~1Oa|{E!QLYmjgZ*i0~@Jh*}6uQ$!-tA2*taK5LqP+lvTjIK1fO2vV``&Ec%$42ljeAL?w)e zGv_ETy$a8e4w-WTGo!l=zlT?Mz#Vi~hg&?Z!!4pIpgoh#4T`rTry6=$RGh{nwo#el zjUa2~YY>qw`>$|Rjmjy=j0;4xA;&U(zDj=q zE2FlFtbgGs&CYac3snf3(@9#KSfYeMGouBie9-uXY+vS5hGZuQ* zlMwU3D~oxroXOe)boV?W86RUa*+3wZJsR-+AMbz1<9Q1+@QS(uWX74n-ZCFlioU16 zjpH--(f@u^U-TKymzK%41p4Mndr4mw&X-1fPlqBI(>~zmGgP1wM#z|!iQi8b_2f*u z>k8hPFN^)kjWdc3cFr~@q_-&n!@rZ5H}&=H&1uaLk&4U`(*iSNDymi7BUz--uG8Oi zys1z4?4fkxF2xm-xezd%a=#52&eJAycTO^skWV~|UFsIzS*>6a!JB@Xfmc~pc&^cL z>4&}lO3eC9*M@hB$z*lF)dk?{0{nhBgdR)i#95opDRJH=t6q2cFht?sT!yh0jei|` z5qsGw{H`)_=}8R6Ro{MFRpI%U;zRue`&%JeMC4t`ka#chUX;E#gq4cuyMI)*>c@48 z3?J$5`%J?8nkg`AO=dHFPmPHlvks!Iv$TNcZ15F4&kyr99oK;h3@JDtl(E8d4ruN4 zV>zB9!m|jK^p*Q~N#4&tt2JPbgf~tS###F5Whe`I3|_+?Tk8E7BIw7GKQPjeCJy^- z6w*-Cub#a9TH#|bf?6ln!Ig#yf)C&4c>fz=g?J>-RdjZ*cl8en*}Z0f70d`{_o{5w z|Mv3v^xsbS>A7SQW&%IIr4D$R?+<6Pli+zSSa&E}%G|ez`1PMb8#u2Q_fvVj#Ns}A zy`Z<_!g;;GzJ9yglo-kErORM_AEImmaN;amk*r>~9FbWmcqUmE`-DrF7rKU7T(-pE z5c+CLX#-I^>Y&|?7UR{#6uOZivEtc>b?n7D`3TKrs;Rw`Xx!9_& z1AmC;8S1V#*7cpYl*;d{2e`I&a4Kt3)V#w?_G_OwM9A=L(GI})f&TCOOeVT!8~AM1 z!Oz|3aZCk5`!h)EAfAd1b@Gu}m(9!)Ja0-#X!q%J?aGnV#U}mJou|?c=ofr;chu}u z9D@hKNT2^YnGKkpAU7xRJC_Obs504IzS(#lRSjy`r~f=WTlK1&n3u#7Qt|e42k@%I zG?oxO_T9@YUWdF}kJllOX6Cg?Y)?UCpUSVSrS_uXbh}xd$tnV3rsP93bho~wof!Ha z{N;D~8>w!ugxXg59`l^9!81cM*=0Uy_eh|C5$1+M{PE?2Y{sY6rVS785hl#OdK*0K z^!+v8-L$Uw)=gkeTtJr?ECMxDnKh5WBOj< z?Q1dL4=!>oV6qu4Tot(ZJ&o8|9+W%t!}Pri82tOA9^vjZ4^fN?ZrUUJiDt4IUt~Yg zOg7yY*-tc+P4Pwc6U}53e8u56BpT)(u)IvR2~H)4Mroxw5J zj`Pb#XKt)xSJu(M;c4$r=Wc}hg8g$hibEq16;jKDy*1Q$kBvfcs05$O@hoc{e;&cV zAufa8n&vmo{lq^Y&is_=ah$7hKwR@vI&K!9{ZYqJ>QCH*_zaM*Dsj}lw-ZxU>xF0y zR1HG2pTNIIGC+d82Q&+`2F(-A^Tnab2xk#(oPVzEk~@`{idWC76YVgXN{09$65iF* z*H=JfAiOJO6ttVkGTbLCke%j?R*lfsS7x#+aAv-W4_YP66r+02Kz{ci!ivme;F)Z8 zT#(#9j46SuF+scwL=HR8jS6Nv;zKnszNh6VH^EuJCX$C$GA~ICV5)hWo5)*~zBI>? z?<}%CYbI)kVV|%Ge3apBuZ%uwQbB7pbsi4M6V(tUj7SQtt+_Pcei-hHFYec0>XdqE zWGuCRRtB|4_Mlq_?UAZUbz(e6P03CgT4FKYLr|gx>3r#VTAjzhZz_~~*d%3|OaJaD zVaC$9FQ zHX^(q^S$9d!PlM=sJF#~+E;u*hSzOUOtmqa@qiqsG5B2**yS)hk_D?AhWqTv))Wo4 zTK(-4{5u=)YH%o9X>)${*^D9fRwepgb~Cbf?~7oo@6=)L7I;=N*rVcE#bBY{IvB?) zuFPa`ECUYwyT6wa=V+Ys2mdCvQi7#Qu!UmF1pP~~mCE57zsb?@*Sw_`%E6Mc#Wv1A ztbY(}C{>xWfEbmW-satznAG{!5+Pw0i(SXzpiLansS)-^jsgGFgd#>=hE#yuV^T?#tn<6HW6$*LIMTqDF}ah@5*Y3dbvk{N#kJyFV0^KrHY1=;CFwZAPLW5?gM@%v^N zr`06oOkfzcj`*i(!tGOXl#_0nz$C6;$CYTpnZa|`aRqq4qMQzHpk^$C8m5A;a0Zq$ zXZdf|c*HW6nZW$`?ULJ(Z`R=d-FRd_-BDn^*9l|Uy2CIkfm->j+etZ%=1D-AWOk&+ zNk3Dg9%{S~YHSKf7$RJso|y#ojgP9&<+}CZHM2BC$gST%uY7hU>vSO)X_{s?&PE!( z)@;pO(_H)o-!!Lj4*r7QSmmrb!^NZ0+sowzCS}xqsYzkGx`x*bTqcq7{c)3*8a8t8 z@pGduaYwFm{`s9lj5nVWc*pL}I?tJFxB zSqw|~*r6~Zv)HP!;9U17q(dE)6SW&ZB~dvXxX)DRy4)r+%K7KT<^pEjx9s;)<1j{A zZZXsvGT9s#ek#vJ1Dpn6iXP{>KDx|xjVK`zW#rexhj9;aknl|46O32Q{uu0w_jD9q zHG3Ch8g8ZBkyyNNOqp+h2nivN1TIeB$*#+&!S|)OF2(S{`bNVL*-mae_hYCcpHBL z@3Ju7l74u9{4N@=md9Jn<23Kv}?@1JsA#-G4j6vnIQhqtpAUW&&{^LUj2qnOKe zy#RRGdt&4L@}hv(8R(05cQ3q`1Nf;g0vPWJfVo`7b>#zI+dYEqGzJDtiq9EPR>2OG zJ!hz3v*|gYacB?ub8aW*qfopkz8tLK<$6=CVFKLI-ImFvyfw50q`l}G=HTsq0oUb` zi%>b>pAx3=)qXTi??vNkp2jsijky4`2WVXR3DqwDLb4Rd+UAD5j3&kf9Gu0Jsq)9-rx1SeHi zmHl}UjAa3Pgv<+XAXYrw%_kM6zR{1Rd&Zry%KRj;Vp^}? znd?tg{_m})OlRDKpFP7pkC)EmX)Ls_OIEFe+VB0&M=DO~OqX>@UHC)#oI4a>NhH^`d za4!LlS~#XHq#7;RaLahLI;%`FTr+j_u zuJ2X%5x(x@eBIjtW|fKS@;bP#S)*e6q;E&l-bBv%YdMcyGzYNb`Y`4yuswlC4XL{=?Su8Y7h^r=Z7-X6 zebJn|bN+n&@gY1_e54+!Ju>MzgD9kwJ}F?7P6Ui|0OK41qezJ4P)}h5;{_h$4)2~a z=KA7k#rgkxeNoO5gTe&zsUhby{nr%k z+9Jr2f+G>IWbm~2mE`9&J$LsVX>a7=p79Lp zBlWzWr5mxoIgHv@L0_s!3O-6pqIqzAOCmxhGuL$v&Nev4LZ7G{&KfvVaGv=T*X4q~ z0$%Iz$ULrV8JrbRHsG}nP?o^igV$?Tb6sPe0N)JPXW_g6&eP!71J}5}nF`mvxftic zmYnSQ4{)K8mJAusYe2(ua$DeJ0=7c3PkYnyR@v!C!%;}vW0mb^z6odVHi(3KsYTWNl zMj-{U)F6Bf8V0}YaGT6;aI{jPHJQ%wnWMmB-0vFSE!*<|jv3DzuqUtO>8W%#l@H5p zDoe`~k zzT{9U@8PSso3HzMz9{$VeteCN!58g*-uQgkvM9b1czV8e)s`3J*WwsQ*Mk0g^M=11 z0Dmt<_>0z?v`24NUjHs$|1LAuKQ%PUU(OZuztR9$GIPVN4thM9eJzv6bBf1fbIpv> z|BT-Hf2qIzr9JxRu{656_3z^K?_&Dv-xWjuu3sB}U3P!8{&{*TU1Q4&bH|pY$I}0* z9{u-t@F@NB6wToAjBpi3>A#?t{woCiuj2L38V(L8V5So5AJDkEnt8Hl1Eo#ezY zGR1R6PjZBAIVWqSYcR~Tz&_B$gStP%C>Bc%Kao&__i;6vDjEFjNsew^4o3z%F0iZY zagFd4-TD?ML&-cwy5>zIh7iW`Ms-R4#tKmnH4`$+8>rJ>V zOvvnAd!+7G{}Uj?1v)I5#2PG@ImX_ySPp!G2k>iwvl{=bvQfF3{N8=fncbs-{+^?b zhnw!NESt*H6y4hd>L&K-=khR5_^}O*^_Na&%9cWV&tb5SADEYOJMkqHipOx9Nw_X# zFtnt*ZIttHS^oRV#)j+qn_QU_9wBP5mU`MzG5;*>*Op<7bNTnAKZQ5TFAjfkBibdc z$9&`~!mNx8w!lw;?Aia2=rYKj1|6J(>&*}!n&7+wj-wD`et_}}xSkHff%y~&iBLF4$m%zYb6|O;M(&&=y(S7b3xBX;JOix9dLaV?k$Gv$#9H?{&C*- z!d#%1RxxwGF(GOv)?rq4QwE#h{}d#BR4=uw_u;*}GFXLQQT&dcbBOk-o3(tI(BN66 z_&UMA5hSzJCuK$$QT8~%_Mxee!TVs8n4}>EGH}%3Q4Gm`{(Xm=kWP1@L_%wDAp#BK z90b&M%SXQPcH1x8bvA=_`S3lAWqcN3Nk)b6T!HXh2|QN<&y~P)mwY0?ec6Zk`O-J6 zdtPcGKQA?do$EvG#&!}tdRF-U`ATbtn;cCsPa36r6QjO7Q4Mk{p^;i~-P3%|Hd9#v zSUy;&PquAj-lN7x%iiGBH5S9~CoM6c&CeOSq;&f{HN+nu+~>bh$RHX~KI+X&+!s^P zT?_0BvZ$NB+EkC2rtSOn;~4415(Y=HLcf9`oDz?e!kKd_xm<(_ervafcX<;#rsCaB z`0L4boP+4Fo^pJ~(Qv-*NOa=N+_b$(FS>|vQGS|f)L*mT>(uHR^x!@Ax}JKP>w2aY+QtH|>mSSDw*xT7gF~2a5yuQ<25@vm12d4L6YH5r%qc7(sWwB+ zv=ZkIY9CLp(Wiqfl}a>H6e2{IIVHlgTTl_*u3{1$Eo~-RrTej#W;f&k(xtkYh zC(=lrg>68e53kD9$&i!4tJIX2xfD%gp9fke%vr$nY-zpUDBYLB#7DI{$%a(EB^CM$ z%%hkUVC&Y23z<<&38P^P+@ihrF*sLQp*!F52B%O~nFj&=l#On$rIT1fhI7HK(5E@X zTd{3WKv$!=H}#gErao7oegsdw0aKrgvEbaZ8Ei{b?m&p{9?{-xz9*LDOE5~B3xNaZ zk9m8t)n?$`g8259+TGp;@ti{s#Dm&9KO&L&hAdgMUt z7v!+ZMeVzf(Zbbk*Kh`B!oxb{v*F1fF=H8|@Vcx5S!6mSTk$F)%w<6}-Tt&1jl{Bu zcdU=nq`a3b#LgU$Lz9}VIB4Xi_v=c9SjGjnd1nMaFiMjd!=fcan`%nE$c8WVC|+c23#xT7joSBp2=cft#Ho#~`9`XbJVYA?@ba*F7cy8LgV~lKmd9XrUohHg zjc!3R_;>ubHK=PN%%#;huTw!rgnE=cpTRz>)e~q~&j>9B+HAIH&6Gr z2VqIn`hI<@21XtO&4p%30}9au)g)b?$+o&F8_HI->8eq|xpvU{9$ZU`Clx$`P|N-9 zXsy?~#M^hZX?`ZUYanWC7@TDbqLE7)&NWB3wjKlRx{83F8LVIjuVOpcD-Nls9y?Gp z#PiW+yBp`jlY-BilQ!^wFjw?3c+{^=o@7gsH-`a&iaC1zfYoDAV(VLB995QE^A58jL>Q;oQOXx%0jv(~KfWAk7zIg!>%{?mUyT0{T zV1b>2rZv%4INx>8B+B-jLCmNv5Y-p*Fp3biBw@xaZRf7!nyhoz7*lzq-Ki1Z}jFLTA zJ6Jaf4Pbg@2yK*sm26em+5R(FdEyQKtz|4C|ySK3a7K%1A;CKT!~>_DtTQV4xsjy zgCzRbZmw&Gk3_a3LQGrNI?fm$QqaGef`(cQ^O$Ab>tf;>MllMjjzOCSL+`#A`Zy`d zMOdFwi4E&BlJ9nfKG%VUOSej}Hbb1TQursN@I-om1{tKYyMv1E zRTuGm3`=K=K@OJ>z?d9#x!nt6yblFAY;Bz!Wz#fo(~>6DdNoT1WxSQ;xg@s8YW1fW zA$H~ZKz6cWj1jK$e9=^1_TN_lJ+R6b4Ai!P5Z&*ySU@iGdc}9K4HbQ8mhr7X#h?*5 z#w`1=rOkYYHjvJ0f<0{jM@W1p%SeaYKzT2Dt@roz1k>5IepwSx7nJ@N?czJXs=HmJ zh2?1VgB+o+UkA1{--F}Q=GOdhToUur6EzJ4>CFvD_Fx?KK~cB#a2v6C=QF4PuPD?o zI9{c*#{(*(ILrawU7?4A(S8Zgyevrl7c@8e2Zke7DnzVwwgl+i3}cZNH=cj~N~_99 zLK}_`XU9&Rg0r75GhqKZ3VVMq&Wkl1uAcEmJUbcH-XgunboOf>#oJm+V85{j>WpWIJ@XjBbEKBZ_;>>&F5at;fjXhA$F=IbiQ!s_s9Jlp z*c7g{7$Skt%H@13Kkci5Iu}Eo2M%FAUu(?-Ulq@g%@zaEg7SHf1+{^Q2EJj;{VcTw=SxfYS#L8pOb6>v2-A_sb6@BCVIPSK5B(J13#0fx;>l(f zhWS42`FXxagzG!(@6ET-XMy^bfo_jLyozJUGL*9f?C8*uWOsCV-;o42o?p4DHNhCi zR5K_?*bPTy71ni-*1_x=Pqgjb@QV2Tad2Nu2{onoK(BkFajrRX#D&YEGORs(XZaD- z-W0yKFnsS>xVOX*|aeOT5GoLGrbz~c)l&hL(ARiPwvzI z5IlBI4@Bn`JoaCG>TZvn8TK@fc;|w=7lZ7$|0B`Y2md=6u5}ACG=^ok$BkuZasU64 z;p98W&=4iV1>R^G9`Z!X5ZzIRJ3N963uDOeut&3pM0wwk=)JF@4}9R4$grYYh8~w7 z!`(hXhH_qppSu2k$*{%y^D^A&?UCVMJ-zyWy=3^P?@luO!7a$J-rHY>sh%%dNc0uh zV9mcsG^;H-jwD3l$OAZzJkQ4wEUC$^Z16F|8MJvYyV#ZZvytSuTkvh=-rkYqbNBXU z672%Lec3A1nbxb$K~N{wRZp$Su1F-o^^Uzmy(_}?CiJOyhr0mkErNQV_{n+~M%A0e zej1E;a-0M$I{p=m{r3Md8Rzzr@#H(y zyD?m^rcb@CuE|g@1NE-iC-{PwTPbEN_6D-(w>h+x&`?$*?oYW~ZFiR$863-Yx+L2w zZnQ4e8b_5uZ8a8yHtM}G&a0WukB@uksB{U`{}8}u{A(`%1{&WX`1e5I?}8fq#mY@& zi}0>5QmTEt`Vkucav+GmW1-yT&f5&x=+Xm+fuFDI@<$pjMb3%XiACYk`#S|N{@-I0DPVWHAiK^4Rj6;amOyPC&80s{=&GD2me93qjmNeZm#teC$th zUVI16)7V|XXwE11s%LY*@oXCV9*k#CyiKC~N4TyLTS=7ud#>vTIBo#Xi-fh16`uj$ z7mV^KzGw2eZVH$*c6-p-cADoqjolGc0N)=jK50A!d>4Qnob2_rC5_z}?Ad89jh({t zO}eO?&Ls~uO?wv&Eobz%Na$@&duaNmbzJ$>y_|7&7K}Hjo7bMLXqxSRdsScULEp0)LhY`W^?>XO&WVEu&qpy zBeO0s(Cd?Or0XYMe`ea*TZ^jrSu@!yOvE3ko1ZU|Hsi0Qc%IDes4qonEF0JgauD_! zy2PC(P=V22Vu_UPP}bRTEvEx3_*zgNu7|n4K%X=e*Kqdw{Anvp(q_pY%K5L%@+Rpf zHTz7jI*tc0hMj>$WthtHOn}RfHsg8N@i}&5mR>(L3VwPo_#FZHUJd`vswRl} zXWZf~^8MLN30%{Gjof<#=1{U8?~62^CPRe$l6yh=RZiQAwG{UT#BB0WhH5XRm#ItJ zV2ogsdkI;yUi|qvM!X{fM(5%k`ObSSl?=JQETdeV*om{gw76!r;XI;sU>%o&+BP~w zpk^;3n)N;&j@;Jdm7^xFj3Bf)YU5ab6>yiybh7atB*wcM&ji@}1L!WQ9a~7J|LzAQ zw&x9aPEv}`$l$Zmr{&KIpETTRcK8c_qSb8kM_P>nT8+HB)$~Y;4ycXNW_gPgT1^^z zAP{Y(-}$jU@q3^^=>~6axb#~n`TR4xThzn+7qB!|9yqs)L?a*Ox{7Ti`p+D$>)p9r z*P35(T`j-nx^nO3y3TLnx<3AbMB}d9$*sAKl(}_%(px zk#3Kg;QuMVLi_LJS1kS>zmmpk0@3x%^Y`~F^)TKwzeS?IJ;Zfg+DM{*gHL(;QLgJS z@SOhno%ybb;(HO#_xYdU+uV!q9G>rM{s`aeeLuzbTHl@c{=pZ`_pV;`1bqGZRsi2M zjU@W}bgt`*4I~=-B-h2l@mJtE=d+&JTJn>zHI2RQbG41)V=LI35A)u!xX3s%99xU} z#MU&{$w}$wAXg4)c6{BP!@0#>LOPNunzca$U~# zB$8KiT_@nMgACFy|1vo&h>}AM$U%4gPpLmAhbMZ;AuBA03m!oZKl&naSmXUEIjr*D zNe(x>(Q??{tHx{I{&Ju|4)b@A=;Ac!Pc)Edy^-tEmqD8V86^K*h_9Pk>zJ>NioF#q z5oa;1VIt$M6le(@;EmH*m)CaiYPdCcyp>GCjyE{14%aW+Pk=v9V;g~zT;(UmxNYa9 z7Q>~oOOxpKTD9)_Uj{8Pbhy!?ucXfz==KHb(eP|1j4Oq8nQ=fh-d{DcD|#A8K(QCs ziQC{lZ{5NF4cFT0mF=Gj^_DO~%{6>|$HMg;Ej!BBS8?Oov;FJa)~mj0z3Q6`^${8c z-{u#4l?UGq*Jp|1Qtx}GTz9==(C)H#Ce>o>HBKpBJBjft8C-+87tS1jO#^EO%nZhx z?Ata8epfzch_?;4Jc7T=Q{iu`65-vej=foDGozw}t&wjK`0cBTNpNh7`nsxPzpCpQ zk>23HMW?YiD6HH_My5#Ptt{iWA=5PsK1W_+NGIy~p2VAMqoqvRBW@s5pz z)>IAsS5F;-@2SG~H1pEgJkReZNtnbYY<(HYAuEV+m;yO-n=6H4d}p7Nw+_%e$G&FgIx?1 zJsITZm4LT^QM!Sb$^ejx-a|Prb2W&DvHm4@w7iNvlI^?Nq_#$Vyj{!;7L+M8F0G?>OOZ8wIL7;O~B-lxUC#8E-KQJ7SZFI+l-;*j@YmPzh-@O?6{Oj)mI$y)@W+^7s_ptmF4n!@_3dA}j=AdKj{6v&gKc~rGu(KYb50G{dvpCFbaVUDxc+l)M4sblWtKf? zE;8?L8&O@t9Mvb-r*pJIHEvZuir&$O94_<7*$|<4iqt$sPRC{LGJ&$sahH<>s+4XU z_gB6bcbU6HK>rWQC&J}(P)1OGFI+wfWzMDJ_q%KO_V4Ye{fjpRKHduR@!~P6r0d&l z?RD?t^XBl~+G8}7UW2>%{7U%lLVkY&ijnf;bo^aJ!{|6gM%TBxE@A(wRJQsUYX5Qv z$?tzf_j_(c7uI!+S9o?JJbP$|(4Sfh@pOdI8h%$0$J@kQ?=WK?gTJv?u* zB+mJ(6w{l;8}T>#G`7SW+x8-F&ePZ#uG3siU0iq09Ywguw8*8|LZZdM!qx zzJabhm#D1D4C5xe3r4c?SUUVBDz7!rqw%gEMpMm1)Gmj6Ix}urbbHN2nK{{w9wq!vE>kcsfuMG zg-8a{#<@)CA@rzZ^Le+l?Dif>;tui zvs0ckJP&j&GbqjJ=6lVu>u;qFH#4^r<+7W9T`ax1{*MgcmEAnOSU4XIpWh3g_k_>8 z!sqSb^H<^X=lmJ`_?Yut@oXvlPTvbu{gDb8r9hSGJa=iiC`5~WTd0s$l)nY^F6rQQ zZJ6ziDQ9*}0_ersRbxeqv z5s0nF_y4Y38d6DqH%T?>cav)kzcW5(U>l?%BVjQtHC$@QZb$+xNoZ5mV+`;_-vem7;u<7*X<6BfPo~N)h7dBQ&nA2{w zBp+h_L{9ry{@l|bKOJX$t?}^@)`}Z1*IWmgo(4Id207-=R3AvAot;6n8vCRJk&7f;Y}n$;8PL&BjA7%qTrYXZEqSJdN@Ac-gA5b z$2m9(UKfs>@EO-$_moh(?53|qZoOf9fAXORRN6yRmKqL~KW{iRX_?_rSuOM%Z&G<4SoC~pDHDt4J)%%EJ9$62k~ z+tzP4(OwBbS8Lmrck8lXw$wRdw%B>sY`U5-Uohj{pgEgrjI{{!&TaZXNBqrm&!una z;B1X?p%c2*w`@CJaIBawtJQua0H;Wxu8MN;%K^f<3{~t`tGF$xKsS< z#`;YwHZR?>ctg$lc@1-|mq8{sd{`zp|6ZI|PKdp7NpFd0XG@&Lvnl78*;pPpXS+P4 zk{=0OPQ2#m;EvWI&4m!6@qE)!oBm_%aDR^~Zmg;K&ib$&_u4Bw9>n+Dzb9@$S##o6 zi)NL+jxAqR$*9;vJ_&;%D6auw3=;1N^dIXuJLo8Xlgv7;TRLvEav0~8)#KRd!i5A=Yi$o&wKnjpZ4cnHo2kTqbv5|!SQGwRtii42nwMaf16Rh! z9)MP>eW4Wd7cxo2+q7?<=L#y%b4YWZqiW7Ww7#zbjOrfiU0CY?Klfh_-0P6Pq1_tT zKYAbZ4=YQdPcWAG6?2kv5nBGOiO(wyDM@@i0FO?gr0Fhw2_CfSPj1!&^$COMlR4&tK{ zj>&M8z)=i`8jkNEh6+#yn=}Tl`)zcLyCt^b=KgmN&y&S^w)&<1_kh3oo+{hwe!t9$ zF%rmo6MML#9SL?#b^mdjDx{)!fyZIN1F2yAZ?nbo`u%hd$jzPqNF#H6Phb6hx+n6> zdRsyan%CMAW87VBQ^vSkXG@B4x7L;%)y@fm`ih!?Auz z-HH~*x<6=Z-BYpdtG1%~vF@jBt&1^YAGwvTj){e>cOSK-$Kc?QEhEO=R+~D;-4J{JXZsYF|VDi}rQY<%`jluGv=fqt0pT->N>h z)%APsDyO1^HCsfx))o&VT4Bwjirwc5G!<)AY>QVIf2-IhTogb44)1dbBXHC{1 z2JFrlu&;(;9o?{l*g&v9?7SGTGuB1;J$yU@YmWgtItFaky2$&DLF}OzFp?NB*VhWP zz7$2PEe7n_wf$iagkcv(!PdrrT^|E>+1d!7GrIYl6$AE>7_dw??ET%a_s4+EivgRw zHhP|q@HPw2@rgGNoPy`QEHjM4-{bwloLn{A;{Ulhxr5krem#SV-R+8=^)iSZ6GZLP zR*?v=FWvY`k6t{1{&cQ*r9YhuUWv?S?U~Ig%;AkUr^nBJqtTWKE68ibaN#t46L+9ogbbh&}Kb;rW2sZG-u^t<+#DLu#19rul zSUfK5!=uv|nT4cgJ-(mkaT?F#Aoj~(Zypx}&aNQQ*<&P(WvzSgV=Na=y}D1SeGBQTbK9L+Zdx>GDf|D`rhHcv^To z*lr`3vW|ZJQ4gM(G4RyJ!1Dx;XJHhc?>^cdg{L?Mo-r}-PPu>bz32ln$AuG$5KzJ@C(E63<=V>hr(|X9?n^wkGyNpD&AClB3BF6>9^-0sy1nAWv-p!Jehpw-leR@VFR^CbHCFp1<*wC;{U zt3C#;MKAs${d=PHe+N42!gMP7(7D~419Yl@&Z<>W`j0{9=2bCb$*Nzde|InayYHa? zFs+Atef00GT}q+_AAtT>M(N+vpVn(D`_tOF@)zpg-An&>p!Jd`tp7f=vYwBhBhjft zp#PP4?G!|O4`I0=6*~-S$~#rOM=y57IqhyD<#E*>y~M7us9A}J;)uAn^_-*i7=}1| zM~GYQ9tdIYE767x%y{5D#hhcN*T2r8nkyWo`Cf`=N1(!LJGHOFO;B3!+BOdwn(7p7 zpTS&m6QXQO5=)SH?gY+sg=ZDe?Q_&>_OEV@Wwu$EGZ1gM>K3PA?ytCsX8^ZG$r2(8 zevyO-Su#r?s{OZgT!^5W^+PTmV7l65UNMq+3A)LPh!6E?SB6^7XOyc4cH$X~b-wzx zY^X;9w6u5&+G^CoQ~uAzP6kFfyS*~8S-sCeY`yBI;v}|u6W$?`wvpi-6@*=u2C?Hj zgV@m?Ivi^wceNh27WZ=oG8Ev?@#I*ZP~-h|lKC}_l{DQxiqW>AoL6SOtEU{qXsiCV z1J8lb@cCySaf3{hIhJIezp1pAncAjT5%(o?#E2F>XD19NLIffVc>TJD!EkC;=N5A4 zzuQWz7c-)U_>d}2Z;T5mBsdEsl3NVp%a<5L=2`=77H>#17dGJRTMBJz!yxl0Mq-T% z>5w#}q3DeroVt;+;%qj6St|`G=ni*5qcl{EQmv#_%XDz6I(lOUM9aJQuZ(e_5d>ao z{hC~rjm!h_+B{hYmuo%aMlH1M3`aK-uUCTQ#^DvI!wEyVS!&ncsMD95=&jhI@f|%& zlR2!OEH{a^X0W7R(uCW>mo7YugWQ_ha6*b}?Qqj&ct!{G7TkCp_m95t>ak2o6E5NW zUzESlCJyUpcvu_r+^Bul5)v8egyTBIoTV>B_L`@dNyb;0Y`l+1PGrs)X(gIqM8L0d zE@^w6?^ne+kmg;uig#-G_2C)=Q9Yieh$o$R_cfGF)cl2`lp6Cw2LGC^Dq%i0XRvDj zJ^c4zoSWvXZv}(TU-^il!|l+@u~(82MfY5RRxC#O0^Wj|cDE?GK~LCe3x2OxHm`o- zc=dSu_ycH|ePWGE=PG@n(jDxU?$+}^l8k*z0t6gofvh}^nw19D;UGefZ+rE z->v|S`GgbYgVmVPNP&kFoWdI6hpeXCsZmK2GT3uIGHPE6QCN;=U1at@zd`L|EhPG4 znIOL{t>O(*#$ill>iL~mBvxcjwRXBuWs^S6PBAG_b84Ws=z3ePVQx4y+moB_WBzDT zw`p=R*zbaba}fKg3$Kw&KuW6(q2@)L3dxOh`%Xr>XTY}e(#O7A%c|P-^b!4u>;JCX z23i(-$+!Z>0sf$l_0)~W+2lNU*3#E?c>jmx&}w(MwQVwJXYYCuc|`C2{8MMMS4=m1 z;|M$hIWp52&oZVbh_=!bPDpj^nL3RvK4g>~ZqqPj5FIB#YeCSKDn0R`0(my0$*JTs z+P%S*Ae8?n=7e;hV=q@ylj+323lNoIm@%H7rv~#+JWko5fL}V?@@J{-9sYzkm0bqUoC>DIfINgDZ9J4!v84xwf2w=7I|XAb zRFGi*)J+ie;P(@nQ`sZI8Z+LRM&wN3vqD{mk%v)}Z5i<$n57uT|u)cA8 zAYV^;gKpmjo`Db%+v)b9pk=zfg2pz1M$Td?JX4h`u{~H{xIyjL*b3U@P07vJ!p;Rm zPJErp&f;Yc^+9U}nW8w549cYh*=&r+rXZNGk*8x@k3^K~e@-UaJ~A=;gnHEN7#|A0 z5#HkhbNO8$)g}r1C_YclYpJX%h}yZu!aUZMtzu@V5w|Bi&LgdbmTDY15Dl?l$-!px zLN%V9avwumP+nt5OUQ>27w;+<;vhETjCvB&a;CsSH19LZbMQVG_cNHDnE_&Jn_g^} zS<*hlbJTK%4Rj2*w3rpf__8Zfi-B$*%V%tw96)&_AIu%0t8Gc7wX{_ZcwyHnkCB z-sf@G9FrU4!nk~Xyq64R%wZzfzvl0t_D|=N$PD;ha4xwc{>%Q@_>cC(|6UmXV!&$y zy!CM2H~UWbTYm!o+J5*~h4H5XUIOqJz&UqzB*&H9GC3^&>GaWq5{up}WWiWOuQ<34 zv|;CH@SYFw*%DBQplL5D+o>OLrO2XVlEC*RbdJL7?}L?X!2LXHEP@C?TODqKiMQa$IS?p< z2w6w9&!?xTmApitmqw=?guY=TmPv)DQogfv;T7l`4xznr*}ayjjE<23eUEqE2lTZB zQGv-m3Mdo;t80JF)F;FO9~l&pA?^50xg{p(LqMC)n@Kpqd^AI>86Frn57Gv|g1CFDMu@quwXR_Z zro<@OkMpyt!B1EjVGpzfYY79M{3AT$I+eZVlfR317s9<=2}5XqZI|!GyB1vv`>kQX z;U%BRjPs|8oWjZ;g~!P6&;_*Kjkct-Hv+=?RqV4>t?^FUhO-^wd(cm8Jt3v+Gsz0HzgjaItE-8STb0f zR}3SS{m|Z?VsKX3RCXr+whXLMB6ciPOTCrUI{=pmaKxacs(18qdkMfT_2PZrjshHh z8qf8G+H}-5oTY@=inEm9tXX&!vdTejMMXH*hS=7VpCr$*=%A3FB-65~&-&wRC(0eu zMgsrW`CMv%U5fWj6vG{tR}$6#l7_vo#5cArm7V4f=WHu-I<9>~1Bq*GLw;)r9&Y@2NMzuz1H_kK+d zSuUIN?>Cij9gpYBR&qIro&Y69%|x=0xJWbpZ*Y&IW@7N0_26Uc3dZp=YQ2dTj%z33 z3T3x>l@(Hl?t0hL^%Gie&eW;eMf?->gG<0O)}xw<5EY?cg2zs(b~Fq*>W-1#@d-!+ z{r$;{O26$KP%pZ%bbQ;*nH6!42KCdWbf>JI;P1?;An|@`LlT|j=(^!VCox3sJP36Y zo#YU)Q*^_Ep(a3$Lsohe(1LC4D#ItA;hO63*l!{+tmcaDI#M9-c=_LMHBPQz$pk#Y z0BS7+uEX#i)T(s6sD7w4zH>x9bz>=W2x^r&6yD{UT{mZqrzfDBb)yQHx?!SDBL5?O zM(0Fl8&DwXB%zejsdIklO{$EN7Era)cg%N<)K=4x6 z4`*J{7jzD;m-75#x$jWF3RI7&mxLt%a=)9(2f5!}HxlHYFL!<*$UR@|l-{sR{2{&2Ng z>_i$oS9!G=6-~5Dyrp3}@9v?K*HoNiyLv6qnTs_Acm69nsm3s!sZImXi8BmscGtB@ z87=>QWe8u^fv;Dw>w_hHiQuWCx_f4fTcC6I91_iWgzF;i6AfF{UU93dre@+lTm(yI zPzq!LZ(`9~>MR7CNRaGr$T%l1uY|IcFQ2gJJ6NtHT0|{~(uVZg6c`lng1*kBMcrv-vpVOmI{#Y=UMk*FhORKw z!Zs~Tv9US<#Z*OyPWC1R9f*D3=q@x#FQRr#z3#O(9FpVRspzd0>jBFe#*$r|X$QeF)Q}>f36K%O*No z9p(OQj{Qe=o%FoQT#+Mp_LE%3<2it|PX^B~M}DrKqg`MjQu^FBHaAE9aepgtHO8o& zr*O;TN{*C}0lZT~oI>;af$v=U_|u$zQlv^B@!wy^l8Vj2Z zjk=<%Qs)G~JHs)>AFk}S11ILlH^*U^9fx62zo#1|Ye5`_<^3d&^^~@j`nqf+uQZk} zF!M<9SHTLf>N)a?e(dSY>t_mZ=Y!mm<|?6SH6$Or(gNH^|6jxE`((f%S%KLK{by|` z$z_T^eK?%(#jWyt!z5nLF*i$oX^M@#4fhPd=@qyiUK<WUK^S#%>ZxUzG+(=Cwj4*CH!rY572DhDNTZp@@<1wX2mWcx`9+kbbVMmHTp^Utr|ZsE8~H^Q@c(S^DMtnU z0ksC$E7wV|U*d3dyl8&)aBjbxMO)Uq1ekr3Z*7mNHwMoVhcuh(A5QDpjWPQ@>z$F!5 z_&qBl%ZO=vrd&SULf3cmvs{W6&O4%uI!Q~FuGawfT-xPu!P_av3S_g?oNFgOXTN*MFg&# zNiCt@&>2ACeL06?oJSj_8WN@Ke0mF(2-L+AQ`-CBn`!%l4n4gaN(BlhF$+LylgS*(giF-~N@=G2-cZW3>^5AFyA15l+hHP*+_z)Aw>TyU>X=?L zf%XM|VFh^eT$dqAxSde8Ho9EHM3*z&^i~y*tDFiRH&MW&E9Kexs`rAwJDDjzIFu%-LqxdKS0ZFK&OVreLP)Eg zZ>~d}=MUXsgFKlXZjQ3ML|OvA{!XxC?rX5mpzak)23Xa|rqU645>07HtDH&!{5FIqPiVGr?P@=BDc@vku`nh4iG{w6 z7G_~aj9D~yW-Q1$NytdoSaHOjJZbT7v|vArwX36E>-GgIsY=K`#lRY({RE{7y1B-g=yf+%`J`vTP!40MzQWqIas^HqVA$TI6S%T z^PAM@%BH5T?;e^9N@_%nJ1wOVgS7gPQ^>gNo z2Fc86{-A}o3L}ip6io1zHeQQP(NUT5+Ce-+xR_P|MoS0n&GYDOIF9MTn3_v?kyhgF z@!`oWWEuSQ}YXfw7;0Q|W@yd(Y`g<7uV(ZaA8 zL1TrjDVv#XI8g$ncTZ~Nc~Ck_H#l}ib(&v|;FuwnzY%;LD=4)`R4wIK9rz@pm`S%Ts zELH5`%B@{`y36%Qd<@f~#J>|rx_3eIUg>?HYO@XFec_0EX^W0BTM|#xT3V>k$&|8Q zz7yxIm{P6R49}eRXUl))y3eWk8E}ACx5Y4$!RIRNRX>RN&Uy4(@##k8>9l7nSR~GF z37R@_1j#c{0d|w$eK=69B*ZH@BqfI#a;$|M z74aN@QF1Ko<>EPNNoBAqp?~z{Q2*)Z;jp2Wqs=zWv%D8M2Px(r=3?58zOW$|qZ^`^ zp#3@L&!!IE)R`sU8LgB8F-GK?569LB=FJaCJz=uDC&qU?9jgG2a|B*ji5zJX*)b`oD&CH1 z1i_7%0zMt-PvY!dZ3jkl1P)Pl*6X&bd+ReX{$=O&7>_lY9Ww1&3pi{VIzL5y6mh|) zEO@#xIuRc-Q@%P{s>EMtp~U`^(_ikvCyWkIK^P@J!sm!u;Dlq`7Tah8T}=rw>g|`AUR{#;q8UcGdWq3z>3ng!uDrOvIAdK=-;xp%HYIx@y7f zJseKCMtE{tj0m6Lp8m~PivW~=Q<*_q3=+&fm3TS`5|h$dZR0_PF&azq$Sj`o{%XaK zorlBP2JJ`&S4L5Dc%qp4SDt5;9sikfv-143r-H7cr05-t#}mQbhWxEYD7!hL%A?rg z0eLj^_Qh=8l@S-g(=bquQ-c{H9;D@33i4vCh4Sr@7RYVz03PIJ%6qXr9Pob2AQ4G{ z0q{6RC(EZkE;nlx|3Q^cZ;W&ujx7_?H$NyPB6;8(4~MgJ6@4*_*Ax=k@qYe%Ql?BI zDO=Lv%QBFU@~+>4e3ZxKV_Ag&e2~6H<>!I$)3I4Z`wX^EGCcn&+<6~o=YlDnR(VB) z^O~Xc$^}8;gK~v8=0|GxO@0U562bTpk9jbv+F!$3MKYGX#Do%&){K!)K;ohG#KdZZ zzL?3w`zvXxg|Qn>Xy_Hb55R)rYJ<5YvET<_xfg=pu;0-!f}?)AJGuR88$u{5P#+76KCZn-pAjU5(?ggdxn2Eg zl|K(F<2hOu?5sy-$af+=P07Iow_&OZrHtPwxLN#6A<`^CvE|{3dACg288$2HVpu=; zDhcTiBNbZ1q>z24|0HUHyfE=w{(~iAO>9g9SJ$gdGe7s#J9yK>x^s=Nn1664yp@HEoB(Od7MxDlZN9f#v>{?^Q<%c;%PVDU)Wz!Cv$q zaFo;2L8hIA?38^nQ;zg=ioRm}ojGdh+AiLY-jEL9Jae6T-atp!r8OAo23KHU?{+CQ zjFcLKs)iD#w;4ui8O;`eL5YEH7^z^?yBNO<%KheC$Jw`x%&w*I+w8W16+Yb$(BA!; zV+!sXEG%!Xp*_$`Yqsr`tn#$*Ct;Fqy4;Z6SV`=h-$XO%n~s4X^X!y;Ss_yRypL_) z>qrjhXx4c+Zs>o_Q5wgwoU%Uy>F%E%AKzyD=m&~%Z+uJtkFUc$^qOWv>jvorMl`pf zX6f%&DWQ&6m?+b%h4#7KMv5jRVNZYUzLMtL)=sH6E(yO^a#4diCZX=Rf3k~f+em$& z(UKI6hTcg+qx~Ep!nGXixJJ9WAGJ^kXf*Utu2r7i@o=EgswQhRqsB{$o?iJA)M@u{ z;F&B?Jd><2rvHWKXEhayPD@dqf9|QJXz?!VuNc>7LcgldGN7jG5*n>zWu%7eo21d8 z)yPe#(UR6uv;5}p2GnR?z=L#yMymxMU@6pE5(SM`WQ-Ze{)=if^d8EG$2FQq)o2f) zM!WUFxJJX-o^rPlw3$xTWKXG@%q(voPI+ovlX>0+O=eGMGPm$E&}2`cCNs;e!zh(~ zKo3k6Fp_FCI9}chG$8CkTqR?(=?N#1q%aLJXzbA+h zoVE;eiaz_6qR%u+RHvQ8=)wGal0JhzuRl%EX2uhmr!{oV*YueN^qJ=Ai)l4JSPnYv zdR3=&Wy^PkQIA~@)UFu5P>;d)Vcy4VPY)r?v&7^$%or!bJIrh^_1RoDrC*yZcMOq9 zdde)vh9>lsS(b;)@i})bXgpO@ndOvWV|-LHTlNeguCsQ@i`>IUEkBRrmwX{^}lbhmwC+v?mO2yb?BN>#3KHCzXdmp<8dgiMz z^2Yul$(9i+a1|;wmxf-39y)g<&y}w{=Y}RyJ~z}UmBGDa_>d3dnop6}59BuAVoT^p zq|l#+WM6*sP6^L|Qr8)jC=q=uL)uWPONe79K(8P5!9r=(dHr*<{OAxPj+`X^wQE@N z!nas*#gf?AcDV1&jg7hB?%-l$H^AMkjg8^@c#|u!I$py4r9*vT!Z=S=#F%2Xyj@vS2Ul52913N=bE6sP zLHq>($NJ?g=~}G%p-*&GE}!=Fea@q5{H~_HuZ0St-8NgL_IBa|`dBkJ_ zJ@WXY{i&R$Gh4oQD0$?*q`q+8a|qYZ`#pvf1-82{fbFIsjwVw>$nGkR!?zsan-ABe znobYoENBOOpX0rS?FMgAyU{zNJ;`ftH+hTOlf77%a}w_Kg7W78?ins~yzFV?xU)H6 z-}QA-twyx|Fv>7{{mcxU`4nh2P1y#RmX1>fq+rwF&Q&b=a2fQqfi6vOf90x+we`>- z)=y6n_N_C2SZ&V7H|MwYt%Jn>U~OVPQgD%3szVwv;3l$i0z@C}q zzYmz84K@sBEBOC-Fng=RX7O75X<*s(!K87ns~;dD=nU(!Q}33&e`;sis&jlKu%zZnm97~sW>Tc_%=h4X9AF*3BWrX>wa zd27ns=QPa9)A!zqtv>H-RNp-?Yo)q(CH-sVt{B8JHCywg>%kAeIO@_s|5jZG`nxL9<^Qvn z_}{*U1xD|Y&bzefvr_xWM2RcwrzK#jl$cpSkpeDMDOK)c z8Xnebk0QR~B~d}yleVGDP}4|NZ=3;doV0l)jNr&@%~RxuRru&8==)2{kvErMBnK1F zE9FLoE~?@qEV=xCy>)b!dav+g2zkhJ*Pb{}*$gh@Qmn89}CD zrR-Vrus-Fenv#pBH1A7Q(qU<2ru->FuKNhmEKZaZ3o137$Z#Xp@FkUuG*zrn&dVGP zGNN#R%+#G=8W@>nvX@{_L^$v%SWHr!(wE@5RmgK0NGGTVD6bFH0p;=c#b`xDq!nMI z^dLrf_8zAL^bg51NE_+_i`D9W29%q5Yt(bWFq&Jl6IXBOy?ldxQgjH^kDQkaHBhci zjWL0-dhq0!$3{2*mAlAZ;>qWIndSC~c^UFF$@4UBs<)K2IJ5yZ0vG1tt1%C+@S{PI zosLGnEZ2>7T)6icd4TvgtycGF82^Rz$a!h<2XEf68eymaxtelS$_DV;iw`N18~?gs z;;W#%sf5;7-;D-w-uyAe_RLlEyiVdJ=&a;~w^JtXa9C4)kCWZZ=jmQFNX%xwjI`<6G+X-ynI!0QWD=mHogN<4 zCp|X0^PKS_d&;@?3wNNK;(c+ECM)*q8R*ac80=0n*!OGUDuHXf)j?mX_+1r`YH0G- zNlZ7%YmIZr*GqRx-=Ik^CvzujQlyO-F8(Kce=*uj{U6iD{BP4n0NQl8Sh5g&j1;(Z z%SayDIsOuWZr(C!iF=tuW?KA9LE~>(i9SsVC_~--AxjX zdVq~_i?rzg+O8~DgVgLK#cDi9yE`xN%{58Vzh>KrD7n#=npUEo(b6ejt3&)>s6(}% zY4RW5ApXu3xR?B564mvpL&AMZT3QR3XPw~Ytp@pBVspgHL-|e$Vm+(lIsm?C$V^oS zG)fD7Jmy%;TrxR_CTN%5R!%jQq{;@Sc)^LU%Qw82e5&p!HlCQUxsy}0NTm2YyEv)U zz%GKeZ`j9xU0kK;dY8ZJfTvOPp{_^F`Rc9%sM%1uF0}rL_uJiwwSr*)#{s!{2|Slf zOJKv;5f`>W#UY`npbM+L4+ZP%M|K?avgk@pzTEwq8Dvp`8Dh?!L{l&>sdNu`9A1zWzRAz@(< zw-k&_8MjCH4(+8NX2_d|ba5&%?xUd9K9k;Z_rM+P>MXF++VQ=O0eIUZ9df?~_onI; z_!bB=>EM}0>q#%J*_2kT<*SVn>#mVj$4s+YYDsR3r>Qzg(!iTFG1H>A;7#Qn>>b!v zSijlDdXXd<58_O%o^-^$ zHq>K(ZhY03d)qEY>P7S4pUB^cqsfKqGUS7UDnGMvSUrv9-Tyv(SDy#pkK^z)9q_zr zk?$VDh_q>P(f+rjiUwSr%F_yKQ#I&_Nl!i;P4cfijUJP5yyDE*of{i+BVhNx^sM^D zm!8#L2Txn^w8EJ@hA}bmA>NBQw59hV*HXbg3;Ql0cusf4yyAL_oP&J8_a7JSgD zu4#%FWs$8zC82bLtZ7F>UW6cIH}3e-b4{n?7Jw{Ssr?rEwBzGrDWQs7p4JdAK)0ho zOIsa@?^^i&-Z6FDhitybSwb!H5Ks$i!u4|N8nCV}P68iY!IFlvqhqm!EIIwh(XkNR zH~x8aY(v8)#~hH)mO3V`$I3uIdm2qpOKzY6^sdcc+<;>O6THEQFVr_3@cKlsHX`VR znGH?8Mk$->p!U6kt?<5#vJLn}*;4|S!DWrF<+I2u2JlU1V}qpfMQ3Ai!}r|{b-zD( zHNdnAVDh}$B54|!5rN(2&>t7#qjwg0!yxY93B*K2lk2dA*VrcLWi?70P|<^U<-P1uXgdOm!VyeYcsmQjAIWahL~h-4yI+>nUs_; z%1YRNn<#7aFFDeWq<|H~mBB9zxP6~XGihCeTWSM%(&)oh!8s4Ucn1U@?*EYwq|`L$ z)Jp)><@Y$}I%hgp#YDmCWD&m00ggr42!{>6r!!6g-wKSVt`Ti5jg4iekSDL^QF~@X_lFpq-cQvL1%3qLvBV!Rl%lS}879909Q zw_y%kVR5kW3y+-oAx0-YOYOD zq%7`I|4edxtzA{TFRZhFyw3H}&Um|Atj1k7R>bv|iF#K|s&~adtyev_y@g)wLXTto zgn2LYH^j~HxH>D($W6ZmTd=|5k)QCS(ETIY)WY7Ck)=w6)yE*cM9BzCmIn5Z@Tn!e zEL}w}p;v}n3Jd^JK&`)~D6xMxa6HBlgyVS3Brrve+T(Fp-iQ13A)~sYm3w7mY_Yq~ zO)})(@Zm7i;glJMv|*`7kCfml&4S%g6QheR*O2IP_Pg}bY<}@AXIC0Yl+$t}0#^mU zPX~`yDeFsrq^vLf(b*s=;&R29)s4|3--{gbAuNp)A*qNl9g`u!oi^-Nq-vW&)uk-v zc_pHw6LEzy58Cmb(*rcx7Z2zcSLwSmawH?cE1s1)fkHdbt}EFSoW^Y}gC> z{%BawEbx)MTF}F&BPPf zxHNojk?>8s-$++mxe^s#hmEg1r2XVL1OQujbFi@5~6V!4zrE8tG!S^h~Oy=b~_UCZ+IPB*n9XI-@Wo7{^mt zykNi7HyAU$Md}$A$YkhrN5clsPTJEUuE`3D}_iu7Dp?S_t?(7&ZF7&m!i72|=?hbciKlt8}q*QfnvA#F49xt&rF8{C#ylDM$D z1u#1t(-7j#ZGIoT647G}?U4AU+-A4?ke&;4Na=Fc5MmEk6WQ7q(}?x%gE2+`jJAFf zUr(u3X0X%c5=i+vP)7AAjJ>#L<@HJ417kq?B&qb#+JQcSL0qlKbV)YibviJi2JhS1;Npa5 zWY~v$efn@URJ!aOtO36Wa$Avi&^r>rQ<@^T!uSoaL3O~@SVg0fF0o#p-oZ- z(`ECZ>NA??_b2hCrtLxC%Q8i#z#q@yic61x?0YYr`hffTm`;(o8GSRMPomP3iMp8o z$l26J!SHsYyxDbCvb+Dztu&DAtb&?E?FFdCVeIc0YI?hq6Jj z$*ppPXEH||9Jn}-YQ}j~_1@C4e<_~t@p`Im>D>!$!uLuP+W3vlc;AcAMok)dAKW65|n@ z>)btYtd|a4C@{k1b@VWy>oO*IJ_REh?k_RvHU11+vq>I+* zR#e%K+v%^BlodG-I&wiCbSMu-lm~0z2OtkWfcC2~{UVw|p#3!YvPSbvP8aCwggkJe zw`0Vs4fTUmER1DeL@Mz6`I6BBlCf`GGH^AZ0Fq&tME?qf{(GZUs$68FT-Yx{n7DapqXWBlDeUtL$;(zRS7v+7P@ zpL#3wk~h*R^4$Z(zBYh+4o*P-#94bH?xp???hO(nPd6@&tV*x%CQrHyv!$eHgWe!B z9PV(}Mm_vIN@m&o3#3igGh(qszJhNR=xfDKbA0>b|fadn`=8`=%o^AW|mx(&j1h>8Kl0 zF_(QNz2=CIZH$0K0koJp8pQPbb5d*mU|T04jQ2SA1B?Rn@biRPrDtEE_UxH7wP!!x zdzkd!p9OGEw8^o3YcEN($tK#OKyI>fbzm=1E2Uq?9>aX22Q^u@6_ z9>?PSi%^>QYo|@d;l6$C^ZpqQbR36{{}B#X$GHDTI6OLaG7jRtV`Ue^p=J^ee~J)$ zrGi7~8*wm?<4_jIq2>CcVUk}?TdOVI{QO^3o%&zI;yv4B91iZal>M`I*bwC8mi$p4F&mE@>n zy~&gG(W1CM>Iv`d#uJ6Q1UygZbIG-&?rY-?A1S)Y7*JRCS|Tx@>9W@xqd|NhlJ@7M z{ExJd8fift_w`!88LqqjM{s4yuMGX~!4=C^;R^ebX$$xUq`|1n>99)Q*?eT3WSqLw zebZVp$8^FA{+d8HTAy(kj+eOR(Gq2TBTIf^n9Oj6NRb_&BY9*7@OxO2x*S&>q1_m3 ziZT5{%4<-)yAhXjW7b!r71Ou--;GveY;#zSlRO{z8T!qK z!`i%xFMj1&dFJmwa4_$j8T-LD$CbyXm*vXS8DG>hz1`o!Tpqf^y$P;WhEj=@r*kCQ zVj#1L+~PqW^6J1A-@y@4cO1OWJq}zCdcx&?;B(6~dC57?-r(;G#Ro zSe{u!+{+x)WRbL%%-{AqH@ zFqz#Mw1>9;Q%G@kZ~|7deC;4YnsfoAxk|bMGI3e}_HfhWX~WnTwni!nC-hC4Jpawm z%!Ixn#Ww{~fEPCaFaDIa(+PgmluSAP31|l6)DNI9z9zQ2wg6ruXJsUOYO;-PhC~_`}I)+DRmb}p&VCL@sZ~pLckc6bf}|lP;^wOR15v# z1+*0O?jav@`5O+f9neQNjDS{)2_kadj;Mi|;5|$4Co!{tya#Xz=1@Wx&8L@3S1UEQ zR3#tB=xrDU*wlZyf2Fi0RP@3OybZgv~$;mbL&bjL;ffN%j%69_&;+7j)`cB9hsQPpGp-k662+ zPyU1nKJDO-Pj!{hsd0KNADkT`g(@{#g;%3HQgz3Rtw@V&VSvb|0tELh(e^(dviP-z#h^`Sp8~@jCQ|Z2!N<>za$; z6&jep>k#1e**IQb4Nb=D-8f#Me*rK48}Pb22YC10$#~VjVY5$`arYZS98cVdQ2Dj_ zr|SaAbcZCKXMJ+w)(1Gc1II_I#yPs`)HStl!LP?xy5l%5g3<82L$^zrp^RQ*bScY3H|QU7Bz>1?Sv$0Lw)2D!G1=_O)j=zt?V@O|L^Tqv(;2<=~*eDmTDacO^sphvpIOI3r};Opx0lbNUuL$lwJhr)d4#4=4_S}yra@<1AUkh z3ACS(YGrbn=<~YYjCfYw*o!fv!Diq2)|s(8d25T%<}e=n4QR1;KNZNFngFKK97&U( zi{36*&@PfDd!zdVw0vN_8B*9vT`_Lv`!P~Wq7NFtKfUV>M@ArJ`larxafOh3Vs;EY zvYi9mRnI#VKlZw^sU&nIeaW$@pVcG>7EvYrc~a>Bl#gradwJ6 z8oafb-j%i!XmRHdz9Z55nIf?6<<|FcZM{AHM3MwHUXL+7uZb0iMPKPhUtf}hH3$nU zk|gUAqx=0BN3fPdaE*^@SL2>5j0JDB?sjDN;@+-~sDbCBT4=4Y#g%!n+?6K364^kFQC?q6%c)sT3191E zuGEh(`g6g(BTTC9M6EK`o+ev{uwJx`2gBs~=iFStrBFXbuJ)^=I%)Fn2hWH0)o6X{ z)Z+ZXRxLF160!98- zMkLZejL`~RDZu zcLL;|l}mf$lvd;dr6T>7<3%~8g6ef@fTLfo|Rj4@yYCBN7qIxf2_4n`wx-!y9 zb^-JrCHm0%0b}$b1$yoR=x_Q)=pR#{Co_;5AD=`lgbQf@`FR-h0|w+f%f>P20Sw*( z3^D+N4#40c;Xk`EMKWNpKTL9a!X!<_fd?E$6&&2vF~DKFf#?&G;E$L2Xt(nN2p!W<+xShe9+G~fPTK=SAfSx zL356E*H$$iLyr=Ek3KA{TC()auDl+|)#lJ0>xxzaZZ1OX8|Z5AzLpXXV6ZUkq55bw z;iDeCE=oxY!5z+>QT)Du!dt>z#f+GkbHQ&_r3XmfHG`TY&<2aD@q*u`#Z_TVUR8{n zWx8@#)o}1=m^}HdD!}iK4tG*u7Dlj7MvZ)pqUmkn9aV*(>5&F0T=H%YpKLiL6}CzPQq* z9Vs{7=bSSYAW3g_GG#<^j1cyqvMT}4Y!KR5Z!Or@OnLc$(}g=K^V>*nvoo&^SImn^ zWW>bdISmzEhhw}aQ+5pC8c*#=0khDRl7}l?1xTIRc6kkv?s4LI4R%Ov@@C5O2QcdK z?g*pAxVmbf^jl0Go=cJ`+Xq&h`Q7T}XNK4O=b2CIe|P4;mSoA#M2absmnmBZ7|EQc zp5^d?yEISL@9_I(9Cun}TQWkl7?UeYzCVI^ZiV?Rog zFpwTU+kx%OlA9y7O8SEFIKhRAXPhSA*H8Q(Okv4iRUq)lx^r~2SY5?E}HKxf$3LGCs`8XUR zKt4Z$bm@(%Yigf@ax1_$m!_%v7W6KYas~olYIobGX30enBHHhMH_TPw?grwo7*A)O zlrBw9?`I$#a*&$RGEH5pY;xuPcw!%f=;nhW6#z<%o5z%fq%8TbVNuy%ACd(5_rti> zS)Ph}n9^e0++IlKvh_%wSF_~)a3X#JmYecV%MDB_cjvIWk|af5@CNa>PgQZ?XeRdN zActhb9DBp|=8D{vr%&9Oc$eRhCBG7O*QqN3x|EtH*Fti$~Q(Bja2;szWx#Pbqml~751l~B_GLB493_?MfJ9viw$HMn#79%r&tEHP~r4dp&4 zaZ8qbqf#R8H&I5}@rFBma22osz5g>Am>0d=j5s{FFZMC$`Ek%Lj2C)iVbIxjj8IVL z)_=;4me+?`n6C_ zmV8-QRQALO^7J=xeQ{O|3)&!a8LsvIk<%dEZ^=PTrhBlqh=RnBLaG_zS&)*sVj0NE zbcH_}1$pxj%1L=-vYd4E+m#i0f*b~(xfl9FdEnPqwk>PETyjA@Z`D{Ds>$TC+hmm{yk8~wNTex zR#i^bQ)u{7(Jf9DM%AJS@W0mA!>`J2UQ(R%iy&t%0W4>!k z%qdKkOG^N9X|Z46>L=p;F(;I2hL)@E$9F6GkB0TvzUt5h@X6iJUAo6{Hpq?Gwd(WH zaME|*bfg8Yjd4kW+%xzZe1&)5pH26((^pw8Xt1YDqF`C=3<@JxkJk#pX_cB`l=-qlG=IWlO@v0_=1^00udj6C^#^l{Vk zBLcHC`nX0Y$C$7f%k_y8?y8Ej50zA&eaJW(9I5&))dz@pU5uN$1g2!|AGrej zn|U3Mckv_#;EhcAvf=xIH*WM{YXgo;Qsm-&kR}gPkXc^@)gF%^-#gHx>>W18_i^gI zz~^MI?|Vwb>`eKFVXocnQ}-lu7uhX|sfoQmsE?m;#w)tl1O4A)DT(t^IO=pES4^DW zgeyc_9hCvpryM~pCE(xua!6e7_5ly;Zl|B!1{(fIDO~_CbijLJ{}Sbc*CRaE|7Y6I96ZVv@U3weQ(+pbv&Atju>90p%!j9Xn4RaCjN^vg`OLYD zyxLeUVWSR^ueWq5Aw18$s~a(7w;fZWTg(nBe6fVDCPnzw?rW)!mPFrXg@#h! z2HZ!XV6O8TLb^6R;BT*^A$FH8zL%WcQw+V^heyBnH{C@}hu;C^?>MK={{(2yp36wX zsQ$Q`7--L2>~wNyIfhxlly-f&`zHtCxA91*k${ZNi9$KIaiyX99V5F*$2#N)n;-QZ z@W^yI~WVyWD z+V$m6Zs)OY@{>0m(IB4e!Gxe)c!QPX9f}e0VL?-DJc9VW8NshysoQO^J}j`sr;jnk zngCm@3GN1sb&V+2CDsumz9cVK%5xJbQ{FiU`O-t@?dijq4J0?$ZSiHw+Xe;M3zk@r zACI7?mRN^eprbIW7-eHJvHE%&G-#xNn3@%{v16Pj`tE(lh&%@!SWQHpi4Bs0UF4g3i-` z7Sw_UWQ2vn;=Ad075(QpyRoGD>_$cZu|Y#9jb2Hirx@d|tc0u6Q35&;YOH18i*s$B4bYyqA zSm%~%V_Xi~#_n>vMS5!VmY5WR8Z(ZDS$3869qZG|SbS3N2FIG<%F{n_LwknVU91%+V?oUD1n_>%}rOZD7&E?2F7U zMv3M7-T<_8*5e?L>`UBL<%)efI8Y}&?idX|Cz(Wc_bq2VMxR5Jmc0GBec^ zCXW;t?r|DMcq4d3g&Hq-iPB|W20W@aq@Mu|^We7$bdzD^X0nPJpJcsefOoCZBR(9S zzY4uF=nrebw@j*~c~2gW6?A3FjRQID#BL54+Hq%qD}IWfSza-i)4q4#70vslWv=D% zSXKAhFyfW7<~xx?O}zg;n;M&P^#HNwc>gQFi_^V^mspW_NnSZ6`Pd)lI#CbS4(PVM zJVJh=@4L)(xia3IDL>Os3KoY-m33>N;XRsAmxLpEcYs$x@`zV0Vb*{OSGn{41~O|& z0B5UP9onEMRW^#WwVEll#osXj(yR$3-oN!Sj-Guupnl^5U@hEa)_(`JkfKFNL1rBb zG6ja0CMcmB$cX#7IAWq3VB5{|%>$Q>pHL*y%j4e5p?;>|^OL)ImXI`-90LF4-Tk9u z+chj%bZ&I)FK{p1H#*jtivAu*zN?VNY0p%}Zk~>N^F>+_<8!b-tsnQT@yQNQmkfwX z|9Cm%pP#DEi@f+{%eOgNqeL#l8GuCOvMc*^FWNz-j)j*j#TC<}=w7EF?~SODZMn9? zgKSbFl3gOssQ~_|?nR78j$FR9A0v0OySa9ZLynQkYHey<@=Wk|)rjQT$7i`_EA3{M z-yTk^R=qTo_?3ty&iRu8P8{bEJl0{SV`nr-DB?5wBdQ#48u%rBRGm zJ`rs?RSpebSYxWSW20l(r-c3{wT$;FC4gs|GPl6QPxdSG zNs9MniZ)pMT#pWjyWAB1rzfTsq!N3vg9;j$y}&6 z0{79;(XpmiF*0XrUkb$*V)HU(IfCapke{UV6}a+ffl@vfn(iv0)8lms!?+_0_dsR$ zo%WR~k#x=S`l!;zP(mQWl$ryj&3V+P?EJdJhBW>#(&0!`&QQboChVW3%5T1j&v>q# zTJq;ZSTaj7mR>$p-yKul{TSd)d4F_l6NYgC_zU2k3GfSWFAOMt`O23-XMfw3NmEsC z2-o|PIbOcGCVndITiw^Y*gd)t&XC}EQ>nGBhO%DWh#UIwX8GR8Dn%pBR>tUNsbh2u zj?uZOwT-l?V{~F9ubG2BM8?(*C4S{vN@k}A+V(9`dJVX~D8ri+VB1S`vqKAAS17op z%I0CF;5(rOK335grEy)B9J*Y|_4hF5k|9@G?i8q9O=FfniDa~k-G2x(x&NQ7yjh)r zDy9xziJu=yltu0nWNqrSz)q>Cc~SH0QlV>9Us%KYZvaZ1)ZYWzaVE&_{2^lq;mo-7V_lE;GoW!wB6He589(c4uA*^LW$zI2 zTRE1v#u)Pam!o6#CYCthI{4h^*x!PqV=w=mA@6pLj(rICDR6frT}=15$8`?}y65rm zWZko(A9c?_Sk*nB8lh|>_UARgyVLqibg5)eVkGkZrTkYuV&5TIDDSVcVSHO0O_|!q zQn7iRq{fJc{#L-^%2wLN77|=mD#ZD3=OB7T$#JPll@|`-n3h?7aFCM_j!j_=K!86DHUGCKAs{C*aGUkmp)zffiP)h?z@Pj7bVU%0u38@U-Il^fx;_c%!r zN;EGa_sx%=hb*?~fm@3y|CAXl_VsaJVqRUGr{sytzY+0g=*m!*H+B-?K3cR|bD-9LX^(n{&2 zaY_4R0OuXE`u@wO`XLB|S?(WBV5I7S^Z?eI1FeenzI~F}isfG2ucP>zf!cY=@I(9YOPlG-C{Z|aR=>?E+z3LnKx^&<_Pu9exUR*!e>R29dfTtkv{0OIQqZ69g z)>ce8FAthnXNIgUYh3cL8ej^h zg)V7+S;_`YfpU;f?@=_SS@uRr0k?;3w|SX%gvBghHk>xDE6s9jP}80vZy7F~q$|tf zE%+7mJ-wg@x1D9k+2PT#W8e?$h3kHJzO!d^EK7$mmD%PN#j;e|c#8054J5|Ik+v9V zYqKkhCacuNc%#HL$PPVG3+5_ZMaq1)xEXa4w_QEcWCee_4fn|rnK6+$ zLO_Xe;h#mPC^_$naPgdK9!v%0D?4d5&-BG?U1onFrMw!O_z1npr`w9LO;+(qKnI^A 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 akj5p^MJ*2rGBz=YA)rqN)LslRbpHc%03DG4 literal 0 HcmV?d00001 diff --git a/test/resource/ams/ams_page_ability_bundle/amsKitSystemTestPageA.hap b/test/resource/ams/ams_page_ability_bundle/amsKitSystemTestPageA.hap new file mode 100644 index 0000000000000000000000000000000000000000..e187026b319b382af9a6972a731c6c06d6ea145c GIT binary patch literal 173671 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%0Agrfx}nf1cpqmVB70Z6tA=UFsu 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�};VLvE{KuEik+?08KOY5|4Qpe*t4b`Azixsb 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¬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 literal 0 HcmV?d00001 diff --git a/test/resource/ams/ams_page_ability_bundle/amsSystemTestB.hap b/test/resource/ams/ams_page_ability_bundle/amsSystemTestB.hap new file mode 100644 index 0000000000000000000000000000000000000000..2dd7ef1091d561b5e5cab431781acb98457cfa5d GIT binary patch literal 102465 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

Lbf%DKep(R34&MJ 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 tiQyyLLEsZ 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 literal 0 HcmV?d00001 diff --git a/test/resource/ams/ams_page_ability_bundle/amsSystemTestErrorL.hap b/test/resource/ams/ams_page_ability_bundle/amsSystemTestErrorL.hap new file mode 100644 index 0000000000000000000000000000000000000000..37ba33e186af7a2ffa222b6e78b897fe2e4f30cc GIT binary patch literal 97540 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 _N)!)_0C=KkeSlZb+4bT{vUA-TP?l6L2M;Du33+ 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�FoL$pSSDJfi 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 AcmMzZ literal 0 HcmV?d00001 diff --git a/test/resource/ams/ams_page_ability_bundle/amsSystemTestI.hap b/test/resource/ams/ams_page_ability_bundle/amsSystemTestI.hap new file mode 100644 index 0000000000000000000000000000000000000000..d898507ee67f6a361bd4db6d4ee413d5f02e8221 GIT binary patch literal 109460 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%0A=WP&qcY@wOb;vc}I2!uqTb6cl6$ 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 z

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 literal 0 HcmV?d00001 diff --git a/test/resource/ams/ams_page_ability_bundle/amsSystemTestM.hap b/test/resource/ams/ams_page_ability_bundle/amsSystemTestM.hap new file mode 100644 index 0000000000000000000000000000000000000000..bc93a5f8848dc22410eb9b83c0e700f4566b45de GIT binary patch literal 103859 zcmZ^KWmFUH`#vz5(VZg&M5RM&qzFo@AdM&?T~cGCkq!fu7+|21iV9L2ASpTo0m+RV zz0qU&`+VR0-~FE#_sjcS=en-vIrlmD^*G!BFbdGIva-_A(aGrlSN`AOpkt)-3lH-T z3b^txIy{UzN=Fy#)EU;V23!EFff#E1e6%*7U*7yH<0B$tlwJ)4gM?*ZKhbc469rg>^fxl_h=wPStDBg%4%lx(}dHiM#WvR zFIqZk2a5C!=C6%3cyT*hsB3V%L~zpP4;9NuZ3;r|^R}Bk?b3I`N`UvC6HsQK{cKtn}t@T8QAif7@*BbDiI;2?i z#Lhvmz1K#a4OynP3Y_W}!CV5(U)uAzx|}b6e-@|Z_owry>>sy7kV_hpzt89ybEC$> zb@u7aEI+Q^A)h3Prtt59FnWg@EUc|s{Q42}baX=iIy#5{uUJC=$rciH&o?yMIUzdc zLFlaq(J{7H60byu?o;cXPsuIF*4fwJ)?q?99B0KnMQPF?}8Ac6^ zL*;WgbR@_^PFj_7K&HL)-Xb$5h8s2&lz*Thc#qXm{`y>iWS0@^GES8G>fv&SM=wOMFx^AWD?Q$vbA~*{{^h&XdzE{aM-YLMKfczrKWdiSDiN24 zwtm~eFgrB`%UOfkL|0CRA1v8mFrhpwwvkhP2hT4zNwa4=wNrG`%Dz-0bLQE)huf|j zR3x!>iLG$Pe*12Ax{~-U^1;4b4D(97W)!8X=u6uU)GR=vP?x2%Fxg}iEBR&%R2pNP zh0O!Y@3|*Ge!~LGSbo$r+^=`1W6Wy!s9$esVR#C|@6j{y^@!gIim#J5BI}73eH~)! z#-JiRW@7n=#OpiF>`S7aM3DVcIFjuSGppXM4i1%jSbLjw-B}hpQ0Rr9Dkx*e%HC9l zSN5WG+c#jA6XMCX6Lk>VLj!~i1r+lfQ>k|Y-}k!&I~39N;B|0c!YiC%0`$PJ7kz$N z3QafjiQ^3=7~vv)WWf|gO*u&O*pw{wg%^++n0)aL5CP{paFq=PTfds}8CX;SD>Z zUDm`IvSLEdiv2{haAX(NaVE=sEnzNnf_mO&eV(mM*36to%ixa+mR8$?+Qm8-#yoC*6~@&r84ZACC9M=2OH;sGvZHGw zq^@58;#OC6J$02KEJHibnmE}RK>h0Z{d#Xpn^7t@hvWcuRW9jsZ{V#%3fV^58o?5| zr_4T+^N_K}sQ@Ed&)>DEmvsPatXbQc>}E~~tHCdb$)jc2K@Fy(B+(%?uW!<&VO+9X z0qLyC4{RCQ>a8(juNY~Jndpy92k+=yBGkgl`eGGc{FQ6wszEex)g*o9s+nxKk{X^_ zOwKuZN;U+3OM9mD@`2l{ac;N)5ft8WLhnYE<|T zK)SxyVLQU$mxf89gNvzv>qr_y3N+37%WODSzH((iK?2;Q6QYQU0do zHfUOWH8w`lPBuPuBx8U3z6Oo!w0EndNm*I1Fk)}tY8%Ed)WT)?rsTjVb=6kevt}#9 z&Y!tg{JH6te)P{}R*7hl>$hFX4mNSGb&N!buz6M~$)v1$`N z=q%oZ61|G?PPK~ha0+l_1}kdTES$;W{GzC4L0WQMSJE2vUT)7zE$yjui1fPNRfT3S zxx)M$T!smb8fl0BQXnWNyfNmzQ0f&Tdt4#M=H+HA3eVG9y4C;oQz=#5jSZdO!b{{2 zk*EC>=rLP9ea+U*`+9_c7PmcA*<)-@twcsXN&_$2ZGTPe6IPM}nbUM4N~vyp@-eXJ z(ipyULse-qf@!EF%;SMP`C$qkO zQ-MaYHJ zUz*lX;mopM@-a)5)`v9BywN|iZ=fvx{9Oiy9%${bD=$?8Hu&`GuoICltbDMBPD|>K zbx%#2#+fqg78nj8{}^)HQvM!2W0I#`BtkA{+K)q&IoLuxuCLjZTi&v}EW0(E$GRve zP?(fDUP)z0pdN8#TuCfhn?ICISUOf<7&2{0IdCQMB|wi9CO~r2N+nT^6WTCNPsK=J zqE-3~+X5}N6sBKjN)tKD;(IHoGM;)C)OpHtwR-jj@kXnCPKO!s@ud7BRbeY2=30)9 z?&1b}cm579W;8<&h&M)99xkSem>OMMxNuSdD{rcg+ayM2|6N@}>v`eaAVr4FP&lTt z-M$J-G2gsI%^tr>=5C7PbOE$1MNkbT0Mv`@|2-%Tnx2C6WW%L2zv7|gQ95Jz4QqTK z0|SBTn(r4_rcgZ2)_4u`b?SOz#0gywxbqITG!a~&83~M{>9PkuH0iS2$_2_E3$v79 z>tDuO^3=e%SALy_Hof~g94*m|tBKruga72lXzyH(4AQczIZzV|PZhCci>a)Rh*wK} zB0YF|-Jy~WT16Eyn=l#>Pg3$c6PtLXEqh*Bz#8%&x>bbs1=PHuSPCD9pc2E1{9}F@ zyP8O`0zs+WU+r`UamlP)%uV7-*_tBpTmY4iBg@yBe?P#Ki4ypk@7yZucLW+fPerNY z`?c31K+ILcNCQ!VE_0Z;e0Hm7yfOgn{Ns)&0wdsc_8Oj4G`y?=G*r691sg?v75lkt4eWZEs;VAAv09I~ z2tfH`ibP!}Ex5oxkuxHMk#|w?Y5>Ft608x?KeQIX06_dg+P+dhdX}oFjyGlQ89^55 z25fKu!UHgFzESNefT9POUqDDns(4#*|7($WegJI*32+}>z6~S`0%n30vYkZ;a?E!! zH1{50f`JvM?Gimdkw4vkF2hCjR@mMp1G|b-Y4Rm0TO zICVTHbJ&a>m$=A3g1j8Ji0hOW*O{MBVQPJBalfa?zh0!cDB&WYZA&RT`+xAb;&Wf3 zfQCh>2!G6T-l%vj0L}+P0xmczWNV7XzhP`*S*8Qbxcpph0vg`DT&G)>TBI2fqIfmr z0frywq3Ohxtrj8295#gX6xAz8EdYA_Ku*f7?jCWj zF`+<-cfN<3cmZZF6q2UaqJ4)8=Z~oeE_Ad?=xE|qfMjEUw;yKEb1fpA+3N>VQIrs+ zdyQJBeh5#cJ;1yJh$QqO%S8zw=KUvEvIErcBp}%U0IrhB&Q`-qFdHM0ZKCbT7bd0t z*S}1p{lRmIX?1)(kjx2~5g*RSnw&!tv#jIP@E*)wLr7EewFpB%ksqcK2zin!m!&}- zL+*$WGyvWK76p;qNf_j3E(fYKbMwF8}MfC#sj5+Nl}A4&e6p z0RU9vUj}gl;69in;6lg;iTz&Wyy$<9p*~M7>ypi$(ZJU}%cuTAM%J%IumM2#Ffb8U z$}5TA0hl)LCqGx4UmoK`2v*EJzmYICyf-laj^<%eYPx8EDi!8~ z*#VLj0cbzW23%uD5&#}Rsskm4klmvHU9D!rE7@(=eRjpJ4kNua@tzmJ`Z9h0p79%t z*IwfKsWaV+O`{Xw)k%SQYcK5d8MWRWV4!_`vr z94&$UR>A4xPc~kc{Mxng0o|cC)O^XTGF_8l##MzcSWOWGSbp_PWV7xy!nrz5xoZrl z!}*sQ%^p{tGcH%8iipMFy9t*9_(F%+zhcSbSO?-T!uGHEn)l;Tu@EJe(s)7Nw6 z9O4H?+Cd;a!Hj{g7_KX%id7D(+x!sZaEstWcg!I zoart?R?w_umi|3G7%KBVj3J-JY7o#L9P0C0+xZZSQ=^Jv5Lt~ss8p6U0~SiT>^KYc zuCZN?)LVSWCN6)^M!;&>2qhh}pUco~wp?dQlfXCk8No|)P5l9s$}hD2LI5{2ri z(Vd$z<%R)`yVTiitiIY~olSwinjp3@nym`w9x3w?>n}f5JU;7q;M4DKN>PF>rco0E z()qe?PNK|UCnV41jj~5-UaA=v9mNJ<6orhB1ImuFwjd@7?S=CQJalco=sf%r->-KB zs}$&0efsw=-UTP66%wBEg;t+*>Il{3#9BfLk?$m`nDYe`hJjgUEUz@wi&kuY_#%E zXF5TtWLBp`a?VaGfEaGq@(-r-!n<{wr8-n#i4pLXmZArvr4r-PiE;1n*e59XvVwEkcD)y(Bp2U>JOZ5M=%ap1i$n{gA) z&jjHet>AWJQa7dhHLf-WgXl&GhHxza^h=2W;qpl&5B_GU}ZqVQ1XD**1Q(jVVk+V7Bah#@2SSP%cC z+8Y8q-4U>+-SzF!-hFF93Z#Nk9C|fM;JPs^2{G=eO_Rr}Ch8*YR(}KD6<7tvUv}&X z2b@2-R06({3iqNrhZgmPr*{**YL#g9>CzO2(IR0Yi%5`524C_`QaHnyz2KKN`T_2? zQ7lP$9Ng6Lbl7qdmU?nseXEn@v}7vsVbR*$UOOa zqXyDFPVdK+ea`Px&=g?BLyXNVoryg^xgxmJ#jZ;$x>|Vhl`byn*d%_$l8IO~9d~K- z$*QW#!qIuqxHmt;v#^8{`7v~@l7jwqk}d<`!LX~NcMb#bZf`BrZ=YkQmyJp6!kE1z ze(y3Hhg2Q6jD8Q>`&Yc&zQ=&u3xK&-AOA5i5{=CSv=R zDpT|H>T$Ly4Dz*L7^OUx*dszzd3g0@v&eoKGlf>t*9gBRm`W9@wXkCsPBG*Rls^1v zhCwKB4p8@*a_ytK_&lpAlbnpSh-@YFwF{|T>baCNnN4w=^&!raj#!!j*YAgf|FNw= zzc!_9>v*l9An$0~8bqqQWfWB1_UX=KfJr2RV^7=^J99W=3T8?6leipixCu&_t?fCX zwjQ4B;}WXjDaPb018CNx4>DtQfvGef<8{Cj7AMLB4g8QW5@y!Xr(6aTuQ7({+^&sr zgQLsLsXgP~0>2*|(*zaNs(fo9OTg9WrkY`Js3|xJTA_qHl_=c-E7r)RE9~sSJ(1MZ z1Mb?bI1_3cr_f1#FQ=)L&2G+bwPJ(l$3__>tnucV<5z}-!>zm5VBYLR^s6~pgl*Po zQ@z5r^P-8=M~^o&b%^lsi98!jH|zXmtmH1!Mbxo0BH%ACsgrKd3Vl-oy*N&dR?Q>c zkQwiktmcFo=>HpBRo=_0%3|s$WDt*&RALx`;NO`3#zA%GWiB{Jk+)V;b{H2 z_f}?{*E`i%`)Qw|Db(&xKhfl9zPf8@MyWXK`3!?l?JI8+nv>qNLK`SI<$zcqG;<`3 ztXk@F^#C6Cb> z{~Kykpr)*=EiEFe3hMCkt_Y$w|GKaG7c@OZ-C-Q;0|h>Iti3nab5#xWP?ra5p5&?; z*PEz3&Ow*_QU3ZGVk94`PXT2318A9!$r$6!a5SV5LlQp=2jx|u+xiHGXuFDVv?(l< zF=67_v=u#Z3e-Q6IEJ#i2Hv8hd`A@OArg^fsA18+XmTPO<>2Fw9?t2$!~lWwP{HH4 zHnA1r?1QR>s^9-O4`XCLfz%+NwIfnX72Bam2UloGLz%5fm41~B@xmaAA>s2U&Oa_{ zUBW_zr={nM;%j#=e9ex86=dhcH$7|b;U1vA9H=#NWH=ozypB>{q0><@GNtL~~PqQ!2;l9U&3sGUkhp zQqNR_eThlbJSPVwv6mlJt)E zAMokr*Y-x-#E^N$Na~Ci!=AO!N!z<>9PGkfFbZh~5hO(GhT?);xqFI_ao$K=5x3l7 z))}rBLThLZt*2$cqZ3=V zrM8x(Tb-&+_Vd1wofJxJW}mjnl9e{!N%mPaVy97HFOzN;u77R2e_qj5%9O@N9I%pR zg=Qa&ydgU>oX<4y40VdKp1yxp3w5CJW>l0O7%=Rh^Rs`PsL~VLq&+HNb=Bm?SW6O3 zoF_xa?u$K~G5OnwuOqmVgJUwg8pnD%@7zK?36wsKqu<0Td|Dym<;DVb#1z6oJ_KG2 zDqJU*_`|;?yvT;!Ch5~7mS&Nx$;BA{)cH8Bn~_{GXtz=hlwdrUII9qbAFrz(cc`a`ugLp!m< z0|&UUMZ#ScvAIVt(_jH*Ap2r$ku_No{J{h)#+w3l=7CDGF()^`6dmYH=6GE=o8D^5fVGse0wc zba`}jGZ5yPI?e2mEOxvnWLis8mzrJ;_mZVr0%1U6pJy>zD7Q#7Io>`Jl4Y8>y1qi3 z5Zs;b#9Gp}R!*c<5ZJk5J0Ci2AIB` z>-AFU@MoSQtK@851PbjXZO_b@bNE0PcwCYy+bxI$$H|{saK1oeixLsJi5idL-R~s@M`##kBa^WFOh31 zyWs;ZzmV2_Mw7jJME(FUBXNEMJo@Vlk562C?NQ8%d1f98{5eu)g^}M+)ne z^aGxew|YtN2#O{>?BZV+SF{dSUqCJc;XGq!60rM8_+j1=?qB@(?rvscToOQ?lKkRD zfC5QW(TB3|_2%DZaTC}&j3Gjf0Ypc6z_zJst>wu?Rx|mG7Wny(1DDdZOnginc<5?h zl+x2s6JZlx3{U(6)0JX=$ARw`G4)POrLJZ5{eoMa_9t>2`Cb_a=b-$#Q%k$hON_Yo z84<%bosMRCOhi7Zeh<;RwuY)RJqVXM(ACLIRIsM_rhw}#JkZnqkR8G19|JzT zf4kN&n4KdiTTHgQcZ^88{IpI?Wk2q=ANj_lkC9q|@WEM%?~|{^c#g1etCr>~rm(9) zv{)7rr9b=GdxHU*?I6#=+0y6H_qzjYss%ogq3?Zj=yUUnb4{a z{Zt!Nj}(rq0f&1%PG8V7>ZgnUIqY?L&VN%=Lm87@BzcLh|31mEIQ*8kq=R%DjOL~? zqu9X!J-nr$e__`O3F$m;YX`p=7)Hm8>uPR4KF>BI#a$MjDVGRDcui3K)X+L<$x9{A zX%{!a!U{x`l0P^ppX<=uu^l^O>5o{ypfqYFPi?jkfoGN;eE-K!SY=@XH%BBIiM%LK z6eLSt(xdPzAqpHl!Uumnn_mrh^pisJ!&8Zm-p+#$)W-Trd?c)rGs0mUtFOhoHy^vY zPDD3YA5sPf#n(vlmwO!oovboo3$iob7fkz4j((ifb3wZuYC$OGFz;N~luPC9CVFMY1*EFY`Z$Cw`}J!RjJZ$*%BI zWa9Tf3ezxA*27ruoTKF=%vqKKTuD#VT$f2@%5b~2!olsJau4I znmg`CF7a2JG^(wS+;tthTJnf>?@7MP4;v&-b)Tghz;X9bmAwrbjaG&u{Kv69*9Fe9 z^KaA`Sv!E{s5jJT&oA*~{X9jQXXHf#4Ash6ck>V;=DG+{oH#N?z@+Ijn} zwd@4vb<(^_uNTKKKbDlN#QSP&PdBnAs3MM`hI#bP3E!k1= zP9t|7zgD9Cw}BjO6iqRHi_fE&RHgK&ZXON!u6!%rMOpMGwhJAjrI*RPtdAOhRB_?x zDF;vaDtV{5F=)~L$IwBXcUsrqbR*?qfE?=vNdELdu^IC5}V=KOSfpCG3H`b zsSl3Nzvdemg>jo5A-!(!l0C=426u9>--Q^u6kMLdY{mP?#lxg6HBh0UY*U%48p$>| z1!R)~dNpynSaG4vUd+rC!I(!aJw+lyqXtgi+vj*tFJ+|CxH7tYU|r!QKl_DzRJls< z-ooQF<2=C`wAHttLoA@$hSPWLQg+!V32Z$#EUI;#!@$PC(`!9zxlM~u!f4R_F5bSM2 zLpCCoAIgHKk>AR#ajgYlXnLnG8ubkKzhYn9?7Wr4By&sucQ0=3&lx8$7Qe1;BfxJx z(OHg9H;Gwo*D^}6AA%94K6)^HmlxdGp?3|c;Qr*4y6x>K74!CoXiWo8LlWb@iLj?xHBwKl2)0A7ELfw|^ngc9oflXUZ)qW|WI>v1SgmL7u=hw7sL6L8 zV41$j?ksQIB`cXp_l)^HR$f53&&5XcJ@9(}kg-5h{ND=@<6MqPkwK8NS)S(=%deIW z*E}4?$;eYB`NHrhL#@jWcR4c$(i500HiWD7O>;jek&7AD2Yz`==B5Rkrk@??cKo$C z9x$`SSa{IB=&iBentOPePWxhseMDxv+e&DAB72#vUCssN)ccP$xR`FT?_5=vBq`nz zO}}N@9{eQW%3Targ$lmH`$8=m_LN&I{V(zC|t`LWyx}HtyucO!b1U} zh)hK2^_TyU+6wQv_YbS%AH++1e11ocZYmqv%tqnis{!Uug2xbf{0#S7#IJHa6fYI2 zs{l!42=Ho-AFG9o)(Ui~OX)BP{WN)M%!`hzH*r43!#S9~hUPw;%Icf`#xZa93h3vI zV|;b>`yHP9gC7axWjvkbT6m=x?3T!^*p?bXkGJTfwsJbI_(9PG*L8!-=j zM1TPvkAnx&c*fGTnelDYN`NDVdAxsdJv~f1Z=o|UT!yQcYuty!hTXZ8BY8!&I4@_e z8rhR-y3DII{`4Ktu}dmrdx|5EBRX@+rQyZD3s)Lk?xhi!<0W#^`UFOmyE6H{fWuaV z-c-Oh=7h5tNPp2qD=GZuJ02Ky#d}c@=BP>MK%aC1QqNG(j3I!o|Du3WuQn4C)5X5+ z+vU7VpZ9;rBRPSr7P-7%SIjo#jDYbIBQtJL;g|p$p9qI}x7d|!7>E!4uVpGHL||G& zHf-aEn00EvHaO~TUgF^Qm12OhC%>Zu>kFaDewQylgrz%u?3fjQS!t)OlyGq0zRoH& zz>4|7H0st~mYV07H^-m4yfSCPFSvdF-oHH!ad`IwvRhDy{gkUa;Kyx#<(0omvJCIc zPKxCdyPu|Y35w3#)8F1>H(mAgor+r^)naMk$y%vsVcjsF<1MyWQx>vtOl0 z9sIa0ldFus6gEm8Ydk5bms!K0$wP-o#$Et}HCv@|CeWW>qrW~ZR`q3rbVUS?;OWR7LNj9{KHvvv;po3|ieRTw6-z>{wL zW|FKviE?T<{7E(I81$GigNx@cj}}jd`Qz+y4l|7m0oEX%&(gp&HO4+o9w1LXj~?r5 zX;&FN>6ER!LDLtk^l=N9SfklgUSnmvSbfzqTx2c{1q919Y&1j7H*HzV@#iwE1~M4U zS&}q_aak>+NCv{btjVgV{A-eDHSXeXQ-V}q5l@o|fvK;VC(NXsb6F|_7U|81bTviJ ze8@BjWUaZHp~h-&639^_`5(AjJhjq4OvX(%&2Sn!^pS=c_gR&Bh?BwHEG9_k;U(5| zX<#!Z9~SR? zfKq{d0gs=pW2v4r`{}Ux48=po4SuGQxG;OtQbG&?>-bYBYpFASGkxeALac^dzca(F z&9$w0-ytur#`fKN$)O!6IKa;={h7EB<7V4F_;_-|X!3L0yNx>V8R5iAz}b#=6<@Ej zDDE%yyJ%OeyGv%QC;IF zmd15=rkagg57MBK25wgf`=ln_v+0juIjE<{!p;-4ae&7x%=VgZc5+ed&soQq_2yUM z8I|Cvy`$GwccwWg56-)T48Ga9`-6ysd5$lGiCvOHv?-R=E7RSDuT(*g-X7MUw$nV6V@psyJ!e19oVnVQ);D{-h{uE{9 zl)nh^=f^i%$fR=k`Y&8k?B>h7Q%g`cak z6LkL9WUc8QCPtX)wmqOVN53LfRblU@&VA!Ll{^DbP4m#BW0UpA5Au$6N#2VSfi5S) z>8(X4^BqRf7MpUftYH%8_#EOVw(gJUu1AC4@q~Xr%fq|@0~^-eM?dfA-Ib**n1%{ZBtU}3y;Yq7AT(>78_Rn*p z@TRK}(%L}@iZk~k1(i0QE*Z{9yO*5g`3v!@Y4{T?{9ikT%waGO6{Jq~^#zea5a<_8 zMo+%@5;Ws>BqbiT2d0C+r<(oO$JQ!V>O&-a)6;o}FqX$*ew!#5E*t-zqzbT%-*rD{q)U`}59T zA==jicjW59Zja=MfyfCEU+a9AVeIML>}9H`=4a>m=6%Vwr#FE3S4bGf9X#Y7JlO> zq_rdI?HA>yuC3C;1sjJl-K3Rj9kax}pb(8SnX1$Z3Ci z9)owjPTKq=$JEi1{i?AsX}0Hq{r&QJwu8oS!6|ja$cV8ejIvKT}Cc(!P1D9+%L}{QSNFW3n=M&m<==Gq^v{d6%I>wt0l2A80yN>rWoGmxI zVM!t5xqK!;?Y%V`9D2g#O##!_1EooH-(7`Lz5GR)YDhX3|$C%4+V@{4r1rWmS6++5~n8{ z7|d|xUV!9xYFu*)uXjdlQse38<>#rn-wbw#mO}PIPG`aCZXXmyH-eYuyOy_Wcj^FT zSHQ_(3$OWmq=b4fd@PB zgV#@{;lSY7wI5#Uw(LcmB<+P7pz+Zft~DxV4)D#~>K!b>AC>hwJXu&DLaQ5SJ(YwJ z6RmFhb{e>~3Z2gd&9z9jg3IATLw7mo3D-Uf0&qeMvE=^tIj<}q> za`Ye|&)62o)dLk?6f<0#IKNR@ulvzBB52}U!E2Xf0{-!DQs4Hk*$+02JLGlz>nAQ7 zM*QcV(J^Y)Whv0)NUzNsAg}8)82` zli2=ncXzw#SSsdsimGBLX=8CpPS`_?{~H9iUd^FxJV9OD{s&Id*qPq#@;lsn95e-6 z?5gWnS&U1>d3*h%Y&kZTG0p8yS$}*KVAq~}Ub|aXb}M}H!O6ONWl_^qhE*Blr545F z0OW_gBG%GMI_H{^;NF385I?ua6Ya`Y3KTm$A1QnN>@b)WXbQsrE)B(z6SnI9G#@W% ztvQkBe?19L1|z(zpPp83gd0hyg_jclmYdFYmMzS8w%Bfd3Ulv--!1tUc>D+C4sFwk zO(bzsr(op%^|<=*B;sLZQH9Dig`p_%#E{^&o`b3Vx(;scvi*Q`|SoLIAC5enzb8k#YE7xH2aQ?M!g1eTZx8Y#Zw? zd4-<%iz}km)Ny=U^Bm1_*NAzV;FZ13k7%8a_s36c?kMj(1bRfBM0A$>qAK$|J3?Pl zD?$ihwI7?XlJgz>Hxfzpa!;!6^ZzQ>Wzbv1JRmAtF-D0sxVvI;cXH!Y1yn{nd%((%!=M?)I3`q~ zSzvmsQ@nB7cL73v26NBKc^Tb3e%~Eu^OKScsM~uU`W}#2a=fJF(|vVj?pQHPp47#Mv&D!Md9SZby|zc zPGqjI*#Tb*#Bt?}-QqK3gTFb?F)U;=0d+7Q+_TJBmkP% z^j|@%rkBME!hOB@-eyw-e+m8=THb1A8A#%|_vB4@T`x|G=j_e7S7!T#@tnTHa$^I< zn(x3WVJGlk?&Db|>;5u8m+Jy!^CpwtV+**=>{ClUU8b$IxYC|P^nHl zaDFfpPrCFropOs1a*?|0&Nnb%ECsOzpVlQmrkM7i6MZf9w271NhybT<^*^gUIcRS5GEuG_v!NJn7A=t#<2{yTBNqAutGo+ zbrX;akQpV6ky)~5;_lBr+#DcGmte$?)@DZ>Y?v7+9E4~7N#t<3>6vvbEWdilPN_8i zNwAxku9M+}Uwz0NDQ8_3*AiaR7qHnXF(RVFcW54;K@`?CPXrEJO+S$&7>S?JYi9k^ zohg`J=J%(v_Vj!5;NE@lstsa)#X<`8lMj8t*`6)K>Jq_~g=SH%Y?Jm9HX)A^xJj;9 z8TsAOYI-_F6Qb8PKShWnqr4ZbbtSDUKJTIa3ASS<{GBICBlMgOBm8N97@ruo{kn=Z zs8VJyPBG#i?DA#;4=kTjjwkc`+DWgpC9_tk-W#1w$H_g-|5g4s;37pl=P{^kMo@WQ z&h@P1?;g8Xx!RRC^O@QugD9Dm^8a!lM4o%gXVE;kw_2Y-Cwy-wg`vVeaFtU9xs{=A zYh!M!zzGf2i7wC0BL#u|Ys=m;VYSj!FR$zjbb-;P5BU1rI14oVN3<}$upcLF?UvIb z#RhqNgh?56cxeaZ!WPcbW@X2iaSLHR+AMQk zfc6v1jKs|D#BkHm1SgK0Uci-q4SbR4^45D|TyEnBft#q;>&mXUAY>B0c{w4zYxP*b zldZSnxTQ%z#SgfOvidJx{DDRIv-C^mXja9Om>S|H zu-ym78jBpFxhFSYHS2E3FwF+=o~r3gY8+H;M&xFnLGZ?XUhJ!9>~1Q>D8w<{=epG` zoMQ(lqq$kA=g$N?Mi+laIg|D#;h=Lxr~{RLX0~q~xGk@B+f_G{{8L82X3&&L4NBXS zWZQT3Us_47E(%QYR~q(WCY{k=7RF_d2@^zjBwfL;6ArxQE_R^5a8?Ox#@xBF-D7en zf!5_`@8u#8c6FBG^tlkEaU)4cm7a$g2TtxTJ=DYcG_zQ~QSq`LU^<}MI44HcpHEXr zv85|3BC`)>p4ju>zM{(KRh`Ta+_*+!f4C%h+GZ5UZbI{>QfN+%`?s%)!}_W#v$5ts zt*s7&gycQU7mvW(ATku|3dXODTDQpo&iG%2vxfadcdeV83B(l!XuQ=rcU-Wl+_hfV;x#0wStXimx414fX_j z*zej~ta)(NV(AmkO_sA=Jq4<`pFhn+ov^yNuf~OY;hnf4(^z&R(&{uvaXhq`LSit} zX1hX#c<5v{A7UA0va0L0z{}7<;?>Lp#{uet%>u&Wq+7LLmnBO4;G1H)GfNc*+-#N+ zfs>2EhrY^qq)IdpCVet|dL)|B&yc*^+>3n$`MV?WZR=Bo6Fxv{5k}Zgw?00LZ%Cg+ zht_cV9ke^d>tE(T@5PADzZAIAm&EIO!Fqd%`EVsYtq(h@GwDiza2lH{KrW`ze)CW+ zL#kFpw-%TdnicS%FBL?sLcW-wUGCDqz9L9XdMYo8^vO6iS@jl3qVOarHxJB~{$Gj* zp4ESL)6>VGaH9m$!SnUhN0@wx@Q2A;J0rdRJANr<^reKL?Fh%}+!^yDzma&ibXGSlZ zqvq81rZ>OYnO4xh_^9}E?benux}a5Q$YY8k-D;eMrnI~{A?x{U&P#XuWld-bqN>WX z-saMQ|QSwzlBc`o%obY(CpQ-b1>8T;bNN@%5bgc`7z*$bBvjU1H1N;<1D=cBK z3;9JE8)hT8hxvzv_PQ%c(qR9=5A_+R4op`K+Id%CN{v0P`$*i8Kmbnx&N}dB*0JlZ z`H$oa7&_Cr-m*T-(&FiI!MjQzETRlRTw;UUkF%;X(2N?-4 zcJL+|dg49Jmc)t!q<^{Cr_HAs@3863;*-SJzH=kuOkJ}n`lT9wiwki%i6U^#41)DL zZ*H52lYcJeFmwj`NzhyyPqrz6fz)6$76ch=F6JZ?xmfsJx7|uos!_&~s^itF> zwn|qfLq>HX3M*2?b5}k06(U!^iMVR6-Xv%VW{F*E*XeDA4g4F-Yb+Y zD!qJl`tW|gIdH+PiaIoFlGdNNt7Nb6I$laEYF%B3g|5m0fCMmxhwg&sx=p zjR&)~&qk%YM79}kQP!MdEz*`se-~V#yZy~cWhG$ie&PLyjS5=&#O*LId#uDXLuZX4 zxoO{G+wScjn(2u`nlWcQkAK4Xo!Hoz52myp0@#tMwuB?5KsZwxLwN5Yk7o6Ct6*uAWGk7@ zBcu)CM>d24TFv}zwHYz1yZ1E`F(4xmM#2+O~en43Ngb%R2pq3nkiK zY2iw2I61>(GPhO9h)tlzD)e6+B)vj@e`gt2nXk zBn5TfeNb;V96$cp=^%BGZsq;UbLu!Pts1zz6M=FpuG)W+7a@$`lh+jYI2f6V*q;o? z(Bf0HhxBFd{l^qF*hDN1@MG%gVJ^_rt%_|fxrp9m;4N#P_aQopyea-X@NU$kgYWT5 z0xtclKw&@s$NfFXec+@b%av0&^oPM2d+Dq8*{5fXH4LpvoJLEWK_Eq(+No&V@YnXc zle-ZFtDNPrtaYGJQ{Di8*i%{j8h(0B!M>?P2QEkLm_02uEp<`{sils|o)u=@{n*_Q0XIvz6|tn^a@oCZa- z1cg&tlq6mx&u}>9Ml2x&0Ol=onhSRFA6=OfB7@>C1b75Jp8gSlrm=;xGY0;5kzmSG z`-bRK?~0Zg<7kQ#f2vlts*FKhi1|?-rg74e4VgDt9z}*cScRxpnpUE!3~V{$A=!Ob zOjLkgCI}8$6@B=TY6t_a_Pl~UZL#2`vs7!glOfq;q;BE(Kk{_7675wd7A;s01yJgi z8re!rl4CC|go50oGy0BSU`@W}%1=j}+3i+kSekSmgX2ATOFQSRM~eQCu0NI&1sSjr zh#7~n@lQ`(6N@yJ@F9UkEF&|yZTHF4CnMQi|7nhoCn^6q;h~x^3n{}5g{VuWYoyaY z`xSD97>C%E@2tK>4RSM_EffC-=Z&N=G(@K)EPTxhszX)0P5ieS83u=GwoH{a!JV25 z&Q)yKGh#~?+`Z>;Te+hNh$hL%D=Hm_Pg|RcN!4)Ife!L9Azh60BfZN!dG@P$8S@7f zbK|ca^(C;opPqEp3X8=6&}ses4b+%6dg#jkMwlPa{nX-t(z2VtP#4=ZdSp({tavl0Hp`is z*G5DVP9T{TwT>zG?$NcyZ|9<5VxJl9l9wBlV^8>pHIh(b)4KR6WkuR&!&;+iv!o;G zO>79IT4PB|&)-rGUA})-(UJ&3w6Lgd&%^TZDWvenOPx6FKOxGO${)hx$agIz!6~#@ z`iiC8=X}=OcFe4jsT4-iN?)>Z(u}7VO~ty{j|7Fp?h=)rHus+@Tv%fVJ3rB{%+cQo zsv7*nDbEF$&o_(t9WEveMg^5A<|)4o;wE)B6(jokVteT zk{civ7RJq&%ENuzZ4sQAZiNoFBnm;#TvX}=6tOswi6$b+GAMoR^3}~yEwyOo z#?c&zF;p6e;dq9rmwyE^uw#oeeoru5NRBuJz zcle0p<;LIJ9&!2xBGug68Tc+;y?D@MV!8k5S)NzX$Xyk(zBD3tMZH|#o~M`y$S<}R zkvP~6yrc#xu(C42J}m3oR3ebt)* z?-WNw1bUB_d-FtNSy4U@X!z_lm%ptC>wZiY529H0#PzzCP9n3o-R_vDlyVKpzSAno z`|_|#1y{&nCG1*&W5`_bj<4j+to(0CUW%*U zdO}1D`&RiG%q?HBkXY!pKlc#>`=`-!`W7$S+@%sh>31qCBpm`CQ({5K%TsB(ur$NT zB97+^B|kgDMN9M0$eHY{v*~Gt(-+PLE6KxoyHB>3{ch4k7d{gL;50<9tI8sG+G;L# z?^0cR#9xh>{os&1eSXK*%wIx$B0nS{*0PL&ML4~3-tfj%yoP~P|3nOfq4=6iW9bD7 zy=1}p-6k2aTInw;O!Pm0d7jb0sx*80!=wcVAo;0tioWNM(xC32}d**p$A%AhJ+(vG=gVmtdBeNl%G3KqIK@M9SMk(q^;l!@gE@vXk=!F(aEyvU9mooc`kH zQVCyxEYBd3v@LpFhllKS5}2GlWj5k{Oe}P9?q(zIsSmUr@Sk^OqUUwV>uwj7sJurd zunByHF_32XE7VkYK)+hEdlKeG_LIKMF-J^ImKCQMc=Y2G!;4-rzni61@B{%#nW4lz zJ+M-%+Q?+?*g;MDhWd)QNB3^S67iCA*pJ9_jhHNwZrqAxNGhYOSIb_7d;@9;*P7_T zw_9Ca8AFWxB^`-anOucdm~PDMyavIQrzMG}^XIqIGd|1KokKLQ8rirlAn@Jc-G_0l z^@yHvUdiY;lh|8oBGy>uQN3OzrqUTh z^Hj*HL)C}fE5uTGzf~V0@l`cb@_1$0dcMP#&v59F^0tx;q$e}1B^uH1U#bam!0k*a zpSdhV_NsHah^2-pYJg~|xs+j$#A@7Y&PCoOM(Z+tiEA z!=s~IwUB2i_uNCd&!{1_Ii%K@&=Bri)bjZTXHf23p(OuUyb20cJ`or?Cbcc1m>r|6 zH{X*capELDcDFkUU-Xa3{SU`5SpIo~GvWev!Q;PhZX?khDN}roNLL>JmazG#l=1R6 zsIb^!OUC{U2%KD(wWBF{+tvFcB~O5HtsvL3G~?)H0uD%!n0_7LEmKM@QFgnjq2LZCEP>BFxDkT6J1L_f z@uy8nmJOL4fX)>wT~;$WtJc)dKhh>D*o19u^V!mEob(xgZKxZLl11cm8yB=0;pQEJ z&{Po#g)pSwb0I#@sMM$E;ns%VVa@`W4ykW0GZy;xHp2yA z*QrZX^>Cm2TO9ysocOvG-~F)i)|wJ$YG_bW9A_Z3?M3K&iXPXXIg@mBp|!*|A;qtx zhqM9nmw@}M*{nMFC}FNW%h}dlo>Kl+*E|1E6q7pFU+xk-s_RbiAYalaQMui#0_`H8 ztzZ*Sb5&hn!2zayVV3w>)DkA%(U$lM~kVZLyBW6Bc5Q)u-(Dr(U!~f;; zgpW;XksE*XK+J?1U&)I$bXN>4R9>UN^eKv*!T1Rf zw(MDvn^(BJW{ybS#7T~LyC{9$9HtnhVhV%*lmlZDT>r+C3r!J$FTP!qmPJ20erUOh zXwy5p`Bd`BQf(dElR))9Ax>n0F1S3>r$+p_7sKIX`T`6AXKe`Xr#W6?Qhc@w8xpoc zolind2@6=ueG9g2n7wF;lOlNCiS=iT3g&`2zo^_pOYLm|zwaEisLMEbEqeXYjZ5mI z(?Vsoc~bVh21D+@%A$4*9YFopbNI&bn6@jdk_cYqDE+R{d4wJv^u77hlv9?$G=ylR zO*S zkrk&4y-FU}w6Q1MXOp1IJhqhYil-6DzbiK(mn)HHnmIjpDxCO8ms5R{R`vGc;1Rww z&{_}!Z|&f$16pfJKQwkEiBPienc#vNg~M{-^Gc9Pk;hB5$`9V9XxLFM#f>z z5i;FN;7*@=JynHUb9joyOtvbV0<%RiI5&EX(V$p}%IFOZLXVFC7fSLRp;d8!j$i^& zE`5(Z^z<@dgdwb`=uuSiF5ZvqGhG<|npN>6EDz@&bS59`8X*%>^dxoRHq4Eq5O@;- zyy7!39lSa+O}@E59^|3ah_1AOeKGbpj-9V&am&L7BnGPovQ-O^f6{x z)j*~a)dUxmAXszN1e@DoEz(p8r$`d^GnyzX*~jdhoO&kJdsMOy$k{T}5fE=Gncn2K zRSey*yrqVd4T`5|Q>)HR85|CklytROD;$hbyJ30xGu`<;Ct`U*>I1?FmFBSa-w@D{ z#(ns;fw4Y%3};LKosxH4vb167!K+^9g$g;pONJ@oosr@ILsZBxAI)Cc{Fzg3<9k0= z@(~>1P%CbvsW?7Vg-}bbq^XF**TPUGh^s0%cTtB}+TX7#&{kHKQeA@a%rR88l8*~^ z=H`{eZmozn%$@i+vripe*r6f1!SP@i5W#4uSNb*36=WpVz{7A|481h( zRIJhjv2i1uAM+R>L=_OG7j%R16sCAQ_XKs(CaFK#racux*~b+y8Rp}Eeg zUvY{<<29rDdLxTYd1~tg=Eu|L0(@qaf~%9xTN18hSAh4d&F0hI3sFYBFzt)Y8KTw? zCKT_w=p)_Em*JPmaS?8yi+Mx(TQ8B~K#7d(CCgH_Vlh*M#f(#Co=P&BMBy+GZ;zY2 zVc+nE$>t$3V`d|fvP97k^^PP_{UU)&PqO&Fb4V%3x9py~i;pfo?Z%Y#{G+^mN9U;3}NL?&}0hJrsa{L`g>r2oTT(Z##o9D+urrX{vJhos7=8I3<)*% z*Z6hLi%8gzzYV5W2n2KOb2y2#YKKS?2O-kDV0C0!aoXKOwhl_WRh>>*_QK1;-3 z*DW7|q4(QJPR6x}TX;xfr}6|n3QXN+3!B&qbdW}N-W6Z%tTE~_I})m< zENv=1CJ9t{U+jMWSd=U6-TEUwQDi9LLPUQ3BX2sH*HlCslq^4LkJ*q8*f2jTpE+6F z;Jk`nk|wwD2vzb_^c~Jc8geN_us4OZbTpV3&0x4K{YEHeUggB(QQ@db_VfS?(xR!( zbg5k>QAwK)ptp4UO5lv%F$^-gY0cM7Ne(DPVJ2&Fp(I|BtHtnZ&Kg7WCrex#PxgU`1of_e;#g&m7Aa^wztY| z<3TG(KTpE|vo~DHrH?jO4|j`7f+J0gUm`AF1=BANU!b1OCmDZ774ut?>wB!}mcYqJ zLhDtYtGAi%(}>H@QR|i5=`%_B^?CuZl>M#rgy1w~g*m(rhe;Xs0jiUnX^b>QL0_0e z!{{9U^UeNK@VzLOe8LDzZh{`q3m z+i_PS=()qi9L5+rIDYgSFj9&IePwYzqq{^#()g5Zjo=vB~&pJxC4JcWLOQfkn3 zr79Cdu2`2Nu1MMc)7a&{4M(DfoZgrUKO@|Z!PIAspDW$FDUlqaq;6Uq6&pJ^1&!tr z;-#Z72c-ub<*+BCtmSyV+F}vpC)=YwL?DYG-uH$EANUKIeQPTb{{}~rRQ;0OZ4=oF{t5b%{-vBJ~95UiaCPHdm6(`XjMsk$MAF|QN zmir6!V%3Z(8=Rso6pc}y$r7R&d*R0VV0?M52~Vn13(vBcx~eIe$sfz0s&1n$-YbYo ziIbDGCNv))5dv<0)GJ-NN%JTUD``LMVOA2el)fIU{BQV?xq94BsB%EnS3N}vs`3u>vWVI<`k78-k|mbFhU z$SjfR9`mBnR_L95@L5buBefqvOmDq-FQQqJZzOHhiHCnCL3$+zZX}LHLgxBBhM@kO zh4RE$qI&Z1pfjXa%cTXk4oa#*u(KFk)qm}fy-@|vh74BH zBuVbq+s5}?RIfj7KP@ldcU@)FbUmq*>q|8D1G^9D+{nJax$iv8w7tiB!3rk1QcSDxyJ@F;v-h^W;8hbb&H;Y*p- za1W1&3L04av!y|YJOt~B_x57%?t}b)L06H~-(7zc$@<8~?8P5wjnR7zxmG4>CypqN z4=0Z|VRe6Lf=sYhMF^zO_07b_RX_5zF$>)9&9!10|L4Ym&Yg?^Ic~d=A`s(sFC_3K znIbaTfj^xU?BsMSWs?HtmJ4!p3#o@lh?x@nk^E^d#?>DGYri^v(g!s@R43XMPgHqG zjFSzo{!Da6dY)(Oh{(xWE-J|2&r56(XmWHwlMdx!{>HrJCKa=@xUj@jACaE8;iKyd zfQqq7pxzYL1JUbIh@AJ-a^{JnJRLA{n@x*e`8aWjDvMyLuF#xGEd3ViQxI-5A-y4W z?U>4nakHCsClTWbH&9#&`WNg?K7xU$#UG6#N=@P$PVlo_fsBYNa`Enlxtfd!dY>qW z*#@;2Ii;jJD{4Mki&npg1nO@uZr&o%XU7fl`O(FP``vH&aW>PG z7N3n&-emhOGXNdw8cU{*hy{5sIh=MzSbaQ-zIvkJ5CzXX933X{T#vmF6x`Y+Wcixy z+-a_SR~%x`Cvh)^$~Slo5$VYy-o1yE0Zr^r2+j7lQ+Ys7C5KE5r86QZFW%SR{8zPU zy7KW$#mcw(Nb<8gjnOL_wzqzPjoJ`m+|8DoH zw9VL1PF}FeQ89ACUsYp_nMgauLlKg!Tn)=}3pNaV8SqtUKV@2-oB1~=YGR7x6TYUq zRh9^!LYQXN_H?@tYc7~3**CK1_a;S^7-^zTG*#fAzs0{nnY}I7evMuoZu{&t^4Zz` zakVk&JoLuTyU-Vkq$}Rn`yQX`hGoIYg0z1s(X2Jy^F(!b0(ZrM&J)eSFRUR!0cG4{UL>j zdh+ccyat;g2rzh|p`v$^G?J|vZq}t3&+_w19xfg#I_rfhOCZ9Y;bOUm%@Maw6uaQs zdSP$PCyIXAq}usdJR;s&VQIT-!=_NNqg_#xP*z^o5B>c8q+A?xGaNZ@`nY&EPQxa! zcmIk9e4jj&(07WGDs}a*R%4!cPk6xJwlj~a9J`YJaZQCIY6)v$KB|jM>vJ1Be6p)9 zkv{DKRO@swM!v_7G&(U%zt?Bf4QSYXNno&Mv{sfu)og%0=%&J-1#uM{d)ro)+gm!tOxQx4G*(OJg^OZhuxko?oe=Y<|x3@-pR_VZe?dz;i`Ikd2_n zIzhA$21}BEVI!+Pc21CyarP&~c>W8h;fSOY_kjRMprdMPhl9@e_4=n@2rD1X4z(yc z;99p{gN4P@1$i~_==!s_+&f7Yl**&$<>AA)c(|>q^L(+=xk^6wyzY8D&yhM^s#H>f zhH+}v)E;0E>;BO<(ErlW1HwLn)nDB)$@e(H?0CjQ5@*gq=~i?i?9S1;RXyiP77JC;_Xtd=@`emSLjY59kd z;F}*qzQYNF;Z>h-|RZx~zFcrOPxt+5|-c+E0f1hAYm z0$oEZ29%%wD8tG>Uu{=^GLnhTtiD&>{G~@fBwoJ!PtAT--Mj@*qMO&fGlq#5Bw>W+|5@SYY9T z{p2CIJR#0qsSRKsxn64mykh1zw4yeZmFIR3Y>)VtYhyg36B*^KdrbYXX8f0p>mBR z5y;Q8E?4Fn7L#FEIdU`x3#EYKzx3<~LMwY2yDCaMJ=+@2JYYy%dy$p=Wq(P2ue!kF z?UujEe^U-=>iT1{N3PxZ$o8}Xd#1R(=}6Zn>C2F9P?9r0!APUilrW{?mr>CWLO97V zlwb%)YjH>=pjOg7w(kDa{xX|qdS+sb)AOJnCaUG>XXrSi)63;1n;6VB&6~-p^a}wn{%;bQ%+N?|qua4%{PvkJ5>xW67kNIcD37A9#Mf>4cbH9ktis);X$cPZtE2DHYX#W#G%TLV{h(P%D$57kxI-;8oDDvy%e zurbRQMWs~OVACkAS{W2G`~U#RU>>Iu3$H%dxr)6gQ1{C*s_;~2+~~t>4R)3a0?y*n z(gzv_dXH$0uIL+1lgI%O+kruLkb~<8I-F0iFllETz{b0S zpkSj<<|iD6F`fkpzbcM5qxM0=368r0SZ@U#hc~;T&IZSv$=}QWDP`RJS!kMC&4wrw zEU077!aPo!Y5x5wm-pLx^8(i`#ql?N_P~p-Ir6zjKh@<4_|Z&2d*XK_o3bqD7|e)C zaA6`$B_uHp4t-3Mbpn06rf!Z<1jg;mt!BRovaA7%5O^XSbkS`-@5axcCrb*|59GfN z!cR^i2NB)@wf_)9o+5yO;-S&1+(V(4K2Wkyb_f|%{V`}%yO41m31U=(eV!-M9_beQR%F*M#2$GE_LEPTe!wb34mv^d2|{-R$_A1UG!HaSLNoByoUZ9ziofZd zwn*qpLK35@9;1qM_P13ER@K}}IY^@LlSAP;nJV5K$08A<>JFW%1l*FP@KcxM4vp%l z5J|)^>=Ih&IeOvxFICDw9MwE;;V0- zEBxA`>I#jot%Fpk9yF@%6YaAWmR<55P#gB;{qGAZ7tX?*2fz@|q_(oZPMoq6^XR;L zm4EsnrC;;SEL=+}A*yaKfoJV-MR$u9vgD=G8eLbs^(0wOmetvQE?%;O5w5{O>U*Db zAAXI1PEu`6^7qzy#(7}9w!7gOFSp@&9NF;d9b{mAA%ch%+S*z;wDkv^5S%>>#+pL~ z8f*DI;T!yomL#MVPt@>AL)(zPY;+y#u_FG_?@%E8g8BYJ$(;POUa&$)Gwzn5&Q=VM z8Biz62fy8lU1RND@J*d!P>ZshC+a1zUoKdTaOW$E=Rs)duH<{$f%@eB>&A9Be25X? z6U(hYst@=6p?I7>Huz5~TBzkOrfZ+@JLftt0x$f~AFb%XW;Y&yNWXRAWvjVTALAJ@Hh&1xO5!nFt2 zUs@aPj^J47-l<3MLl8&OQ0h!;l5V9&($M$^H4zNyjTKPqjB3(u4M&!d`6o093d0%^ zLO_kPp|4_WiE{>5)d!?U+>qZr)D>QVF?NYRW6bSQ8O&@1_MGAf$R>?1kqt47iBQcR zE}8ahW7tp`3~R(J^UX)0e?}UULpowQpaoVM>S3^$m!;by8rcU>M@$BUN955MmY9h4 zG)EYazr&0#g?7JUU_z`tC{U-3Ck0<)!*F1taiYn55*jrJNJjRdDVfYjeBv7SLS|Uf zBrVM7G99RmD?>Is+4CH5j4earnb;$l5*uBFu}0}ajIk$3=nhv|g&R166U=Sc_h#5^ z5cd{hwiGl+Gg5EGM($w@{!EIu2R4!n#Kx?_7zBO8a0vZ`Ton2bxXudf-2kuYz_bG_ z%LZNr1b;&MLcd|ycsB%JX&x0`VILLRG2S)a;l9x9jBD~7pn&<%Mh+Nvpa3NfkE93a zJLM+uX79+V;ede1PY4mPg%2E_vN5?qc~n2>FEnnPkE~m0U{jDlQM`9bn}BZ^0kcVo zSMEmz4{WsJh*OIUK@Ub?1sq^O&TmpfKHz7K)BIa!V8VV>&@40@gxOhY5FPmNNRw@c zdZ+vhYP<_kaHfmBl{w9KfEb;J$zNfDGwcX6MG@XxfCdKl+4Bc>!!~A$IA(9{D`W?l z*%AH;(LXiV%Qgotio~tKC^*;T+*$)Q*aK^8{7(WnA{I||k<+km7{34IfdZg2=g>O8 ze_(hD{DpDeHP!>aVK#tPk_U?M02BJ7!YafUt<%sagj{Q#jq# z!rfy<$QFG~3M)lJJkAVd!g{By0e0gj*_Z`7-g?zWm}m4D`5OV~t^VJ%dmp%I3a?0U zYtX*f%OU=wpOlNh(N^+0Bg5kBh@Xak!?@z>$iHgDEg^rSy;JIrHERzz#MKhR?*S>3 zXN(6;%K0~vDaKd_8UcSpn##!r%8+XG9L6*5iujQ8nW8Yv_ygvD-UNBbzwHAKHxQpk z78-0-(j&^4KIAt(k2ojvb3Rj)F~dL`=QG=$MP4f^;;ts1A>F7+sK9AHQ<5?Nz!a`q z;H|snSXAJOgX}MS_%AeEF0)_wNFNGg)|zC6DuYHaKmUE9Z37_|x4-Hz0F0rz*NQJg z;REqb*&Szm026NXjmDfOMOY_wXNuBWVYmP-2dv5&H${OD_eFaJ^jRb@ z4;^=e<^}939;do!yU5^WNIVeCj`+^V{MCjN&`8d}uMuN0Dsw|eFLf09cx?;vts;>whaV|2OQ=q z>aGb;0`*bB0tnL!PBXHc(Pqg3HT-CD(FjuBf4|Z8#8>@G@h=7TY*zn=SxVhtAnXX< zDRTxIrT(7?Y7Ib&A8273QUKMZnX^FC0>KRjR38wwrSO^=rUlc(J3%?Q!h}}{{h`nv zYwk8+?x8N<4*ihNg!rxju+${q13%4I4En}cY@o#8FYq7GVY5Ln1k#%m{6b()6-W#> zpk07e&w>0x`wO&-7LXGQKpGLvH++R00WQj|!(D-!KM1VwnRSApvv% zAFzM!Ks3Gx{zQEO^Ibp%-v7G-8#n>hVKn~U2y6xx`UeA92860V1khHf&-u6fK&|M& z5f>R!3_Jm~I0GeW|3}9{!^#l2-5->1+;>VBAS&cTz9@BJJ`^}{fGETOT3LP24EY*p zP+y<}|Hm){-e%NZkT0}jVC7?=^)df^QBDqiQs&GwqMC_N8B^B;&&# zg3air&Z+zf_?4+|ukm#=f>cT#Iqn#?vPv$BHMjb4ywZAlH$g`{VrO8<7U3QF@bFy*z>)zZiZ^rr+V-ihzm6p-o<>kCq^m75n@MD*-NDC7c+H!-UnuizKhr% zWjp@7OH-v0G3jwE>c)ls%7J~Tcm3=XYev?o8G1SzMHzX0P4;T{RC?V5Y#B6)!vgo|R{)-yTU_zJndo6IWuLPCv|HQhsYjAI-}m~$*w z|+YftE=IM(2Jf!zDQeAS)E9(+Ef#wD(c4CtutG|9qLF z<_m6ml=}g;5M?As&Ce7^2l!?8sA#_9p&3Pv1>FeSxs`rD{Deo8&k0nZYyVoeCrdHt zUPtF-*FdIH4(TP!{AC|UIx0<+gw8&Tl7^{M#E=StVaT%Y!3^+kMAVhNgyAu$@;^D& zQW-z8ItAR)Y-p~(5a<>dWwDeld)eE5#3s9W7&O=_w3I`s>q|<;O7ga()j#Iru~V~h zG*p=`imbn+)M9$Hd|Qtwi(ZmZKd38af5+xa%Lt`>%#we5LCO9|BTM0`fyDK6m@`my zgqosxN2ft>uT!EueaMx=s`yC>{c%f>Gx=GTA#UX0u5#Zz{+VA~v5?JK?a@3!-_c^K zFJQXGy^JSY>goN;Sby}gxUF$QpJb^#fl&4SZvrk@XWJM{^=?=t=QItIVZckQ2o4>7 z+5~`=vFKG%&l?0!!9?1&xm?cci#Q=_@U1Fc8Fo}8yp_3iAQK5yq2CEf5PCZJRT`}q z`Fe^4W`>oLI`a>gS8HyqCaSy1vozEbqO>IHkF7jifxrKp%z3$eV3>~sSk-h;S5#_C zJ6T1biM9?Uq}rR`o=f^Uhp?A?+-fj-;Seyq(ZksLix~xEq^D|uq%;8gQy{-PL6@6{ zHH=>kV*LS2fYW`w{r3@aKX$u5IY!2wu@hEWCDC}vWk44zML@IkNi21^5Cfh{n5Gt2 zhiafq6sYp?+LeHznt&?qZD3gC__`K zBEO&Y0pR>Q*!kf>X1p*^L#+0Z&@q?;q>cDbvZX~5Rw3?rH+h*)OaLeyMYL_G1&GG+ z5hiWS2}VV)gyWB2HB`>2%A1X>Uw_eWD+A4ZG}D@!xyEm@MG*xDmag2A=$N;CVffjC z$AKn7iKy7d^t3;c80b?(U{(Uk#e7`>L>hbz=ItdGi)el|LDRg{<46P=!k&vpR*|(->kZooTKJzM}7f;2#Sjbh$y?fz4hltr@(8d z6}UX1o_R%uR;pgdhMj~N=ETBIcn~PAT`q8C-|mo4qRP#J-1T@;O-~@)4*6efywE+UHB0FJE=0j@ZO0KejkD{ABAls3A>-@ZYu%K4@ zW|Xos`q@X7qCJDUL5r3eaas&ehL6?j@lYJ&kjK%)HDqQ%Nkw^CVs@yA|Bf1fe6^k0gHhtWrP zyCv)w?E>_&?ltGcQt6J>7+1Wi$gd~}-wN}(B41bcy!nN)CJ1@M$G!iu!c5Osl)QWn z_|ZFI0vJP8)CPps1OR`_T<}UfA8pCG(E~dE( zFz?Vx1?JQ>`$acLkGkg@XT2m+hFAoW`J8t}g;@ib{F3-D3e(k8^lCn*yVkzFIg5;K z&|aCGjU}3Ir6Kb}N`MdsIKoBG$7*$o&S60`cv?qoSRectGkCKYQ}LHF*)`JzX-ury zN@X;HHU-32I8&jQU;AA$+YtVz0BL!KrVXe1ibDdIi82R$`!yL%bqcM%&I;x(vTPsp z#bAdh0POn`;&$7xK~tB8eyzezeYbYswVo$%0lz!QsyRhXa;v}WNp`+F$g|_HN$J=I zn$ezS#b;eu*-%lj8@O3STWwZF#Zc1Pt1x_>Yxbfj zIikvrfmKoMqIF#an#zu&gobmr+ok=bZrpnK`EPWjudRSa=P5mR42z0dZ~jWTBEO;M z@j3PBC$0Gmq;<#Tq1658YkOWArj+tF?&Rc!+UIVi(mThmG>c|KUxL_QwVsess~|%9 z@r@^9S2*FrjHT}#N|ZODTnHKY@iP3!vlYBvY4Ui=ASc6C+#j;qpVW5KI!n}b??Q&l{bpU}9!8p=JKm2R=avY_MNPw9i7_m7pG zzVGj+m-;^cudj<61ONXoTKe8PO)FPjYDP(&7vjk78=zTcW#?sROtcY=&@lS6-JCjO zqnlevaaRB9@33rdVA$KNm2G6<7f~uRIf`UTeJuW)ypwCXw1g<WJjJG6z9HCK~Pmzgv$H%5Zl= zS7qU;+@ZmyB3&?F7`Y>0*)~wxv1h?YeP4-OcsyM5?$gFkBXkE>V9f++;q)VwGIT+< z6|tGyjx2u{m5pl~A7)0@=V$I$!qv{L`OD)jwafZ?OPw>bHt#WQ z2G~uBxnMmNT5Fs#sGR0~rx;@iz6Ad~e~cQ0U3cYIx!m+cTrcvw(8F%wz;4l3upF}V z^?|!6T%Tl&vueiKL}%j)kT7J&>RRD&^WAJ32&Zd8Qhct1(jP5px*naKyv~wI*;9V$ zZiur@dqc@h@v6Bk6kNJ1WY%d}DP8C$7c6t0;w9kfN?5?14f;B%WYF%l@B9ekjj{)a zr_FqQi$&mpesNu0?c~>g^Rx?4_NZ1Z$$W9G1#zFwL}PvW4Svf^Sb9fGzYIp7_HKvU z^$5H73BQbEs>x>-be+Vfmw6imT!%%U)?JFYcL=ws7xKWk9v1ugp9p+@e=v%0unMmD zp==pE74k?FX4lW!@k@U2!)~#LUPCUfA^6#YZ4rDd z-Z}N7d3wj;6FSMcEsllLugK=QGk~wpBpwW=X&>j}F(tW%T05CwM$O%d$GXBg&Ci^P z(E8dWOYJW!`uY-Gqh>$Wxr}uV4>lUL{O0{vet9-?l8zPh#(P|-Y~UR+12=_V4Vgca zFYzOEkb0&vop#)tlu9ZQ)%TZ^j`2e{CiaSM67vO*sQNRO(MILH1H_Bet9hiE%RAEa zyn(j_ilX~uIffaj`6w&VO88CMpj|oXUGFS$I*tD^Pv_-0Uy$c_{DfX~RtNUS*@J>AqA9_9bk=oIo%iM(oiz)z3}QCLgno})*kgexx=y{=e+X2QlWarMlwwB zHk?h8C(da!Oa;E!sC4gz!D=3Z$;H+5qNkaRA4kyKDA6@1yhT=FM-aq&d0fCXdGO<_$l4 z`+?q2{PADmr%oup&p!JQ68>8r&o}XzDvF25gyv0E4P}2eaRkTtX!f;nRLRc6(z?_< zM@h9dD^gd=GkZs=%JA&Aq(%LIs%=aRFU7yUj>f=-?O;7bZJk<^4=83Zzc_6IzY3gTWpY_TCQn%W{}p*8>9ksJ?22XZ-vXG?FLP;8@a z_2ou+;&$?9n;j~fh8^d^L8RM|9j36xTt3;EhEde!P22tgzP|#uL6AjSl_z~~DVWB~ zX$o8SpF*Ko)ui$#pWRiO+zpBtJ|%0WCn^YFVZugIx^8#}cX8`*tJ$^W{sq*CzH);e#SfzK9H>kg9+QzX>SS3|# zvMhs?YF_C?H^a%geBoTk^dhs5vHqi3$1*w6T*67jC_e>%L~Kh!Z2Nm`E@M6c6&maD zvslD42R8ZPzKO3+*<*RVh$Nk^oux!8bzY}dzv$KZv|XtZM&CM#AEs5&N2zo6CM_vh zpEgZb-RQPbp<VU?T0$10@LHRLo@yOtaM8$9pV9aGkvR0)00R)Euij(yfhC;TS!1o5jH zqZZr7uE1YyTRdOLV&WyMFXX(ezlfMUY}B;W-jAxdJgn;T+ODpjoyggoq7LWd@xG7; z<*8ixgPI?>*5j%LFq-j-u}p}2xcNHpib`9%)vj*{8m0M<*E=eCP!xWf?0O33@St_Lqauj&Z^yC9 ztAw=n*Nb*O9mI~Wo=CtYZeA*cw(NNWxyZ|^h#CZC4}{7hl*MCT`8;* z;3eZriL7s}jZV6hEHE2!?GRU(>eb}eSR? zz7BxuK5qz-zANcipDFARYPGbmx1xMHjFWf7qAVqGGdK6psKSol((6oGKV_lb3<=8q zA{eMslCI=Q5Qs$3HP^LI;fmeWMK#A%!LVZeSskO%IjthSGQxf?k0xq{e6jF_!YW9F z$E~C@((?!iTOD?!Nfiy1PL+eg6-Gi3Dl7y+kdWAPxl3*5k)5xnkJl6rT+!s}RPh)l zt8_Fb!qMgl`fxB99r-s+2U^L)!w%_Y3znF*{JY}%A)uvR>AAS^J_zx6^X~Vky8m#a z<@_J!zB1v(>=BcP81)OnV^J+h7Gj&{E`_lTi4(c6Bmz6CW5l!6DR%{9k}Sy*cRFYdwoO&+ z$czr7DON6SUyyA`(A2V#ODz2AfeGB|%v0relK1fb+0wjfE4N)=HcDA@1k8e4JJ$I2 zaKf466$kZP)0oNut`^^ZPH(5&L%ug3I;ht*QV#Ur&P<1p`vpdpu5PRKJ(ArGG`e(a zF*on(9%E8Fago%Xt#HxJ13VwI!o#VeJFBhYHfBC1$fRDrAqcOlo3;1YmJLEg8@WJA{IZ^mn1wICL^YM0@ z2+C{Pr`C;CR=L~j5`+MaruS)pt1wnRO% zLa`#f<9Bvj_pC^3H)Zp?x@QGhkdC%E_=3Xo4tNawVxnYMe2PIPnknU`ov_w4j?Qx4#+R5O}GB08&tbu?6xaG@=It7wuC3Ws{B4|;{x(q&~`biGQX|cs`OZ4#j5mL z;XU4N`E6}W$mX^SuW$jYGNX+~?UUYNedbQ)sS%WucDUOrAA#pjHaW}=d)7yG9#1f*UwiaDvJ**mRj??K-5&S} zTKI=AV1J(nT#Yd9B*)%9q26o!9CACE6&fVBIgneZA~%ocSi@%lxwUx=>oZ2QWVJwU ziICgTescR7+$1X87{JX256NvidhA+q*Va2b%x8J&i2KgFX0Lt9H+AMtUsf(@ z7q)A0&emzK9C1&(Yoc@qu8qUBR9st)-p=OkUiU6qm@KkUOn#~oD>yeJC}(+P=uYBv zx%aMZIonCQG#Vw(PK-to($!-$>Xg-lRuUSKEFSAg8CH){9a&L5)n4Qcp3Ap-)mzdR<=IBntg-=Xxq*exb)+nv85!4Q?76WhST`zRobY)YOH7j(h4j!SU zPa6ggQ8?xPO*V0<+IrnK)z*`3m&&xM`qdMI>JRTzzs()GQ}r55Uh2VqkMMlxtML+f zd5b)O^|4gD`W?LvlH$9#&=z;`kS~0x^`xb+jqt+wUrB;9LwqDIqXBlWF4W6~Y%^<* ze<%qr40W*^gcnA-e(sndajUb3PK_JTJOPwXdFC{X#Xh$Z@zb8v26%C7o0oCh%xy|N zZv9qoDBJ1{;keX>^Hp8-=PTteKs!4mJ!Gp( zxv|qViqB!EJL8C3H~)xlm@@0$KQ%d32VZC~cHB>a63xDNctq>n!E}?|!Q*|nn?@$3 zW+HX1n?^3B?m;TrJ*Q`8-W%}i$Gexk%dsP$`2F+W;@B;)Z4V-t4*C671oNN#{?gC= z{=>&OmUT>>r;pd`q`R|LOUgYE8%CY!ee7H7tut+d9D`(ziO!kIj968vS$ovYRSa<) z_lfnmB8bj=ME+UP`O7$#C^|#CxUj!9yk#yuu@-xSFfS+0kv@Wk7c|pq!8|On0DGy4 zl7JMC)IE*XxUJCfTW0U^IW#V|&XicfXz2*{glstcZ%?X&e2?*!{Dv@By-l#EI?Ap5 zhJ$*cvECMo{XR3LTFK|gk^ML6>guiULu01Ee6rfigNY(hgS~OD$IL@bcru!e+YvXq z&jYy7sY8NGE@WaIvG(lhUVF&@DQ+eIN4=Y(dOi|n#7}nfb4$JM|Q+PFhBPzviqu4m0gV7)_G~)Cq{1V{2|%h+#|bpTZ4U{7`eIAXo`^| zI=|od(Fc5=742OWjk2)ndQgDoDiDp^jnM5!VYlmsnQz>?CsZgQxP(a;sQ;Raw=rr51HJ!6~~5 zzDs0DlDJk-cDMJpigmv+YZ?<9I9qlh=i+Q3g*BOd^xqK{*dG|`?FVAy!`M5&y-(Ha z3$JmEp6Nz`FJ@zBR+q9f8y*r<54jl+S=wK+GCBSn?N8Kau`OJTyu5?q?akX zyuhq~!jKl;=9(YJs;lf`q?MvNSLAOUUE@71D> zWJzsh!$Z`PnEIZZ#anzrxb}?4&g28WwV>DAj;UWevHjXHD*dQOKbqg%|CZWD%n!8j zM87sV+WWTgO?%%qzHFzyZ1$;^YWMy*7q!zZu?(M(Jj!bEiD;=6E!~Zl4h6OJX1|u| z`?a*Sy}LILzR8^On`%3;KiEz}zjl`QYiC)%cFL6=O$hWTdp~p5C~XN+ZO@bV80GnY z_mlV-<>`O-lX&RAy}-8cd+zpejV7u7K<^#D79~Eq^!4ugQJ8p~Y9n)te(4 z^-@gG-A8D@?QL_Kbh-(pIOa-~4*BYGW3XRu@zq{ME5p%B%~g~)pnT<3ls^rA99L1E z__tq0`9mmgyNdEVP~Hk(KGqo{|Gq5|qf6&ANnE{rfH_}(LmgWqvex*r2GU3tQ%%Yf zffnBkjK-9=;B9yMjLAj|&8R_H z|5XT@H)0&oNgQi<e6rKNJO2+RMzm(N~e5yx`Y zN|bwdC-%v(lVYl9wP!NtZlvv*Ej@qrd#B(kXUjP)+GAvUJA5A#OD<}>b^3(g-8xl_ zpLeb^^w*Z9mPxlCa_fx`TL#*ME(3qa9l~O5;#l*!XF|o)B%3&n=D{Yb(3OmSzuk7Q za|RPmy)-a23oA^haOUts4$EYe70w)bNX7jD+!MeZ0o)S64FMDa$OZ6x08a(b6Tq(? zVm38)T(O}PhsQbgkZ=6J-qpb*y<{cn1^vgE@-_t@c&DWezDgrPGr~Ru2f{zUY-zdp zJW`CD$!A9^wr?j}#*h@&=zrf(PIYK93ZG{d(_tB=~=x-t$P9Kc3$6 zNbqMoz2}i&0X%Dhtl*cPU@Lgc6Kn+=J>BP#V&soK-RF@odpv#5BgM$izr~yf5C53+ zNSIHai_as?hW~Om!pc8$Z1*~jrS7Kl3NdnBzw-+J{r43?=M`e)N)MHKQaP_6pbp#P z_kWAM(d>1XKCjW-pwcb6i0*xT=+0K?S{1r`Q0Kk|zyBG~y-;^)y43-?=@-#W=|eYB zp*voon~yq0p!;*s-EtYa;{tReFQUu$p?kqir9_2pB`4aeF?khcy z6eEA;rW(85SAHHTM&9qf_&n0;y?%ekM;sdj9xRBzkNC2BwLd%D{rj{2AHn@uqx5H! zoBA^ib?VTc0qD=N=Pxa%ApyFT7tt;5L)WIzEm!DXcvY3t8`#$kzYN`vUsdVOzKE{5 z58X)$-7JOf4%D%}>i5qD-NVman(op7-NcLNM)#p>ROrSjbni!3-cxrQ}wkYe1a@@cSzEt8ve%<7H3l|KvOp)xY>WQaxnd@&U)bT+6XF zyHq~6Uc~2fefX?Z_}rlIS%f;LcA@{^vwZE9pGSf>-+E=|kz(Yu)*n8P1aGMIYR)6U z8*2S&&Lc%*KYAtSk)pAqztZza(em4!KXe``8vE;?>O4}kyrT0;&m%?4_RcFmj}$G> z>AceONYS#n^UBU6MawCjS9=~QS{~nd@p&W*#{MbHfz=3=2%!jPF`u79ScZ5;L7l{#tK-L?N21!Pr2meqJ&zPEAL_W8^GFy!9Y1^? zDO#@UxU%y|(em;R(xJ8EYR)4?%QmH!)N!Tfk)o9+(9v>o$CaK(ik5HgxRUco(Q-lu z>5p|>$$6w`xvjnbd8BB0NJszkNYS#~9(*2&(*4gPVf=J3rw-$7HpbgNgj(2s6Yvyp z^Q-E4q?4;Tw&4}5V+ezG`2F8C`~6nr{c5M*fBF!|;t>A?I1cFzz(){@5!z7J0(=g5 z3LzHp3x9&mNBlT&^($Co5U)ji*h#;CK5%?3-LFyh1X60MCER6?H!_9lmz9#3gV} zK-C1QBspU{4;dWpAW1ZLB=+319Hl(3jg~)bW6nIt@M(mlf1v&8@Udh~DoK+$RrNYa zeR2^c)mxj~oI`Xp`-Iv-4muYkIy1#VG8ZN~b3Av3u+br2JrkW=7bhCKj02LILld>f z9BjNK__(l=w<2A}RFga)bOyMZ)+R`yT^s{t{T}OW4JK%QBJyiH5*-W_nQ5xzx+_)s zV;38+%_cev<1oJ3l=o1cNu|-zX5Xuon%&%ZBXOb=oU`Mmh+J2yE?ycUQHhqeL`By# z+Uy4|U3OAW*|!5_C!%bXjT>8K6(xJ-JBYob#JECkESF2M$%su>VpWJ$DY17Ddq;_J z3s5ePV(PiPr|K)E-(-dC%8|KHhvkW$(_MzzROyIsI96U`TkUI)DCY&RezeVz!d~3y z8$Kgij_lCw;3U#tES)_vF3J+uf24O?{`Tytr6aSmvu|HY zwC%0>B^H&sQ6lzn zMr!+G&@eFSk?z0<{4%}G+4bE1^jAl9+udnM8NP#hbrJavOb zyAM_%?JYLqRdbq?8*u>t=E(k=Su#Bpji#sdDS{JiF&fXo(m3l0=DovX=sCF-93NqR4a_Pi3BDs0 z*?6TkM)a!pf1~9m-eOMQX7#?=pdU@oz9Xfe5}_tS>gomOzjS{7JKYQHy2qDyThz&G&$hk zw2|$58EZ}b0jeSXV2wFJHPq+GnrEMtCd2!Sv?bWY)xY&I`w5?5`iCAfQ)Eenjl!-Y zZcZSskGt6o(Jsw~yQLO4r-^r9l=Gr9OJub(Bzi_HI_JTTrnH$HxibkfPdQL4k?-9egIANRl`lGuge?y2@%R;=Is6JyJeBuTNJ&lfP zrWJgjr=}qu?dTBS?@4U12cAT?AJ@913{B(jy&+m#+^!~Wo%#&8#`+FCFtNuU3JJ`P zN8HhLN1!ggPj0FE$xWp1C`kbQe0PFleq6fkCEFlnF3%7}=U6GVfh9a~|0`ypi5pjI zKG%f#I?kl{|NFg=i7|nmy`z6K#Z+l#gE^L)Fv!OxZ#VlIIm~FB)gZP~T!Yc)y)ldYuCT6T zPQ3#g8_#S}peu&Je%HR|X4}QO_k7|e?zb3;abXzWY&2(?YSTBGPgk0!TE%rUkxw~h zS>zLBGe6a;Sr;wO_Ug8hj^@B7S{T1BdeuQawR*%YX2&_Nft_04N@Hk-H$r(z#|_hM zrIdgxcYBlSv;iHB4rpUXE9}P$94miO4G9Q4UQq8pJ_=v#_N*tQczXVl(Cv-!wHzp> zDQBY68h)#s90+S-rdJRPcbRPHkHKW&3Mb0~_kimJog;|n?0@zNMw6{XqO0+-Y0@V) z_-o#uDfhq?f6ZI1_=&^4T*{ly5}84FEQCw>*$JU5R?9}JbQ9+^x;2AVnYl*MA-FhO z_JW$s$#Ih#C+}vXbSIAcMB}@=2l^6>AL)lQy|bIFyWln1xSt2t6&lGOc*FeZ38L^g zD7<0*%L(u}l5??<7&SIFM(x8vpP{z9KYXF+6vhsm5-oq_;RD_m?=(r8fE>kEKK?(x zWzNrF=M68Y_AD|hO0j2ae95LImK!8yBYS4hTyMqr(u`02omCtQt9D(6FMU8G-4T8; zO5Wc|+OsQfosss)ewBL2qAl{!n*!H@ejGx_231GT*K42EOHEnPQjPNLPgl!q(Y4KP zHe;(ftPwl}J+q3EpX_|uY@+uMHVoQ2L8`FEHJB1$A3dBaN`9e}nU1(4n6b7Fnmpzc z>~vb`h|gF_D=izttI&MplzDkthhLt<20}cYFS zLf&kkQ1nT^% zwYSuDN~w`9W1ZekxdWa*sMj!ReZJ0hMptlQ{|V_&p~h8b5GaOH?Qbg{7ENP9$B zY-0$@G2X5S!58k!e+QNE{aFVMIF>XvFQ&S$T*Ge~J(R>nYCL3RyYu+BRE>a-wU3Bs$oLO!jfvMc zanD7|ZLK@Yb&>|!K`fzaSVQoyvT%6QB9*A+iixd@az-t z(M5Q#3>}-V!?6(9ES)!2{t;l?S@-1!J_dGNd(GLLj|aNpD!iu{S|;2hhEf z&bRQ645H16&b!2g4a;q81REtfEpeNEiTz!xwSiOi-kiyPAT%p1Kx-Lj*$)U=2~s!p zawUg3Zw1|FL4O8t-Vf5ZU55U&i|AVd^uMg-*q=aG27bQdhv=tYhJM^d^dkfG9|7HD z(60sN>`>2;SJj6)rUm3bTipMe&SA!?#?iTOvHG>App8bK2 zUvnbGkuD8{?Tct0i+Ra+%xD;e-I5-0p(C-u5w{ICZ!`R@9O(^j2>XLqey>G;*fjE+;)7n zOQk|59f=MzVTZm%unZ)x6&_j+oq`S7oRNN%jTs>&H;P_?y=&R7_>(uESO-s)_F~*> z@;+0Vxph(U()JmzWn&GXwwAR!8fba(XP8P1~nq3 zv&Tg=-ZWI$dN25d4XlrnA8F?|COQu42Pki7#3;4JI*l^(X?BGK=6+J!RvX!%L`RX8 zEYMb4lF@91?+SgW;K?+pC`WjFMNThNY)J%C;&I-=wc+qKvYy^8s^P#P;GqMi-)7^C|* z+NP2?y?2K22hC|4R#6~zQg%X`K*3=p?lGuFy zxhVO3dsf327=wJ>ChH->=jcj^>k$4Wx%}Qrnxvj=@Mr>OY=wIJ0eF+1qSfS!en0)@ zE2dx6kN%S$!)n#njmnA+_`1V`d|eZKUGi~->sZ%#F2k30ogtM@qjh_`7VOf|Kjk|r zs<%t2MCJZKlsxJ!<{St5sR&GICnlS>#oWHca;MLb{IDg&wmf#Ijl(`}#SE^?#5P$+ zNbt4U4U(oyqgWtwkuUz1yY_YVA-@Yp32kjJ4@wgw?CmK1FB6T($px z(oJpDDqj)lZew*DjrivR_dTNIm)~U0U!jfr5mGK{>uTh;MQQE6KCRuSv}WyTt@zDT zShHwdJXlL@4TcN{|7aN&DJ`1%w3wi@IHIS;pP_#>Xln(+9kuG2Q88< z^zT+rmqy7GP$xQ2Hsq3JQ`{!SUaI9aDDQbju}_~bChI=tWu-*DFs^CahyykzNG zIaYUH;}<^DrhQ%90N8?*S&fGqBBW@a>EHc&gOj`Y=>=Q7x{w@?+p({U4H(q8uZvgy zn&=BqI#-S)Ng7v^n}5JL^q(;>G+qtQk`hk5 z<<)B(US2co#62Ef6CsP5kjAivPi(sy=6XJvulbbS2u^=yY-FRabv|Lc#qy3@Gagsw znVq*6-eP$ocfS-RakNhT4Es^*K{x*%EYD-cz18(iK6a1|hgH4)3tz13q|bN|bMy{Z zCSPwnP+j=Wf>r4EyLkhpT3@PZkUr#7zHlXSxZF_bpsf}$=CEhdJqvs0qlHgO?=D!6 zyg%g)ks96nHS5gL&2g}cF^#Bg{75IZRPMdT$HigS_Rohh4zyOL>zeMp_8@l8R!QUI z4l9%G9VcS+oX5?i&(oaWSaC2NM*Jb7q2b*Mi4(-di& zS2SQG+;&143A+~PyavsCZhl@;E^)gp*R^|+UF9v&_8+^=4<@SL&dM=nDre^<0diwT zdRLy_l+QSI*InsD-od|>M)nW>?~b^w<~hfHXS;XErFa1fJvPgM5yaT;AlTDU%UP>SD#1)P#jm}%ex42o%Gv;d=*@%1EHDUMo zg!|JeAZ|#@bZh2k`h+6GZEu-7n^1BlbA?OW%&^>=&DO9+1MUCAmG@(?|BqDm|MA%W z-_Sr-Po5kp&wZPo!Lb|Ihy&l6q)54~v!#W3d4rIoJIb4$2(f$NV;X$RGsf)=lT)MJ20R_BbheEK=Hq&zjtJsnYNs{f3i4* zov9p~C{>QqG;<^WXdc>}>1qH6nr0rU$mVp{Ti$^=VpF_F6hJEzydYm}9uME7L6yPq zKd?WVlaKPL6D`6R-O(uN>5yXR1pd@8jY~5ox+zMEkoHhsH1Za{M6pQ3rW>X$v&{C5 zOpl*}RNRT7GcvXu6kU=zBegF5X-DQ8fxbTG;dS+pdm7{(?#hhg;?rQ`*Spgibnp`C3kkO<>HXib5&OQS zxyL(dq~3j9R73n*E8?`UEi{T(*jP$tqmJf|!skuBd@7m>YuXU^B={UonnKQ1@hNNy z@EPs0fKOVBBzI+lUP@K&$zQLe)8V^E%HulIloY3MB?NZbQF2GC%4hMT9DDmkzn`0+ z8MWM*bJlOSXa22~llh^7f$TKrFgq$8oIHTz<=gl$7o{IXTCb!JI?SG`ff~dV#MN|M zyADhIZ7khWWwd9K4yVNObO+VIjk@_nj(jb~ZNcOyi49M2M0h@9@#mS$WR1RcaGg1& z*&Jt$(~QwI@?*jqIgBWse4TcHtHhy`^}3x7y?mQK)3YL)cP&KD0G(F8O`G9a5w+jD zc1)~uQ`~wp-N|o0x}NUV(>ZR_dh_|l?)wcImo`fq=znpmYV+x=cX2hx9)t`Wz*}Eb z_tQfgxKUf3+-Ux|k*w3B)6cRH-aAFZSsP-Mf09!+jlSCa95=;t~}0UslmFk z-n{SVwr?xiSF&-?wi0zEGT-r5AeJUJqXJ( z1XAUl-S<`^<>F2jptGqGe%sT2|4QJD=luRw3SO3oWT^@#_c%t&fxNeddqB>hp&Yi7$c?rb&yYs`0iK2M62L@CwB59KCZkAKfK z-R&A<8;RZBvTN6vPc##qDdK}Ry4%e(iP#14@q>oOqo+@I-tJ;avCbzme(^a`17(ev z#5E6;hPXCl@Xa;mfl}151k8#OjGt9Qf9I7VHhCq{c#AP@yfp7zW~ewR9sizddd{3K zl}SSy`CIt3n|%BdZh{H_o@*NDLhXnLq|M$4f%D$M4Bk65i=^Ch(?i8uGx0BKX1vtI zOv%1MEKzyCa|TPaGuHxZq9iD9r>W0n>ZF{r9c3$}56=3_?j5qqd{A~(a*mJS&8&!9 zVaqxD%|m?cpU(OpTA2}cjQ56e4c@5((wsS-shoC{wmC=EhK0JY3l7t}IQ6TfVSmIZ zN&n7Snd7;g88$@9R&SM5^qQEQrC8yFqdKpJRb}X!LxAy8y*UfHF~^3>dToo8J9INV zmkd4x{>*48M;b59rykv+_Gp%LSH=kGD=ALWHjeZ0wV(loO z(WpKLa(&c`C<!JXe`|~V+pWE-i^LU<(`(l zE>e#5^nNuYQZ{w}j!NB$j&ah1^jxa)9lZ$KOQ*zWvU~ zr0R%^l<#h%C#b1aI*D7;ow~NFN-}QcQu$hOE1h-VQnj^_NDH;kPkTOVnMLzFMnJ7@ zO-R=@V!Wa+vr_LLmHKs*nxv#oSFXc~BqYW*8Mcy#o7R?&byM7a#Fw}!QVwmSepkvD zD#?~y*R0(@*5oPd;72qixkROg>HpF8KJZag*W&n{+1cIM&1SRt10plX9{HBgILsTEY%pxB}u=oSEGu{ITup_kHvEOm=tX&b{ZHd(OG%+Kg^{#tL{t zk+nDetiCb7hfBZFKx(438U16dhW8x3hvTLOj6>ND>>W-70-6_7~*_0bNPK^F4w|{@I(AzDjB?9tkEY!2 zw^BNr&4-u*J{@^a;f{}n4$QTdug2fIpiV8@TE6nkpsn*JfV^2QidlB7K>3r;FR^(L zalv0>;n&7d+2``XdPA)|AI5&-eBjLIyYLrgzi|^reIMa#8Z1oj=qXaiJgkxL%vY`( zEP(&l4uY-v1F-9!7#h0f35|C#SJl;C%-aT9!QA38f#pHU$&``2RrfgrI4&uv+pAylAP5=6>%7K~ag$yZJfkmt)kWHM3#ea;P#@aFGpYe!FYt*3juWU?7_ zm6koAAb2=#z25fJwiK~pehu9gY{drHtxcfpT@4b5G2OhS?AzEhB0G9c5)ie z1%Gkf4?KtCdcQuI&s9-Dl@Kibi@;CS{gnmE3ibE10XJPjN%`AQ;szM0L5A-zL*34V zCXYgE0OZlsb28-!E>3vK9?+pE$2rmb7!T5N1J!o^<|_>Yt?;%ffIBQ-p?nbgLsWZ& z2&BvecpRgn<3TeIhIw}ty;sxWAY+1l~* z{QUv>igUpFWF9=Z2IQl<>vtd@)oJ;-#%%*W$a_-b=YoM}Q`3n4IqaWo_-z^Jyq|M& zQ7cHVHNgc7p!ce6HkA*mRo*xgZ`eEfUV)m8#jQLV@WS_(;(Apwu6db>VYUps_g?%X zka*}lA+v++WXclY!!S0)UaV)#2>>FH;m)1|-vp&u}^W$nyvU+zE%1r_S{xDevnyN&r# zGI?SQOJuiePr+J?tMfT}7RK3t!jM}N-Obt247Xt^w_3+NDsF{gW-`(&L$UAlkL;t! zSJw0w4Da6`lac;@q=Gk2CbQ4=o2?)jr`nnu zpmKy6p=)18uF(3qHm*q(#{WOqRak$o$0C(TTpKCTwPAizW(V{~{3MLrzX-i5TEQxx zdtOw2zT)WLr$*&xa)Rb7dHtNKub6OWu~xgjiw`UN@|76?=QqEnts!)DU0$D^w3%?% z9(uQns43|(M>P#)o7iSbHZZy;0R~Uam;Y%tCEbknDWpGb>gR1G;+F@^%#KCyy};)H zz4cNrKzq+?;S;H4X)TUDQi1YG??-WxXPIj%YN{blE^MJ==zg&;%KUWP z-mx(<`Na_1zUQL6r}@gxzSoBHo>o)#$N5S}-^BEKB@;$FP*AP$eC5r)Ki`9~0J;{_ zruEVZBd$cEX6fwJD51?)SSZt?hyJp-=ZdMPD0xo z|5O*(wtqU67PN zyZ8arY4>tqnal&rBwsl@h~@O?c7sN102^Qt+^+8Z=#SrFcLUtNv0mqv`<{4MW;dQ8fZNB0i zAm`~RK_0EA3gv?I9x6R(yo{!rBb(E+k~o4Ou6#;f@|Pg z4Ef&rp`jUT8S>hC)s9K~Nvc4PjpS1ve71!l-(GeXc;-u7&_>gM zqd30>qd30>uj@QkNC}hu-0Xyiz2wb6(G>V z34=_T55Okgi9537R)$GhbenzfoW)(_?|{@0c|E(!cQj6n4~uz`%&J!nUbyNtZ)DYL zkGAU7Kw^5@iK|}uxaxKOu2&cV656iU>7n#Go;zRp?>*|g>J%dU<`nW*a{_ZsZ0xdl zH65l4N^p1Dz{xmaJg42I-KTR{G70bKwoQ_@sXHKSFouA=7)~^6`(z&P%1-*MC*#G3 zp6hjsj>RYAW0#{2vmDA!3YH)BHi!!(uyHRx9Ov>%paos0wJl#U4=|K*St8h;<)Ze^ z^qXRtIaC<^`)~#w^J`esP^kNLHh}!cN%$Fn!?T(pyV}PsnaNPXc?4-p4dh@X#_2zIokb}4Svy=B{os5^hfN=e!H(;`= zu_p26_Kw?DDZJi}8N$;G=SCn27-oF;-fqnvY z&GcG+rD+p;5NlBS@V~Vmt&zj=LV})Z1zk(sU{^SVnlHP}7*k+KTOCyt?-X_7y$X2m zT%Vp6cB20HYac^#&jBI0c4~~;x6W5#DDFc0XIHNU`ry63A{GDN_7!av9fiTda4wAG z#%R_s*KLuB06Nls&FOcl-aY+%?vk$vIgrQ5k!Hci2uDw?13ccB7!qEu(KX-8?8s1- z5rCumJZFzA0Xs-IaC#;7@T7*X7zKJ+*P4s992oc3S2||#nfumZuiw{qKGkpT{rR_W zUT9-i-UanO-G_DRwoU@=!-TO7tRL%!dc#`H*c!IPhOrH;##uo7YoX4pYe)sIk$vA& zEa{TG4o2(+-ElS#SF9};M1f)spC7?H7T5WaoERgBxwo>_NQO>{ud46`LkA?LBIg9g z6=P%)*0gK_)HIt+OGTMVHp)o#62>WY?W0g9mfizxLU{|8zeO#7Z7-=J6(i;Ox=dR+ z|595R+m)x>xu1kTTEhUNcS~q<;%>Cf(v~JtiQfuU~CrCAtwvUL1HaALSTFyx_Qsd&46EZN> zNX#^#NEsKak!tob{zr`ZqloWtO%&idigS>r`X;J*ADFj~v<0Mm<#5gqz(93#@N*AD4flB|_C!md(sW~ThCj+-yBHx6kTSa~JCdYMZiNWZk zSokk9AD2(z^ZY2|U#tX{Jz}&T)k<>dk_CHn)N)uGnW}t@kQ+XLGFNA6N=4NcPUQO# zYj~1FlFe>-#*m6HqKshMN2VH1Fn&g1nWBa0dD-@T3>E^Zu%68D+!Exue54b!1C%#L z8iDfo{Zh0d0@8}FS3RaA&))07tW>1bB&}ZwSS;nMK%VkYZWaNJx~1m2u2(VZ$Lr4C_f!dd{v1L+i1P0X5<4Be$KD$ zM>GEu<&pdHls#{*Rbg<0Y>hjiMv{+`h%V?Ml%F(TsyzhHSW@{#6e!jJkiwf?DyJ|` z)CgQvrmQ$&M6TQt${HZp z-Ls_UAq1KYV_BZ!1z$dKCqp*EIJ6S3IdBd4KIl#jzpK(2J1xORiP=p`H>Ek{!rFb( z*J#zbWaenCinMvJui_ubz@=z2{(nrH8~$b5yxvE`7N8A<%MO>}8d8d59)B4?H|rW{ zq3;@rOf3vA0`1>%2iiAQu=;DHW~o(lM*bx_T~4Ntrc<-z^EFF2;{)T3598Rh9G`xv z#X~Bzcx9)rH1hQ=Nzy+z&JjWK;ka6OM<(~?`E3aQ3vFb^(gUxP@UL%Yh+DdpM0LF? zN*LFxrwxGl*c05Wr69)(9b&pZl=G}8wzD*?3*d>4Ox1KjlQciX;~Q5qmyLcy7j;T+ zNlqFBXlwjT#k><2$~WAXLYfY#FrOG1e@B;Sl}N>TW8|n_gE0~`zke?SW8@N5?|Z{t z`vOfu2=zW<&ewJALk)-0b+ILYc)zt9u~spR;2bD7D}(342^nk{C*s2THC$4m|9hAs zDX#m?B*`g_{4;ii=_0$r3;3XAVN+{Gdke8F2*ZB?ZLj86sYJ?N2-$>eny0*D&c>-R9(bLn6>wij z-*@_j#_5d{L1KI9ds5A)H%R%6MlAK7G`f6wV+oz!NZQ|$+=y8_<9E|db!Cm`uUO|P zPQb6dQ5)}Vpw(k>L%Mev-%-%UpGpUO-SCNaK>*6>7v1N{llWO?Uj*)UONV?1;Ip}I zB|MA7nLMzr<&~rd<0hmfEBHFI#QN$b+;iXBKuTHz&2?Fl4(=>VSr#0CJ2iK+cO#G4 z)VN`$lvK2MHm0ft@K0DG9gJs{u3VMQg%H`kl8q&v>g2#`Vm> zxRLl)3ga=m4_Y$@fa^~_4L^LhIc`%&t(-;7B+O`JlJeAgO2+fE)bYHeaaE}gYMTX6 zxS+;7s4@3o++-6dK$DAf=z#jR`Ly^2=O`PAIHyM@)9X{*#F`K*<@tkk8f>*+K5BOQ zV*c*X(RkL99ila2r8lIwY!{T`<{@oto;>BV#H(TzJspktC$Gv=e%^qgR%wmeb) z{-35-LnW(sh&h*h|Ezi0IlLhaYoMum_rDI`mh<3So`$b^U*Od|<(7Wj zEuX9WI($HK`*BAxPu=$BI?!#SeuZ!bFueE-T70(S?z2PdHuy^tEFqrbKF&;wHF@GH9cyZP#~UHs)%Q3dN*VewJ>4=XRQB z-z?_$h=n-YSQLe}u76gnKK_(A=SW9WY&R=4N>50Yw7u@o?%NxE;Kj3GLyz}PP_4f_ zh4fd(@({A-?f%jPLC9{|{(0c~PVshtEL&~;cKWRN;W2B>UBc6P5(MbB`}K5_n0c;; z=f6Fs&0Uc#_j)QpXC4J=VN1Bjag`t2`pYR2_T9vgeXECtEb#g6s-dAXD;Tok_Msu- zZ?5Zxi!=cZ;B&oyvp56vOlu>P*2h&a&IFn)&}vD<595a;T;a!gjuBpAgqKz}?+b8>`1&xaHj)z55s8m<`^lt+)FffE zXpS(Kt*T8O$?WsYQx>UZF-n(&CqTUqtsELUeIr9&ZPxZeuH0QfHvz+s+?;v?fbzfKLyDOE(6{#tt%HJyH9QiPA%$pw~la{0=H9RO9q17kE z)RCH0DRDJ1F4szC?u+7wQPh5zJBBnhHet;jO+K~e*l^9}zQWM$D`SngR!86pysE{P zsQAT=@8dojBUn|pq)J^s6ipFk);hrM+SCl2mPbj&3$89z@}y8UE%EOVO+6z#2=%Kx zsMRk*?X#eEM(t&MYYa8h|CSp4ZfPsXP!WCCUg((${r4MLvnadv9gXXl3Xjus5I(UU z)T8EW7eb%k@3DK9r%GIA&(aik?IgFD;ub{Wx=ChFk*7PZD?vT>>+huZy;pF!XPP*| zV<@R))ZNUz4nffwUl#L@SYb4u2d!?FeWA~!skG7WliC2DT>6OJ=9vXg*2=aJM!6{a zto1F$DS-<=86rymHO2 z@+ITxSc)ab0;X7!Ht?QWAC~5;_;hJaRz{#Cax;`A1Gbw#m3U8}pO`NN?daP7oWM6~ z`&_H>4csMjsTQzb;vtUm)Qb8eUh5d!!@0CR$vvX=$Xki8>ye))GCh+0FZRgu>oAra z+Hc9G2aHUV@@%YAIu=?B+Jq~~Q#K~r0gH7Gq|#`Noh>^gjQ;mKw5YgT<^4AiAMGtE zft1DUG@nZ11^ueweQ}$;!)-1~bf){|QZ4RqumbLx&9u8^RJ+suVY|4_wXv&}F887Z zlG&l73xeMyY{7_8!Uh+gRhoYXW5aqepgbP1($|yvoXI_l6N|{}>gp;X5+zBNEQ-9I zMz4%{RTvU+;=D6*JjD@&<9NzqW6H&b<7rslh0mK}W^Gq8_v_@))xMKH zlB*Qy-tchbv?_^WUKam&TVFlIVyBd35vQN!ne9#(c|^zh=u5`J-F6O*TS;_bT+rpf}bMzq$~tJZqMZo$6? z^!?Gek(n1Fr468m-#~poYcuG3cdDdW0DUj4lijF*^a-VYQI;-uXLUJ~Xg;yr%Aksn}$Kf_oa zxIx2_qo0BmrF%G=TJP0(Z=lz;yHR3<&!kPrd3oF{4lGq&-q}#~Zrrnwr~Iv#?ABst zv^PHNWhfEe4K+&XcSdomw(k;Su-%~yEij_ZRtL`?*5Yi`xKqg+67Lli8!O&zO3xDK zD%Ll&7JlCAMXgnOu{79JZ&C;CLL9X=f@eF4J`dJVJ}oZ(p{VP@l?ET}+Q-R^wL8Vf7E0@C+r#TH7C`@= zLnm{VQboruu|F#6dusfT)mDdFeOP{bq4s%xiyV~MEMl4FI&8JMj!lo7tv(z#GrwSr z%f;WV65eSKo9R+JSE<1(N?GGK_!?GZ=KHZsn^=~9c8vp`-7@;w$op488TTtAHQ@J) zOOR0|$SZ#zhV!5D+WRH=oJsOJERpM}moC*x_o!C7F9}CrREfYPO8m6nV73j|%)_M$ zgD`$+ckrBoR;hc?Mn*$tI5G@ZA?^WP(&x%LpC`Df8h*${`B3LADX{NVTJp_WUVy(} zcBIs{bdTWEWzZ*%^Pc|QIszA#Vn>yF0_s|D$x@fB%XeWZepD$|r3IE-=~*frh!gf7 zm$t|(LE13_uKPFF;fUv!UXV)s4;F>sttz^?823EnD(mFVkXXE3y1_BYzp03ug>us2 z+W=*B^y%Va`)<+LbBDhRq~Qgh6Ft4jB=%UL_Fc=8OA^6 zyAejXJuu2lI(Zp=MSaRA8U0U+pB0OaeYsFXAQVc!iY zrt1wAvn%N9>eDR1?1YNh_lw5LMt;LEW*^$KhB4a(n29Q8>jAU*p7p-MRF*J*cPn6a zIHe;bSkm$?SS3Qh9NRAO%_S|EC7FwKNV&=_al{_3X0r8UN++!J9ZWGcz-a47={>P} zbyYrBX@-(-0A)0b!rX&#M{kU>9vBnSCrhJ`-U+lA8^;}|Oqb*!K`*VLH^aSKfIg;F z7WsOJ3RH+P*)13W^IN;Br&R9mKy%?`` z5_h!aDw})j!7hTg?Z`W59SLA@O*&!(nB5-E)gkJSbMSo$eMl7OIJBHtGG(XCg5@My zI9Vk5^z$PA3bdR!*{C-rZAQ&<+ERN5)ko%FG!#Z{O$FOYC(Q#~b zVUesiZt#su^Crj)&{Jp4&~u6Xv05DceyEOqOl${?k8@Lnwwm1!oyVbURA}~T91$4J z5$4`Y^Qdl^M>E#jgkCj9aFoRxsJ*>s5A+G&BT2*n)PU{t=_D<-Pxfn|~zeJ6tBVf-K+5|OXu%x*WusGP0 zDZ#;u<>0|n616Go25m~q;I40s$U_#$!y6*bKy?@EoO6$ll7}Gj-Q<&Oxk0WsTvzKn z?xep|OS+365=%fH3@8s~lm~m{+aM3$hW@L!{7kkI=s(>gMW=hNxC``kMjp7>TPYIM z$9h33=BJ7-Ar<)ie9349$=EwA8Mvd<29jYKMSr(S|Gy2?YI0G8agTnW}M0eC~fj*djfn*e= zCBvp18n7wv5Ag8qlYKZZh2Q>bUvnK#bKzTTAG?T5!Wm@zKJ6MUHlVfZT8T_+Jb^y- zR`8NHpoGc9xgvsbBPYN=@id%BTdBW?Prt+{6U~bfOY&CkCQo@y)1@rgZ!{?khgk~r za)6&jG0X8hY4c5tP$7|X@XTFJF^5>NPTIXUIWdP1bC<&>DGXz-#m?GR`lo0E{Qopc zwnB@fUdmbYpAKl>H3fX``#ksB3q8DNX{tnM0I%8ZcBi;$029l5ay`FSEoUunMkd?G z9jh|2${2A)7^|Jks5ybwcdqj1L~QrPe(bS0xpTibCL&O#2ZH55LsbpnCRh&9i56HP3$7dl>aU{MO2$ zp^-ju?0cp@(YWA8u0p==n3j{gx3%TwI{BOI#F!{N3!9hbzReiROG#fh^<#Ub{!I1~)y zP?g4^^`@h7GO3zwsw>>h&;D8M>HkG6*7-)`z`uD*-9PFFU;JO>rPTi`Uh2AaG!8Gl z@eF0i$nTwR1nH%4x@HtkXM2fr;Xmk?v6t!>7@4Z+vOd?;Oy4N~i7u zmJ>m+*KBly{W;NeywW?1R;ue8U||f9Dc%?<$I}@|DVdV1NWGHOC0=!e?#BF&jOAxi zsb919dhEK&oa1(=^G=B<6WI#Ma*jPcv|^!&kvHgW3>8Va3r(@9>a#kNPJUR2&x@qC zg^a7n_mFrz+94$!rT!8{$2?NJ9_nP(wJ?28qo0|ASv$7-*ck5t8)!;(I=4pN)eP}2 z(sGdeu**Pw-e7ufzd5*0+AL1&>5?9`zbd;YJ`;XNcIR&s3y+i15ZD>UEr;X!Qukke z5mWn?} z4ZqGl9p#c5z#pDRU7&Xlg_yZ- ziZFJ7k8VnWR!i9g&i5cO&!k&*(1vcb8fXh}eoC$3fZ5xV%lhAv#?xFZ+SW$7ron2t{cx=c;e zWm}&|&3Xs?^PNwNy|%q_V~%kczV`<3J{N1PT>!MI=f2~M74MaOIhDu$KCL1lR;87$ z1gV9TV&r-TsijeBJN!awna`t^VVGLyQ)J~83<=bYrp3BFyj$~ONX7M$RvM73^mxi< z+XA#;X)Dme486fs79GLSgB|}a&|>@wB9Q4`05{X<9reA}t8RAr0sFtWUTm7*1ed&CLG}F;|S@z7n`u`rU>o0-V3-SnFhXAinhw)1FkH+hr zG+wcP0x$k+@Vajv@NVr0UOCDOVc%6FGM=OSJiPoW4Nr`&sJUSM>BdMl-7X2|jXuTc z(FZuX1LsF-hdH|T^z{t~;93tJ=r-W)nck&zW*X~CxeB@4{DBtLQ~_gZg=pVmW4|(; z-coBgj`Jc;puuDPcS&Pn`8{TN5zENyjSq`i7er#_D1RE%A~Emsk(iNAms*N3D$1lZ z)G|Fp7!%tk=0(;5_m@C@Yx{BhvnliABWp)F%E3X)O z$i`}hT<_6h(2zFtf0Z_~fi|<#w0S1+&(X&APtfLuze}5mKpV#}ZIr%UP=mJG#%$Bh zE(tkA9@~07F`8b}RC@jQCFwBE&|>XjY9ll1BUnmzBuD8RxJz-qNv)jH&%@&u`B7z z;^tmfmmOI^)$+ro=S{RJD|>$-PNAnWSsLqdlppO=<*A$qZ=PzPIZEMRCZCSBm!1!H zNFlIKW*#Tys$KFl*d=$kPI@OG&JE-C0Q~n1=yx1A0A3HnfbCQdR)Ed`xDa*=6V!L= zb}&0_%IrSvkJwW}L zY>vVG9e7{Av*-Zc*ZtC_d?K5M&q*_@YnVC8Y=E_Mo))jy+VuzxPzNFiCNB(zo6~%u&Aed!dKE#$zA+F@ieeva-~9d>%v@Li9`}s zVwP+Rd5l|RDm)sEk-m8THJ%p6fMzDPbK?ZbDEHj)-Q1mM9m#@34f-?ns<$d!hEdq+pzkxyGyaguhEGDV~ru zpN8$X6@Q!}-TXPjS?4+9SNu8i7g-6T8Dj{Y=eRSwWW9At!fXV{nrFKgOO^y@f%@nR zveC33=wdiq9k!e^ot+|GwXoa=PwpA(F@W8BkI5)MWPBTBYBFc#MGa1145}SiehVjLb~He0lbX-vRY2p+A`<((-vIZI{MK70{Qr;(K`* zF@P41#-RavGR~W_=}q>4oyZ5EmWC7acfXYs804wP(F$LXMbQV^6TX7JYv-gP`!uLK z*Ikxi*y~f=HLMRymbh8)oESXmkSQ9)o$umWT?|WnInF3Y@2H^P$$cI;)0@D1MBd0~ zoQb^4IP*?qNx+*%=JH2dBKSvr0pPu5|iD4z0Uw(k^+ zdN3ljLpJfetOtEObal;1u$T$x(CF}Y_iDaR4X8pBhBm@9n}&iwg& zspw?%bYT3*QOteosafWY6|@?3?alEUJj|8GBxC$4x(9mGaH2t7O@r}a0NX{|7i99q z7eEJj)B5$}*R^?D&~Sa{L;I?{GH3kp47_?-GQI}zdQ^B}WT@FAI>Scl27A?srxw*c z9Kz>wPqu)@-7f=N2zNk(n^oa1Q%Bgv35ocLS#}%H-Xd|cTxVpiG$dKWg-|E@M?w9< zi=&`!9fsQ0m!mu_UkLg0ImM$O?*zyLix>5zDXortIPT>gdrckp>TJK;jU_BF>NU%_ zA4G$iQ=xVOwcT|%jw}VN7AHE%4uC$OLO&m%e^`Z{y9oLpeJ%8*D)eLuQscu@h{djp zF!<~|40-_ra_cq27<2;$2LOY7z@P&#c-Z!zyRk$zU|<6bK$3Db9C*Ot3l#@nT?%ke z5{N@Di31MZ2IQgk0kix&6$kzz94fyShwi->;&82sgOx_&%o2`b)V#MCiutSBpphFbF0BYR+h04j2tG zC9MQ`|2w_-d>)0ngt>}IT9~h*->A)tkkae>by=Vd7S!Q|QS?{W#&xB&DQ=qO${n?8 z6#Y}*s0IA)?(k(rrVZzfzFxKEniJb=Cxb1AG_Ve1U$d78@5EtbyQL4AMWecC(D@mUTZ1tYPUh@oVL03M7r05XR$eBNdct=d``&bCqf~ z9DKhG=a!c^7AA=vb0_8~hX$)DmM859ea|3fu2A8OvyW&QEI?btkq^JqmzU10&vv4B zfY#o9ePzSvb4*sf-y9_pC*jRi44H8)Lki&X%wos{xSoW2?F)y7Ho(WQpdGjlxwIH7qt`;UZ2eB3 zb9|1nZjcDhd)|q2Zj8ht;f~>Q1?QE!BhElM^fzn8`_zM;W|ahJI%Ze|aZ@;bVuz^gfUT6j9o4c2S@hxIx})qA#A z+bw2Q4u?rNHB-ZZqhoN!2HubySc)5Twzx|cpEk+7&ccXB&N;nuMR6F5}< zXtFAQ9z;2LCNWx0`uergM6Am1G0q;~xd*O}=@*^{_>bk#s{BT+e@((Ps{S|oQ4ZH7 zgmf!`{cE9a3taB$ne$QZ^^E-=;}THYnsZ)T52fNlK4><-;MeaJGo(rS{&2_9F&(!JOEl6frZ@OMR_i;*Li}c4-VSp%IYba61r`&r- zpEs#za+HDuw%*ZiXg_iO`8|(Yl{teX{F|u^`Rh~-e$2o+&r7CY9uMR~F6fJ#OjQS- zpf}rp30D7BdJJ#~*bjk)$ILLC5TsdDw_2d>bzR~$QD)}66FJ+6kTp}=BVy=D;91y) z7Tgg+a$?4$jf_p_%d;wb24+zM?q6!gjCmxO0F37$$H+ubt{0?d!OLT}>Q+aL^MQBO zlZ%=5y3zZLt;()}{bEjZhn!_#W*7mQo9GBUc%I%NJjEzR%D7>P)2A`tGjO&tvoDul z{g%Oalo(w{GdqsZGv4HXzv&@yLHN*016}Obo_t>1;Tw~*<$SNlJpJlp62V<-uZb%o zw&~s@zlO5DqKCzWMLd7TQ6G2tE`W|pI`!J`qw%ae_lvoa8&X`BRe8SuHFyg5zzdleW+yJO-<4=%(7P)P z3#*(GYIdvgSpWa=e=8(3b&7@vSDmBG=zCB+7mfMVD7lqZ7=W*;R(8_-5e@rcuKEXPjVFNIwT{{zQZ zah};E8he^CP)1F(P0mU(S--D6a)N-glh|00(>!%F)TO1% z+^?^{*Ms^_JSH(2qrI>dMIlt7g?1bHLy#w{U1%a^s#s$BC1lqtm$WZGY%nqO~KZs}`Q zb9xk{^C}pFz~^L7=v(UP9XX0e=GuKBEnf(CiR=YfnmBu-Mm1vrX7Xs>XH{1Ak?^l4 zXU^i}sK<+3F>?MeMmlT~Ya(bfa0I!OfX(oOgs{dJ0vkReoths)Vqz2=aBnV2vG5*+|!J#E{)~OwBwsJ*x7>LcWfa<5Op-wRUul z6IY`lHm4DvV61W#4c5h0gI%~vle*an%-^lXwSkpWHhk7_n%jWpJ@VNvx`&nneb_as zy{MkB^X}?4(W#xTgHoyIR8Qti+)4km8thRR#np4jYc>NfUaQ*c8G4$68XcK59Y2c4 zR{Qn>G(bn}ALnk3jvvB(pksuT09A|?jX)RU^Q&V`&wpi{^B2?3a@|*Bfi{znHY}0f zVr_m`Xg$UQs+b#srkJ742>3f2X^h=rNauKAcU8bh_}4E^r3~#4UBn;Tq5kb(87F-N zv}eD{&&3mlFe(OU&+z_>GdMucG0Z&1)%E$#2M)q_^O0B+0U5K&P|s@46I`T z!dJ%c?wrDYHSV&0lm4r5cL2=II(eb4AvL+dD8G%~x=t^@ZP+i`BSc=Wul8S@!NVyP z&aJk0eg42*JbK^{>=)%Io*K!-pkH{Cos=E|d*KnAuEKl-@#{$7Q_kh{ne30)*org9 zmn{|pAEKaqcnO&rKM-P^!4j0ccj--tcoY0t*2O(83~5IVFO=8-oP^QLzW<} zsAK_uq%;4`ja)U6nLNj?2W_}F$>o$D0sUvV%md|_z3RH;Lrj}E?g;8Z)PSJ#bf5+G zpaB`%eB0IcfDM8APyBL2W!;w>RQ<J%$M2VxFE2A*IR!HvCa zuBHW_>%|drIBOti!9#n}yZXyXNyjOq%W`dQqXxBLt#?GKj6uP_)0uT-XSLAi0~?hq zX4}{uJ|AW?x;G`opvC;7ah6?Tf7|}7x~81fvtC>lU3}&NAM|IO-N6QN)ciy5f1N`A z#}FjKbv9C=5AtEAoXpUx6uqtoDG5C)Kge)xY!Jo~q7Pynx;7ZmL%YZo~3ev*2K9f9P%~bj(hG(U134`3q z6o$Dr&5~$}^Dzz1Ylq&*=Jgu@WI#?FmMsnLRRIk19wUW`9T;5A0Y?h zjBaVH3uglpJ_FKaP6(;epi<>;y{K(>!?^m8g~%JsFN>~7#YCp`-C|a5Q#oqfOLgkD9r8BK-eS7UnvqKa5p_qXg(Nc7w95hfVrplXA<&6p|3;YT-v^7tFpgWqY07jls3_afhMoh zwLlYg$)n=99&d4mB1j3q&!m?hF&iQ~W!5~8qDOJhz%L}dMum>0G2VVY4VJ1jxL>6~ z(t$L1SzMfG1I@hNJQL|K>D^-8Fdcr#qg}yWwhidOUPOl*kPbSa1Dl}(9Yu$w^a{ER zXduG%EYM+!MBpBonWn)sE>aE9HuN4%aUDp7MJdkWlelVMnhx`k4vSywGSb_m;Z#|dRiT5$?ZjCSF}0(|=v6&Njsfd1QQW>~?-ebtOV@a> zP3Kg-&w-g)J@vOH4mI=P`yH4=9W>S;aTW(ZiSWY2py_2+fc`G6reu;;aSn2w$eq&$ z4clHxk_U_@=XmF;YwA|zbb^#!9doIB^I`N4=we+G`WbhF#Ysv@P^*C-)ZnW2Z1j_9 z3nREAZY+rdT7pbF z7G=szFON{-vw{4ypN~EB*#P>M-o%{YlaU2FSG8=jm1hQ-vd>O6jc15&0@$>0MV&)K zZx%9S@baM{LlHw(!*6~(`T{U2cqh{|?U~xtZ4)t%l0e-lzSydC4vd_-iocxj->Oa+tAx}Cq9r3HrTmPM-^=gJ)+~ttTuzTf6!>^n)Tlw|i!bKPrM#}F4+Wu%jJAr{~ zJKWD^Wil>j^6_UY1%rlP;kh~3+6(FlGwe>T9nZ_bjJgdD?fe`ZKedx{ijGh7PEYsS z*hI!ZzC4!smO1l=3ugnI$iLZ&d2sZ(I#y-9noEEB-#u3+Tj?4YIakM^o~vWU9kYV( z`jJyn0Na5}wb(NtKn+h1e6yG#m(3U&;>Iy#;boX-9iwm+=h~1naJDU52@aIo8B#Eo zA)n0}8ZyJ@&RG~Ij~V21PFgAU5L;?hj`rjEW8?wr$ue&#EmP~~ViUcUbYi-#+u|5? zj&a^aC(ndj>WL4)&vCVn;oGnK8COBX)ly1BYIOVE4y18ce}|Z>p52anYH)rEVA_Yj zE#B;O&2!Y6S&BKICsFO*H1*zdV;J(YilL#M@Ocv8_Q2<%s-Ynle6Fn2a_7Dbh)Jqy25A43l%kDBHIa7w?EiQXoJ!ON2q>nJ5k=FJuQ8m(Zb&X=0 zwnl-cdh%XsZzFBEMgiklUug>m{$>8w4mHpE3QDHuMcVc*tVejy^bu!%Fe}2gyGn{; z^SxK7xMeH7{Y=@dv3Vg@)fuj|F3XP1Rp0tZeM^D2a!bZR>slGB@=$MnyRiF@ai-)y z9Mvt_E}IG}@~A-y`!jWs`)!IoXF}w8sk~)D%Nx>U?-$0&^?dkdpu{QTy`UYZLitU- z<{0LoF7`UoI`d{#N8aDd?jmI*#*~qEd(cZYEIa$gq@^F*x>;sG<5+uVw0|@_M>jLA zac=7;;g3MSNCgbJ*)=ru7U-Dg;rhk+p`rcIH$C|bv6l`F^}*+wlA)pJ3ooU6e8akj z1KrcqH(K}DWz-{)K~488fcMJ^aos@&ygT8fg)WjzYA$a+yof&+BF^nnA?3r34y*E5 zAI>I^Kgm*|WtF6zWdy!>q|jTW_KPEC^V+E`-A88!(PGX{OI5aF?Z-L&Y~`atPC_`= z_US0^rc!rc!S=4uEH)s)onZvbL*CSWC)V_IN-m_Z|&&9q+Q$~U%J$Y{# zlpf2RO#f`kXk(gv5|ciez6Q$9>BBe5((f{JtV%iX*=G^F>*{05#>S?$?3C=@;xs=r z!5C_a0UR!FTcNiweRmc`T%|$OFe7@--KS6I8xyFOkt0a<4d>IbIIF4Qn@6r zzt=;`QKESXxo>uxCc8qL5xBL2@=s?gTLx}Q+Y+-H(>$fFE#hinpzCnT0URyJMPN-B zBgXcT`DYGXsrfB?q(v&tTO3I90+~3Af-;n|l#EZyq5$}G4-~a`hKw(1R)nD100x=u zMBQwbx#zGyW}LhND4@waA43b}a_{BpFFeWNK1a54aDbE>UmgwDnZ&G7WBZwe7kK^V zf!V{7=AxIUC2g0CJ1@qb{3N8=AsP$^6B&#&J&+f{c8j4`vE8>$F> zeH$Io#E!NK$_07Q#JXU%va^4_+MhF3O+2G*q!bfGiDAK4s!q6C#*~F51L$HLXKqsM z_`>k)GAAts$YbEGa_yu7Y2)@7!dicm5|HQqG3|lS9|3!AmuN@*wl2YxjfvU4_B8M2 z$xPXV*kvuRNJXG2P!1;1dsU5@t^BE)eWbD`b*%cxs;Vh#$b2liRKV>g*`bp%hTIGJ(=K8Q0EPf@FA;lsux z!)vGJUCXa^kZDADEMVG-GgLJ^FEi%tV&L?T0yomvWHWemJcBEsq2y2%MkF!`qW?pz z*?V`IYB%(g$-h^}m~VO4rnSdP2R>N@PhN{J=K~slioJUyEdZM=TiMu$XS6X_VWbRmXGII@B<>mQ?7i#wyBwGc zfGCWG%&E`_WCO4#&xY74#|aiXMSCtvxkR?xRFQ2v3>CcRo%yLt6Qe*bi-S^-WvG8NBL%vPG?BjE^h70YWaqguiy!N|IWX&I}&HM;SLd9%VT)gi0Aw*GZE-Fvuw)JW;L&K zGOC z9_T^7wf3VPW6a<+q&cgy4_kKAOsrdF7DN7)uk9Ds=10fT^Jhp$c}|XJAc&3n63O-ebxYcY%y1H`aXbqw7q{{uex>%zw~JR_m1|c*7TZ&^Bf6OogoE} zWK-{FpmVy-pnHIho$$G}P(AlavM##MgS%opg?SPS9{gkqo?(taS+LL0Gt5@D4H|~6 zGxRvM?79}EGQ17yyw9rHch;}Uuf06-fAQW27fjH#fZN-&FUYxG{AzSg>H>mf+mz!MGt8Y#$cdwh<@hsLqd&iVO^! zRTz%Ot$7;}Ht=<`h1jZ+l^fx1*S?yNZ*^={w(^5PrUdTTI#zYAajOluLoKtyCagr;dU&h52$a{m-ik!^Rm|$M7v- zP)`}bkbYadpAYg@5b4HHYeaUsE08r5uV;w5@)OP;LleMg-jVjPD+d zvkh8{{IjIAdJRTu;b`%j0bA%GjNpk=ruO}}9gGtxeoCF2UWoe~7LA&l=7PBXaeu_O z2G7rWFwpp|_Y7G_O~!A3@aY=14d`gwz8mM0NO`t>dF*Ih&$NoBh=6(Hst^isHRj7? zT(?BHq*o96%j8>A+SIsOC*A5_R#*YnC<*SVGf<&Pw{_AQTqT$f@ZB@8N4zY`%;=4< zGiFAFHF#&m8}nk?>fq71sfuxKmvwr>3Cs>g%9q%gugLWU(7w*rD&_#RFG{6N2I<}6 zIZdRE-O&Z_@Oe(V&BK(}+A#y0u*NSkrP<0XpajBciD7&a+um^-a9By>?LfKQlE#B^ z6CsniVJ+s=c1dioDCGm6f02KVg!9bW+9U37xh5vWdr1oa=|U3g2|I9lQY< zXq{i$w89Qj!<18-$G38`SP(v%n%%uv;Vn0$ygy}S3v)wU_un)nI863kvY!2IiVL=h z)nPNmwmSMONr66?gy-gEd49GM_^W%nbTqXf_HoMA{g|i11J+4v6`rsjkJag% zx~R~!y{W^;#X2NztJ8z)cQGGe-NL9e*)Ab1+C(-?O0>Q*q|d7{rh904|L0$bUw*{n z+UL$tB+kxyLd@;C#*rThrW#x)4Em#aDQ3Z~=UV@|s#YIeHsNg_PuUdXXs$!v#ay~e zCLHjQ68xs^J9q@f`Ht?;~)D(Lb|cqdiZ)z`?!K7e0+e$X~$@5J?QyaU#tO^|N?rQe=p zNKRxb_}mk9D;)6bvfjoG;M05%*9!|BzifO$)J1b+H`6CXYXsULfzWgIscURN^I6dI zANF;L4Nmt#Z$OKW>MA-Oz~>Fhdd0I1E57xuz^zb`|`t zgx{CJ?>X@M!oREFs)TDETnolS9gbKD{4a`4fd6A-rSLyL=79gU*jV_V9V>?a=2!vz zH^z$KKNrh`|4eKg{KqUh*~%T@4+*zjedd=h?=VijJ?jIUbA~ZXX_B2G9AEyND8CIc zz+KB(rlFy+;FGM%85#-|;=JL|P!C-3F+)QP+>gQMCvd$F7a6Ph0_w?k4IQ%H1h%sp z_c7~ahqQ@eoQk_xi&QZldrgg0sUuVNk}0HIk5MUg*gN|Z25OLvW`k@pwgVU7{w4G_ z^(S1kf-Zs*f9snpk?9+IyE!hRMfzEkAMe#-I$$)CF^|7tR33j`IutS_ZF-B^4&qk}pOW-jQB|C-X*f^VxvBymQ7Uh-13N{n}W}$5ue|T3m z4bT@t$g9)FGqKs!N~`>vL|spngr^6YVy#g7Y%DpkBveiZPL)#vrKU(ZV40M~3I&Ve zO&IC%I05VOcX7^UjBpp6UqFQ4#R=K(o8ogy2&Fyj^p!~Ss3d`gNpwn#tJB8_n^GJ( zlp@WVeWT`NPTGumfTtQTd93&P6uH3QKYQ;U*i?}&fY0Q4@+e6kl!674LQ7hp z1bk5NK^od=0TonG+(k?g-4lEjQMZaNX+fy?xB(PXMJ(*DTabkYRu|-v;x}c@Qed(%&JS_u>dnO#5DTzmXtyt$6uGd)@uaxTF|fK+8}^D?u*Ycw*t5_A$0KN?7Pio}10<(62dvL$#C+h@O3@b7 zF~ryRkrc_vra`NX;#PMbhAWB$e133@xZE9&>;VfwB_R}Ji>eOco{MUFBJxQK=P%LC zgc4$>k5raX{;Qnj(D){_Th!uwRJ4No6H@eU?;nGXfj>RHi{xV(o)=LKIq@_Uv)mL- z%EGbRt#29!Y&~0ZYHI7vX~qS)Vcg&28F9cuJUh&~`;)kUCra5~hH-i)m=-rry&{+a zDH_{W{Swtv97UA2(a)vl_51jzz4yv&35WW#Rs;P{O;(;h7>8 zZ};F1ThDk9HtwuiCmPw!am|!9Zt#6 z<>d)4Ukv5RFDS1`l&^&Gm?YYRDKIJ||NDqpva_4w!kq=;dbciY6jS-raB&rkJQdeL z+qE7%b%Kts0gJ~D z0Ex(TzEvV}X~sgZGsDk`FM6IAuM(ekXN5FZ7I;#`zMhSq8^jqN^zt@(QWn;_`!2xK z4af-a`Wz%uxf}PGSBI(X*|?ch?pA82W__=b&H@aki!Y1W3p2&FZdG_Fw0e*8!t}+*9qT+}*oeF)s(dqWfpc3A`NYT0DQ+4{{!D z?>gTGmM`8O*I4j7vcH2B1zcVKclZO3yB_z*!|zIJq+yJe68Tf#KS1LY1yuttJS}Nl z#S`ADia!KxKf?ny-~pURu`!c8yKB2x6{O-0u)Tp3>vxGZ(YhmD@`$xTO+p68o5@fk z$QS}|)lxDQzg3AxP zMpn9&e;2r2%nIsZq_Kp9VShJuveNYtxfylo(_ro7m8<@YyDwQ-FOLlJZSQn|Of}29 zIU1Pc4O16QDrXC%)oS9anIyDqUR zJfuD z5j+xMwEGe2!807Y;Xl&rKONu#eK38(2NRs7alwQu70t4-9Y?HBJK9Qz;w15{5RR=b zCTIeXe+66K>w6&_gZj40CxxIYcepeFNkF#0sGQ_d`<0JWm0Vdd{}J@t#{!L&f$fQ3 z|EOnZUj+YECo;3sB)`xpg8wrfR~h)hzw2=9c;pdvF8ZHWR#bY<&te0`bYLw{w4MJh z$dULi$Rrm4K5D-uqy{-S@%gx}}ZPGb;L%iC=Ttr9)pj6I^|Sh}?h-(A5^m^pL^ZG8>v z-(&0F4Se=!2Y!!gmLKn+xrcY)w{g$KHPZ<6RA}=&Ss4UuYad`3g-}vZ3gKGjT(7W0 zE#-Piz$|Opk|%jN_(@(c`tA39Lx@se_67A_m#EJT^$9zB*B5TheZ=!*?FBV{+uKVHkAI=cv8$E7Wo8>>WQk(4&#qu`E4Lf_kTMb_O zP{8tfzD}(7n_74?7v8+U-{87tQ_pugQ%@7{M_Sqi`#xL~&2in*PHc8oUr`*-0KeW| zVcmTz;2>F!iXIWqtt!segw66%e$KSVQ{lxg3-DQi@mV{5)iWqj&LtLSgN*|I)H{j% z%9oreKY_RPNAR{L;JwwZd|zskUwxZ|K0cF#i)&2u$CX|z;VVu&9(n@ThG@#QoU={x z{!W9f=@bP^aZ`+tNd_gxwyd$5{XV%j5Ra4V{A0p~m|1v+xd3ZR+plLp{gu<>8F!MA zqr-WCOX}U>rfhpiGuj|Fgmidv6L?Xtg9YXEE_2(D8e$n5Dve-T=D>C8NAYW-ZzDsb z?e3hTBhVwX$iZCj2$z;GOSJ9rP7`k%iJ3HCOS!C%bPTL}Qt<0=rFUlOo#EQ@+CUeJxa*jSUMKy&anFbepsfKHlIepjNl!cH5=32US34V9nT0S`9Z^~Ef!+R^5C z#rNxSc(y^hv#R9wNn{nCi)NBDI-i&3i%$oIgeBfzQtG4ySl^7Wx?o0FRWKu>vCWo7 zqg8HEfd=fc(Jg9jqvL*EL9ltSAK3cQj22=0Ik&Z;ZfI(~RA0vR^yP}g>JJ$Ij`Mv{ z_3F!-w#IFRz4|c%`k~_eXzVDE)HbuEw;84U@`41MKXf2HDC3ocr?w-k@zAnI+p2=L zUeE>sG&P4-+o7}*zcxh55<#vW{n7W9Ci!=*B;+^^bPY7>(RX)O$%JI;y1PFzcXyY= zy`b&x-qc0NWVjMY^TEAK)7||Qyh{PSG#8##@NNuTPpK382si54AU=@NFf!tO=&FG_WAQ zk7P+#m0y*lfc73P)88zO2QNq%Y!Y_@<)w=Q_*07bDp1}S@7q9kqbq`5Ixbj&mXNWv z2p z2Gh$Q!ZlSuDQP`)_b{G~GYorwYpcG;swz@&y38cs7bT$v81Ic8gq#IDI^p`Us=Ip$ z$TR`&_tWlf71KC02aSog;Fs;%9!Xe|zyqG0w!R(c2g=3;MIJuYxR_mC4nD=u-m$M^ zabcSJ1v2tLl$P`hzZvu0S#fX_MVx%qqG9+Ah1RO(Yh5VVV$XtdX+}}sw9exXc z8Sch?IWwlB4S6~Wwt}-D{Ny$|a_}+GnR@prwPC8PG8VETF%Y~hE@V?VRb?%p5slp- z8TGnDsjUW!Ib>|TiBda}1h8rkN3CP&bzeoGZR9DpCM1#%;Z7^1Bv!M61=&VM3<{}U zKu=|3%a3MufY*bHyF-T>rrN=NA279wEl3 ztWa%PgMMbHad-W_7oPp9>>EMtRVDWMiXD(`Gs-`7fi)Jb_b3_{#y4iA7>m}V)>kOs z=pz53T=9W*dN`id>lQHDX4Tt8w>a73!t>xg_@#9g+2z(o21^cRlt1s< z64&3#lF&)3yJ4vTQj-b=d++gZEVDRjPp+eI5WD>b$j6Y z5W#ieBxdH{1)JsTTOROQuf#8z8$n8}X?aw{Z)KD{1&s2cJxbkT(9H55!+8mSCpC!3 zSQl`xpUprPUoMG6Jp4n35bq1H=Ia-PD z7xmJCcvhpP_qU5%gqQ;)NBrB`A9NQvha3BUO^cot1&5a3oLK#Cl3SzwB~o`7Y#G60 zg;s6s)B#mCMOEc9xSw8{pqMdU;5GX+PtfbED9>)JK>C3kmf}IB$vJfgrs*Rn*Q!N4 z*VYBpc($_~Xsf;f!m zP}1Dj^@tZ+x52HB443W~H@F?)2H=FZL9>|Tx4J%!5?buR-6E-{(MyXOD>}trI_qeZ zU++Zjad#%ZGKR7JX!pEk(D^X7R_BCfD*Ydm`}$st2tU2>GG?T=#u&9dzbgx3UIRy`qL~ zD>uem!Yd5-2ts?#>~}#uFSNN%nGJX{5Xc>aI*h)Q)~}PMF+03H)T#ATXJO>Ca^05C zCXt+~k^@o0pB^juHQ!t1KvbV5ICcJU41J*-rt@kWh<_Su1V7z)5q`Zj_;Gm-`*_mj zOyPsfmJKng@tyqOM#aXM%zjrgT0}a=l?#)zGjKIT4%iV-g&C%f@!+qLV$Rm=h0DlZ?LVV#f7P4#4TZv zGc1Rtd*5)Uvt;Bp6?~onK>OA1iDALp;C3Arz=|f4hS}grbHpYNV>sual{5#3vD<(i zh(nHCC+c=09hlpC(ZNkgI{1s{I?rL8m*RNc4|n5$4$#Ij$#dFpS0C!c-EtbeSQf@F zTqCZG+nl!qU1BxpHk2}GdnK>a=HahmXDnvR%2U`ZhVwiE*ca2|MT_W)mx88Pk%mgw zFwpnVZuOBOK2w5J%=h>ODjvqVnxQX{Cr|upM;5exQ>%{gmQTZ0|J9S{ITpVn(drN3 z&JL|U7B7NU3vI{Z*FdX3gkKZLNn*qG?~i)*ASDk(wHr!3~7V>F**bWW?D={ZK zIQ)nT)s0Tr?xVTwuJ_+sik7<#C|lEd zYw3XS73@**Um_WK=4be+`2v0_Zw1S}XHUMQb){=P_3hXHCZTseCq!T-JLn8r>sE!# zTzgcO;fx{f(4oxLk(f(U4YC9+6#`f@!`h{ymMKaBc zD(iDK)9O(wk=H%f@b6rcyo2AL+8NHhndE)Z^K);9qS|d&2eStLXr0HZ0=B&TnMrtJ zl+wC)T0daF0_$pHOoQto3j6ZYtPH^8R2uuEl_o}zr3R&ygY$#efh@h1-3HV-mR%#7 zIdx`0Yc)V&oDxx%s`f>7c9f=?I&8U+ko!GfRoQ--ld9MH66b zgL_M48;td~#8_vy;=2=ZtIr>|Sur-PT~o~Mx(8bSz-GmZEREYBhwUDav^UQ)drjXH*{w{F zRG$&@uaKs&c(k=t10I2vRmAQR--mI2AIAB880Yung6mz# zdm)XE7AGaJ`B003&12j*!C%31B%V!h#x)yHQS|91jL z@kBhskM#Fb`t1X~O-a!2Bu>AWA88om&@1QZ*dRA{{mh-aFZ18Fb( z)Q=dnCM8xR909#{Goy86MKSo8;4QZd6Ll=S1J@DuJ8>g$MA4o93L0WXIw}<=<0}W1 z_)40z9k_@;`Qgq}-_AL^^$6kL zg_PY(p!a`u4-T85|5e_4w>mP;>i}6Mv{Z?7=I<|sY80zawUi}M{uxu(sw2v;3=<{9Ke?Ml=aIJR@0Xd7shKk8KGosEZa zPPhBp1Kl_;Ymi^rdEq>~QQq8%^YA!7_{U$o64N06(5}qd8{~%)5S7z66`0R<;*N?4 zwHEHON!7N)QLRP*i}A1;rkl$+mXEUF}E;h)+cOE*#cR~g}8q=FzR-Ly>PW9a)PJ*0&E(7ip}e}&w*I^pzV6_Ir0FT--=|^nQ+n1VDr2e zZjk$MY#QW^ZHfKJ7XM#YiGu&r{<`;7@j$; zf2z#W8h=54Wn41eK6;4o{kEMzF9X_uZpv}JG>oP?$&dOE^nYuZR}|E8Ncvv$QuT8% zKA~u8Wo}B@>tppHY=@bpCaBL2*ifZ`1&~I)_KNCxlY%6crCRP5!h%=>I>ujCKL>Z= z#$N@RZyv(KHd@O_=w^UNnQvYep5+`?qAl1Pp$vN?lwqHJ^M1akukG-?39WbsYVM=< zs(bd~yE$%dGK%vV(zK^cq0&;mLQ=z4xE}~_a^DyJ2YA01ta}_wM#Uo=JY8ao=TE_+ zpBdHOboF`bqvHJ{EB!Q5#x}W2B4wrX!pNnwTdTpMcpoHjqX;%PkwvsS6YB|kd3?VU zY3@|UN;7$>lGdPD?TG-^AzEiW9Y0dFYjT&!gfZsI4Vp6Pw~1zfHs%hIyXw z)Qb*0m622SSZK-HVVjtr;G=xtqk3@^yI-V5^`3M81C8=;$L|fWF!B|1FW(~_kjhO{L;f9uiu_H(`nf8X5_2FR^|Lp*EfXf zn7Xp*lt8I11Gx0Uo`MCCMRilQ@OvEnI{J8H6?)OU^sgYaCr*qE}%J%Yrc)O4_1}=fzkT!ab=wWvwwL;m@6%H0_vXtNl!Cp#zCAUf5Bt z+hX@RCiCb(nRWEzAVEOCI1fbix#mCX{AT}&4!y|`I1sgH9qd3yis_qgUpr?FJmpRc z*K_o|7 zn%e5;If50UY6aTestx|K-n-))djG1HOY8mPA75JU@A(+0W3p8HVjOwpzE{J4wUaYi=cuTf&q%Jx80-4>X<71jy-1SK}FSXTQjas6d5@ z>EW>~Te`daoq&t$b!8ZGY=n&vwU-mx*S^^=s@_F zoggE<;rnoxyZI<%h5`=o9wo?UQQ{~KPcNU5fU&j}=lW+MjH?Qz>sTJ2A>9?dw*1

4*-qxF$0t=$m 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 literal 0 HcmV?d00001 diff --git a/test/resource/ams/ams_page_ability_bundle/amsSystemTestN.hap b/test/resource/ams/ams_page_ability_bundle/amsSystemTestN.hap new file mode 100644 index 0000000000000000000000000000000000000000..5f80a524c8531f48e3a12d27fd478dac03ad2846 GIT binary patch literal 112150 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�(R4yR+V)ZN^=CpxV)6j>7w0_+Gzz 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 literal 0 HcmV?d00001 diff --git a/test/resource/ams/ams_page_ability_bundle/amsSystemTestO.hap b/test/resource/ams/ams_page_ability_bundle/amsSystemTestO.hap new file mode 100644 index 0000000000000000000000000000000000000000..3fda7b54d9223ef00f46f174a6f5d9db6daf19ac GIT binary patch literal 103147 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 literal 0 HcmV?d00001 diff --git a/test/resource/ams/ams_service_ability_bundle/amsKitSystemTestPageA.hap b/test/resource/ams/ams_service_ability_bundle/amsKitSystemTestPageA.hap new file mode 100644 index 0000000000000000000000000000000000000000..458b20faad88865d6a3d6a1a3c696a9022151bc0 GIT binary patch literal 173207 zcmZ^KS5yO%+BmtV|@xr<{P(e-MVq(2Cw43;r}(-8KUyGA#PksvN1^8Uhliu*yv%xu zg2fuEq~&jql#+knLc5#wIxt!a6kRIoiR(s)8`mO+B8f9nEo0R>R32_}&3W6eX0)G1e4h>qIr5)O zV{+32hS{(@15JPG^kn-rMmQ>QiA0! z>`4R#z0XM>2MzSY)$?8P-0m0M+Q~iD(Ha!!LzVCimWRjImah|SldR}NX{(v%um1#X z+TZ?kdG@K!NHAbm)Jv^lpfej^5lCM%bTOgzW#23H(mY(dC3;%LaxYh*B8er_N?*)D z)YZj#>NwC}+oj=-qUbxa`*h&_j+P#6hTC$tf)wZ!CTm|&L1VjMg?olnky|Tu-0{7G z8YeMCg&9v=z;8^2V~0evyUdKc%!=0zTX7L-B`e=?+58?koJO^PNVdN_sCca;4^+Co zX{=9u>uXd0oi4H)H+*Pr+%W$C+MoL$5QadLn#nb59+UDkeJ_$v)Xqo#Po0v$&Jt!#oucU;%*kXvrZ^UU# z%F!tH<;eZX|L)hl)X>suhaCMlZf}L{;I~OAg^TWnG5vEpK}n>8i0k%+T*jioPVga^q)WG_Kv)Y6@cJG$Q{XPc`%XO8A|J zVHfEIQ#zo&>kTRzJH_H?mq=r*?0VYC+y9fgE`KHF73XKPl#+)cT-i2 z#|dVEOlR&wMhcDre+&f1FgN|i^<+Dix#ZK*A#U;6J>J*;9A0h?QsL=Ua>b)AYjbt% z?-5;R@4}(un)+WYU+amyK--G9kj*q(=ufQPJeo*`dXFB@B#V133~jQb6O=}-cXG#* z{hQxGUiX_d*EG4eC=A0GGU2*6yIY3cA+MpnS>Ki?eC0Ax?XE{bxb%jd9%ysR`mj%y znDUO`HvF9FplT6e6H14$`T3NKI^-20z0>D*uRFp9wn-ZU#?YcKHsn8TM1if_HYLPD zr5S*OKKpEz42Y_s6_O~L;d)>~Vl9yFg$ACgE*1w$v%mCfi`m+P1XN)_gLgX5;E5SU0Reye32%H|wx~K) z_AB{`SJuji>$b&Y#UNF4iQ)CD)K_~NB{4y%TJ}SH#nOsdqf3Le!A4@E-p$lyk)3u-zK*B;aSO%iJ6n?KOKvzS_`n3Zr4vFoC$s&9W%Dx5mi z1x!tV3YD$U$4i*9U8nVL+;2s{f9EFu--da!k&s{jLxer_;zglJOf5zvA$v#+$;sPR)qg@w&5Or{L?a|e`NOsvTL5D z>-4XZ=Zoay>Oi*^xIk}Dt1{1Gj4LlEK>8ZPI~Z9gbC^2ftrc&`MeWDc?W5dFD{r)Z zDb(xEgd5mH=g7*IITB!>{V^q-al>X}t)#}SEZ#mhqoN(1zm|@>K7C$uLBdzP1 zZ^m}OS(CBpQ<15Yd^Iwx{_?EV<86;O4tm?IRPl^+e;+i>JwZN7xX2|JQ*JAG zG$WYzvm~-#D|zRgrBl?Y=Dq((I%NE7IhWjAw<6t)@lBkuPXr;R?xbK{3?|=O^H-}? z<9T)9he}4fj33n}UoEU#CrW5L=+0b@4ouV5QXKB!t(<2YZh8bfH%uqKHnd#U-~U*J zn0|GXzW=;7WXS}Sykq4_p_fm6YG~aiXP5=omC?%&aLdvEGis=xtfcz~@zb84@rIm; z?ZXe=6fgN1DKC~K(?JvL=?St?Yvu0s%1Y>doASKUI_tn`@@Z5}j1BU+zBRH(+zIh`++OcPx<2pWjvFD(YAcrMlqM0@8Qn~C&ZIG)ZSce5e

M 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 A2LJ#7 literal 0 HcmV?d00001 diff --git a/test/resource/ams/ams_page_ability_bundle/amsSystemTestC.hap b/test/resource/ams/ams_page_ability_bundle/amsSystemTestC.hap new file mode 100644 index 0000000000000000000000000000000000000000..943a4898a53248117830b09f16ea01292414a0ab GIT binary patch literal 107306 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�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 literal 0 HcmV?d00001 diff --git a/test/resource/ams/ams_page_ability_bundle/amsSystemTestD.hap b/test/resource/ams/ams_page_ability_bundle/amsSystemTestD.hap new file mode 100644 index 0000000000000000000000000000000000000000..3550f939c1d9d2d1247c67ae0f56acc8126b8caa GIT binary patch literal 105056 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�cWdR3m1&&}Vp-^CkGmzf1Px}{PmE4lu@FG~qz6DcYEu!Hi9rwXZRy%Hc8QIc@ za8g(Z7%u%z<;Ul2n2-R3qw*SFA4udH{X66FN!>p42AJj#v|l z?X&6V9y=K8ceH7>Yl8TM3dQa-%4|I$-DzS|+RjF3qsg1LRYi&ljL3bgOWNg>2F8Bx zhFu{Kn}`B~&zofI<)1fY6hwnMPHXAPKQk{D5DijDRd4&_PLK%eP_*5m`QGE_gu?`uO-d)sK<)w>tq#;vJ)5aBOPF%Usy4eRo=*l`PocbkoMSZaJu7>Jh_fSSm0&*~%d}SL%c5d>Bib=0;bkMQ6|uM^@b zy^tJ(PesKqf2OpiRD_ioh^q4|Fy1ZW_x}u?IpJ9P9eQM$dlqsWCn?3Pk{r*n!SSO^ zR?5;>4n?NPgrHLz{pYwQE`I4uLs9zYc(Y3VNlfJgVB}^1cKvrU-;KU|oT%>L<<*E3 zbC#QV7tcLyj8yR$vv)H?$=L)Z0~2L>Z?xm~6Mo86929|Huqyj?g#=_Cgz)B(SMVza z2`XsRq*_oZo9g7Kc}=X$^_B*bKG4q3m3R@3^w(Vw4Xg~hGt5aqY{|8MowgEuz9-On z;#=*;jBevh*pzE;EFZ=_Lb6QXsQd7IZkoUsa|;0j&=+{sZT>3TAhf&0q@~zeHGa1~ zmX-3c7rbFfk@OXR8g-7k+-C}HuUxs8@%`?P_RA*pLAz^8+LOl0;O)Dn*bZkIJGNom z#zL5{{W-8H7aS#YNH+}06s#ZTZZ{pDhBeWDDhr!))d=^N5V8FFQ+8o#%YTnXC&Zxv zaWVBG0CGgveO{zJ${?2qHz>GI^1f!6(XisDU5v23q-kFD%|@CM%yKvjE&<)O-eL$> z=f>wRL_6ztAlECf^uZ_|(9>#MCl8JSkWm*Izcyi5=7hDG&$|&RN7#>l9rWFbXls_f zmwRvb*zaYTF3H2d7(K;NJ>4i@qrufW^@j0Nk+s!j)}9bB)HdHTY|mHRtmI5}7;0r7 zeCptuZ9J5_U3|-wDNggYY23|#rpw35ot%E=79Cd`N7lxL;D;eD%Y6mAzT1~hoxZ1H z+zfq_QTwiT`N7*7Om@lGRo?F@Os>@Wt;BW@u7nP|j{ri4!3Jmav1D$FWPzT4qzONF zCNZCb^+9xDsBuycBo^;lM1s_!Y<}nXIs*Vr&NJ%R$A%zhs@cjDJ7kIf#POl}5^we$ zFa=HrGIxZ))F1B8<@IRG>`=AwhMhJ7MFdQZ#$*iaduAEJ)jTzZ&ux6)Sgh6}gyPz= z!`={Fjo?N}{BAM`v!~4SC^~(*vot9^w9O|*S~dDYO@G$$~HVE4w9i9qNR{QKS&V;Y zZ=1*UH%PPXwvg=@#d5nxdk@FdisV)Ev~uETDzi}@lbgg717z%QRL*9b65T zd}2l~+N{62N3S^h?R06ZtX{?f3AsHxK`?+SLme6F}JMuK{(x-eB9(zRFwUGGef{4>Rc2;&$23&{=Y4@oqA0~#Z5 zqKQMEBxAQwP4UDcV|&OXoMc`EZ|i08%m&x7&H`!cO=>o-#vEeIo^9&AFT^45Q^=n` z#90=^yqw&kgN%3Vf4?b>!PwPOifHb)9i$mj{ikD15u(p%JRq-J_T;YWwQg(XIo_)= zIq8bBD{51q4{{t@){Ihg3DJ*oxstoZ&F{dbKJO>wk&LEh^u|k>>X&N|r1tqdiCnhP zDiTJJjd`kQ|}9lhX}7BZ69m&%uJx!KSn<^0a4`RWLPjG7BPEXT0ahV zHg#)}GzS}l0ZP4Lu+xW&%dC%l?X;hkQOkdBo4>nI`GA%aa%St`rg3WK{~`2e0Kt!i zfrCFiK`iQDLwZ&T0^ADq+8H_kc9G(bws zocRW50>?QvQek@zo>_%qtO=h;P(rqVTk^-{OZmW-26|!VueL2 zF7Eqa%B&^Hd{9*@W$Hh_`OFP0E&Kj^)$}%0A{Ic#!urhqF=5;9pHK|lrfmARk{Zac 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 P^LrzYC5!~A@Y_gYXL{VoGbJy> zETsoi*}$Jk7;Q|WC^5-w;FVD8<_NZZeX=fdF|-#U&d-9_PJ4tY8X2C@v{kZu^OF3~ z06NqZ1~^>Yh8%BB^6pd>lCX>tCMD<66>pzD8MjNIT5h6r<%2$pcPh0csku+aewIcA zNfg6JN#G>N92RJ^clYUm<9kmJ^cFBA4Buad&v)b69Nyl^v>EAAuknSYHC%it%v3JU z>+kW95}eVzgxoi+O`E$yn-RFRl=ADWidnukX-iD4OY)TZZV}%WHg~?C$ZxhPQhzR3 z6ULyieQ5oe16OKB(++8lO7o_Cg!?_9QEsaYY=c`&Nj?;A&%_1Lb|Z=m>{ zf!=w^EABqZJPp>ot-{{v*7uazah~1K?~vH=gMrn#qG)_^D#d!&_cJBWAAJwx>~R>s zeQ^Eiv(p35IT-TnYo`bP2%iMTZZdrS`qk3|Ipef-dVi+@e5>J-*wu<>Bv!lU2HjvO z*myq9>D%a#B+hRurCciyl2`|lxF9w|9nUGMB%a(hRElZE8N-6F)ZFK4x}eA}89)}J zp1D@F<8uPjik!4SwXhhgV4GT0%~F}qQ-qftd?$#s z#pt4Iy(4M5MqP}zPAtRpoWF~I5oHTc%&i!0$Ew)-I=aZ@%Y&Hx;7G#R{9%-#n4PP% zi4Pd#46kKlo6FytPbL!O@n+L{T%oGud6_Y9bT=RWMe{ZE71<149nat!P=9=&3{NC7 zF`|Dj+~~bMIpaTwlHxzBI_AgTTa(hGUY%2Kz>`